103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { Product } from "@/lib/types";
|
|
import {
|
|
defaultSearchFilterState,
|
|
filterAndSortSearchProducts,
|
|
normalizePriceInput,
|
|
parseTripDays,
|
|
} from "@/lib/searchFilters";
|
|
|
|
function createProduct(id: number, title: string, price: string): Product {
|
|
return {
|
|
id,
|
|
title,
|
|
price,
|
|
tags: [],
|
|
image: `/assets/test-${id}.jpg`,
|
|
};
|
|
}
|
|
|
|
describe("search filter helpers", () => {
|
|
const products = [
|
|
createProduct(1, "贵州黄果树 7天6晚精品小包团", "57500"),
|
|
createProduct(2, "荔波小七孔 15天及以上深度旅行", "112500"),
|
|
createProduct(3, "西江苗寨 4日轻松游", "36000"),
|
|
createProduct(4, "贵州定制旅行方案", "98000"),
|
|
];
|
|
|
|
it("parses trip days from route titles", () => {
|
|
expect(parseTripDays("贵州黄果树 7天6晚精品小包团")).toBe(7);
|
|
expect(parseTripDays("西江苗寨 4日轻松游")).toBe(4);
|
|
expect(parseTripDays("贵州定制旅行方案")).toBeNull();
|
|
});
|
|
|
|
it("normalizes price input values", () => {
|
|
expect(normalizePriceInput(" 57500 ")).toBe(57500);
|
|
expect(normalizePriceInput("")).toBeNull();
|
|
expect(normalizePriceInput("abc")).toBeNull();
|
|
});
|
|
|
|
it("filters products by applied price range", () => {
|
|
const results = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
priceMin: 50000,
|
|
priceMax: 100000,
|
|
});
|
|
|
|
expect(results.map((product) => product.id)).toEqual([1, 4]);
|
|
});
|
|
|
|
it("treats reversed price bounds as the same numeric range", () => {
|
|
const results = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
priceMin: 100000,
|
|
priceMax: 50000,
|
|
});
|
|
|
|
expect(results.map((product) => product.id)).toEqual([1, 4]);
|
|
});
|
|
|
|
it("sorts by price ascending and descending", () => {
|
|
const lowToHigh = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
sortKey: "priceAsc",
|
|
});
|
|
const highToLow = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
sortKey: "priceDesc",
|
|
});
|
|
|
|
expect(lowToHigh.map((product) => product.id)).toEqual([3, 1, 4, 2]);
|
|
expect(highToLow.map((product) => product.id)).toEqual([2, 4, 1, 3]);
|
|
});
|
|
|
|
it("keeps the recommended order for sales proxy sorting", () => {
|
|
const results = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
sortKey: "salesDesc",
|
|
});
|
|
|
|
expect(results.map((product) => product.id)).toEqual([1, 2, 3, 4]);
|
|
});
|
|
|
|
it("filters by exact days and fifteen days plus", () => {
|
|
const exact = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
duration: 4,
|
|
});
|
|
const longTrip = filterAndSortSearchProducts(products, {
|
|
...defaultSearchFilterState,
|
|
duration: "15plus",
|
|
});
|
|
|
|
expect(exact.map((product) => product.id)).toEqual([3]);
|
|
expect(longTrip.map((product) => product.id)).toEqual([2]);
|
|
});
|
|
|
|
it("clears filter conditions by using the default state", () => {
|
|
const results = filterAndSortSearchProducts(products, defaultSearchFilterState);
|
|
|
|
expect(results.map((product) => product.id)).toEqual([1, 2, 3, 4]);
|
|
});
|
|
});
|