diff --git a/.changeset/violet-planes-nail.md b/.changeset/violet-planes-nail.md new file mode 100644 index 000000000..e81c0e05c --- /dev/null +++ b/.changeset/violet-planes-nail.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +Experimental filters: add unit tests for left operands and container state diff --git a/src/components/ConditionalFilter/queryVariables.test.ts b/src/components/ConditionalFilter/queryVariables.test.ts index 4acc9029e..18b0b8ebd 100644 --- a/src/components/ConditionalFilter/queryVariables.test.ts +++ b/src/components/ConditionalFilter/queryVariables.test.ts @@ -4,37 +4,6 @@ import { ConditionSelected } from "./FilterElement/ConditionSelected"; import { ExpressionValue } from "./FilterElement/FilterElement"; import { createProductQueryVariables } from "./queryVariables"; -const createConditionValue = ( - label: string, - slug: string, - value: string, - originalSlug?: string, -) => ({ - label, - slug, - value, - originalSlug, -}); -const createConditionItem = (type: string, value: string, label: string) => ({ - type, - value, - label, -}); - -const createConditionOptions = ( - label: string, - slug: string, - value: string, - originalSlug: string, -) => [ - { - label, - slug, - value, - originalSlug, - }, -]; - describe("ConditionalFilter / queryVariables / createProductQueryVariables", () => { it("should return empty variables for empty filters", () => { // Arrange @@ -56,8 +25,8 @@ describe("ConditionalFilter / queryVariables / createProductQueryVariables", () new Condition( ConditionOptions.fromStaticElementName("price"), new ConditionSelected( - createConditionValue("price", "price", "123"), - createConditionItem("price", "123", "Price"), + { label: "price", slug: "price", value: "123" }, + { type: "price", value: "123", label: "Price" }, [], false, ), @@ -71,19 +40,25 @@ describe("ConditionalFilter / queryVariables / createProductQueryVariables", () new Condition( ConditionOptions.fromAttributeType("DROPDOWN"), new ConditionSelected( - createConditionValue( - "bottle-size", - "bottle-id", - "bottle-id", - "0-5l", - ), - createConditionItem("DROPDOWN", "bottle-id", "Bottle size"), - createConditionOptions( - "bottle-size", - "bottle-id", - "bottle-id", - "0-5l", - ), + { + label: "bottle-size", + slug: "bottle-id", + value: "bottle-id", + originalSlug: "0-5l", + }, + { + type: "DROPDOWN", + value: "bottle-id", + label: "Bottle size", + }, + [ + { + label: "bottle-size", + slug: "bottle-id", + value: "bottle-id", + originalSlug: "0-5l", + }, + ], false, ), false, diff --git a/src/components/ConditionalFilter/useContainerState.test.ts b/src/components/ConditionalFilter/useContainerState.test.ts new file mode 100644 index 000000000..806c4a98c --- /dev/null +++ b/src/components/ConditionalFilter/useContainerState.test.ts @@ -0,0 +1,166 @@ +import { act, renderHook } from "@testing-library/react-hooks"; + +import { Condition, FilterElement } from "./FilterElement"; +import { ConditionOptions } from "./FilterElement/ConditionOptions"; +import { ConditionSelected } from "./FilterElement/ConditionSelected"; +import { ExpressionValue } from "./FilterElement/FilterElement"; +import { FilterValueProvider } from "./FilterValueProvider"; +import { useContainerState } from "./useContainerState"; + +describe("useContainerState", () => { + const valueProvider: FilterValueProvider = { + loading: false, + value: [], + persist: () => {}, + isPersisted: () => true, + clear: () => {}, + count: 0, + }; + + it("should set initial value from value provider", () => { + // Act + const { result } = renderHook(() => useContainerState(valueProvider)); + // Assert + expect(result.current.value).toEqual([]); + }); + + it("should create new empty row", () => { + // Arrange + const { result } = renderHook(() => useContainerState(valueProvider)); + // Act + act(() => { + result.current.createEmpty(); + }); + // Assert + expect(result.current.value).toEqual([FilterElement.createEmpty()]); + }); + + it("should add new row", () => { + // Arrange + const { result } = renderHook(() => useContainerState(valueProvider)); + const staticPriceElement = new FilterElement( + new ExpressionValue("price", "Price", "price"), + new Condition( + ConditionOptions.fromStaticElementName("price"), + new ConditionSelected( + { label: "price", slug: "price", value: "123" }, + { type: "price", value: "123", label: "Price" }, + [], + false, + ), + false, + ), + false, + ); + // Act + act(() => { + result.current.createEmpty(); + }); + act(() => { + result.current.create(staticPriceElement); + }); + // Assert + expect(result.current.value).toEqual([ + FilterElement.createEmpty(), + "AND", + staticPriceElement, + ]); + }); + + it("should update row", () => { + // Arrange + const { result } = renderHook(() => useContainerState(valueProvider)); + const staticPriceElement = new FilterElement( + new ExpressionValue("price", "Price", "price"), + new Condition( + ConditionOptions.fromStaticElementName("price"), + new ConditionSelected( + { label: "price", slug: "price", value: "123" }, + { type: "price", value: "123", label: "Price" }, + [], + false, + ), + false, + ), + false, + ); + // Act + act(() => { + result.current.create(staticPriceElement); + }); + act(() => { + result.current.updateAt("0", el => { + el.updateLeftOperator({ + type: "category", + label: "Category", + slug: "category", + value: "category", + }); + }); + }); + // Assert + expect(result.current.value).toEqual([staticPriceElement]); + }); + + it("should remove row", () => { + // Arrange + const { result } = renderHook(() => useContainerState(valueProvider)); + const staticPriceElement = new FilterElement( + new ExpressionValue("price", "Price", "price"), + new Condition( + ConditionOptions.fromStaticElementName("price"), + new ConditionSelected( + { label: "price", slug: "price", value: "123" }, + { type: "price", value: "123", label: "Price" }, + [], + false, + ), + false, + ), + false, + ); + // Act + act(() => { + result.current.createEmpty(); + }); + act(() => { + result.current.create(staticPriceElement); + }); + act(() => { + result.current.removeAt("0"); + }); + // Assert + expect(result.current.value).toEqual([staticPriceElement]); + }); + + it("should clear not filled rows", () => { + // Arrange + const { result } = renderHook(() => useContainerState(valueProvider)); + const staticPriceElement = new FilterElement( + new ExpressionValue("price", "Price", "price"), + new Condition( + ConditionOptions.fromStaticElementName("price"), + new ConditionSelected( + { label: "price", slug: "price", value: "123" }, + { type: "price", value: "123", label: "Price" }, + [], + false, + ), + false, + ), + false, + ); + // Act + act(() => { + result.current.createEmpty(); + }); + act(() => { + result.current.create(staticPriceElement); + }); + act(() => { + result.current.clearEmpty(); + }); + // Assert + expect(result.current.value).toEqual([staticPriceElement]); + }); +}); diff --git a/src/components/ConditionalFilter/useFilterLeftOperands.test.ts b/src/components/ConditionalFilter/useFilterLeftOperands.test.ts new file mode 100644 index 000000000..e169c903f --- /dev/null +++ b/src/components/ConditionalFilter/useFilterLeftOperands.test.ts @@ -0,0 +1,44 @@ +import { AttributeInputTypeEnum } from "@dashboard/graphql"; +import { act,renderHook } from "@testing-library/react-hooks"; + +import { STATIC_OPTIONS } from "./constants"; +import { useFilterLeftOperandsProvider } from "./useFilterLeftOperands"; + +describe("useFilterLeftOperandsProvider", () => { + it("should set unique operands", () => { + // Arrange + const { result } = renderHook(() => useFilterLeftOperandsProvider()); + // Act + act(() => { + result.current.setOperands([ + { + label: "SKU", + value: "sku", + type: AttributeInputTypeEnum.DROPDOWN, + slug: "sku", + }, + ]); + }); + // Assert + expect(result.current.operands).toEqual([ + ...STATIC_OPTIONS, + { label: "SKU", value: "sku", type: "DROPDOWN", slug: "sku" }, + ]); + // Act + act(() => { + result.current.setOperands([ + { + label: "SKU", + value: "sku", + type: AttributeInputTypeEnum.DROPDOWN, + slug: "sku", + }, + ]); + }); + // Assert + expect(result.current.operands).toEqual([ + ...STATIC_OPTIONS, + { label: "SKU", value: "sku", type: "DROPDOWN", slug: "sku" }, + ]); + }); +}); diff --git a/src/hooks/useFilterPresets/useFilterPresets.test.ts b/src/hooks/useFilterPresets/useFilterPresets.test.ts index 83a2dbb1c..e695f00c1 100644 --- a/src/hooks/useFilterPresets/useFilterPresets.test.ts +++ b/src/hooks/useFilterPresets/useFilterPresets.test.ts @@ -1,4 +1,4 @@ -import { renderHook } from "@testing-library/react-hooks"; +import { act, renderHook } from "@testing-library/react-hooks"; import { useFilterPresets } from "./useFilterPresets"; @@ -94,7 +94,9 @@ describe("useFilterPresets", () => { ); // Act - result.current.onPresetChange(1); + act(() => { + result.current.onPresetChange(1); + }); // Assert expect(mockNavigate).toHaveBeenCalledWith( @@ -124,9 +126,13 @@ describe("useFilterPresets", () => { }), ); - // Act( - result.current.setPresetIdToDelete(1); - result.current.onPresetDelete(); + // Act + act(() => { + result.current.setPresetIdToDelete(1); + }); + act(() => { + result.current.onPresetDelete(); + }); // Assert expect(mockDeleteStorage).toHaveBeenCalledWith(1); @@ -156,9 +162,13 @@ describe("useFilterPresets", () => { }), ); - // Act( - result.current.setPresetIdToDelete(1); - result.current.onPresetDelete(); + // Act + act(() => { + result.current.setPresetIdToDelete(1); + }); + act(() => { + result.current.onPresetDelete(); + }); // Assert expect(mockDeleteStorage).toHaveBeenCalledWith(1); @@ -186,7 +196,9 @@ describe("useFilterPresets", () => { ); // Act - result.current.onPresetSave({ name: "new-preset" }); + act(() => { + result.current.onPresetSave({ name: "new-preset" }); + }); // Assert expect(mockSaveStorage).toHaveBeenCalledWith("new-preset", "query=John"); @@ -218,7 +230,9 @@ describe("useFilterPresets", () => { ); // Act - result.current.onPresetUpdate("current-preset"); + act(() => { + result.current.onPresetUpdate("current-preset"); + }); // Assert expect(mockUpdateStorage).toHaveBeenCalledWith(