diff --git a/react-intl.d.ts b/react-intl.d.ts index efafa921d..152e90425 100644 --- a/react-intl.d.ts +++ b/react-intl.d.ts @@ -1,4 +1,5 @@ declare module "react-intl" { + import { OptionalIntlConfig } from "react-intl/dist/components/provider"; import * as ReactIntl from "node_modules/react-intl"; export * from "node_modules/react-intl"; @@ -51,4 +52,6 @@ declare module "react-intl" { > extends React.Component> {} export function useIntl(): IntlShape; + + export function createIntl(config: OptionalIntlConfig): IntlShape; } diff --git a/src/attributes/views/AttributeList/__snapshots__/filters.test.ts.snap b/src/attributes/views/AttributeList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..425e23c5c --- /dev/null +++ b/src/attributes/views/AttributeList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "availableInGrid": "true", + "filterableInDashboard": "true", + "filterableInStorefront": "true", + "isVariantOnly": "true", + "valueRequired": "true", + "visibleInStorefront": "true", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"availableInGrid=true&filterableInDashboard=true&filterableInStorefront=true&isVariantOnly=true&valueRequired=true&visibleInStorefront=true"`; diff --git a/src/attributes/views/AttributeList/filters.test.ts b/src/attributes/views/AttributeList/filters.test.ts new file mode 100644 index 000000000..5a50d1f1c --- /dev/null +++ b/src/attributes/views/AttributeList/filters.test.ts @@ -0,0 +1,77 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { AttributeListUrlFilters } from "@saleor/attributes/urls"; +import { createFilterStructure } from "@saleor/attributes/components/AttributeListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { config } from "@test/intl"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: AttributeListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: AttributeListUrlFilters = { + availableInGrid: true.toString() + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + availableInGrid: { + active: false, + value: true + }, + filterableInDashboard: { + active: false, + value: true + }, + filterableInStorefront: { + active: false, + value: true + }, + isVariantOnly: { + active: false, + value: true + }, + valueRequired: { + active: false, + value: true + }, + visibleInStorefront: { + active: false, + value: true + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/collections/views/CollectionList/__snapshots__/filters.test.ts.snap b/src/collections/views/CollectionList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..37f201d26 --- /dev/null +++ b/src/collections/views/CollectionList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "status": "PUBLISHED", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"status=PUBLISHED"`; diff --git a/src/collections/views/CollectionList/filters.test.ts b/src/collections/views/CollectionList/filters.test.ts new file mode 100644 index 000000000..1dc360a69 --- /dev/null +++ b/src/collections/views/CollectionList/filters.test.ts @@ -0,0 +1,65 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { CollectionListUrlFilters } from "@saleor/collections/urls"; +import { createFilterStructure } from "@saleor/collections/components/CollectionListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { CollectionPublished } from "@saleor/types/globalTypes"; +import { config } from "@test/intl"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: CollectionListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: CollectionListUrlFilters = { + status: CollectionPublished.PUBLISHED + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + status: { + active: false, + value: CollectionPublished.PUBLISHED + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filters = createFilterStructure(intl, { + status: { + active: true, + value: CollectionPublished.PUBLISHED + } + }); + + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/customers/views/CustomerList/__snapshots__/filters.test.ts.snap b/src/customers/views/CustomerList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..d9973216a --- /dev/null +++ b/src/customers/views/CustomerList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "joinedFrom": "2019-12-09", + "joinedTo": "2019-12-38", + "moneySpentFrom": "2", + "moneySpentTo": "39.50", + "numberOfOrdersFrom": "1", + "numberOfOrdersTo": "5", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"joinedFrom=2019-12-09&joinedTo=2019-12-38&moneySpentFrom=2&moneySpentTo=39.50&numberOfOrdersFrom=1&numberOfOrdersTo=5"`; diff --git a/src/customers/views/CustomerList/filters.test.ts b/src/customers/views/CustomerList/filters.test.ts new file mode 100644 index 000000000..7f73e826a --- /dev/null +++ b/src/customers/views/CustomerList/filters.test.ts @@ -0,0 +1,78 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { CustomerListUrlFilters } from "@saleor/customers/urls"; +import { createFilterStructure } from "@saleor/customers/components/CustomerListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: CustomerListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: CustomerListUrlFilters = { + joinedFrom: date.from, + moneySpentFrom: "2", + moneySpentTo: "39.50", + numberOfOrdersTo: "5" + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(3); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + joined: { + active: false, + value: { + max: date.to, + min: date.from + } + }, + moneySpent: { + active: false, + value: { + max: "39.50", + min: "2" + } + }, + numberOfOrders: { + active: false, + value: { + max: "5", + min: "1" + } + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/customers/views/CustomerList/filters.ts b/src/customers/views/CustomerList/filters.ts index 92c398ac7..10a1abcb9 100644 --- a/src/customers/views/CustomerList/filters.ts +++ b/src/customers/views/CustomerList/filters.ts @@ -7,7 +7,8 @@ import { } from "@saleor/customers/components/CustomerListPage"; import { createFilterTabUtils, - createFilterUtils + createFilterUtils, + getGteLteVariables } from "../../../utils/filters"; import { CustomerListUrlFilters, @@ -67,18 +68,18 @@ export function getFilterVariables( params: CustomerListUrlFilters ): CustomerFilterInput { return { - dateJoined: { + dateJoined: getGteLteVariables({ gte: params.joinedFrom, lte: params.joinedTo - }, - moneySpent: { + }), + moneySpent: getGteLteVariables({ gte: parseInt(params.moneySpentFrom, 0), lte: parseInt(params.moneySpentTo, 0) - }, - numberOfOrders: { + }), + numberOfOrders: getGteLteVariables({ gte: parseInt(params.numberOfOrdersFrom, 0), lte: parseInt(params.numberOfOrdersTo, 0) - }, + }), search: params.query }; } diff --git a/src/discounts/views/SaleList/__snapshots__/filters.test.ts.snap b/src/discounts/views/SaleList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..13faf2f2d --- /dev/null +++ b/src/discounts/views/SaleList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "startedFrom": "2019-12-09", + "startedTo": "2019-12-38", + "status": Array [ + "ACTIVE", + "EXPIRED", + ], + "type": "FIXED", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"startedFrom=2019-12-09&startedTo=2019-12-38&status%5B0%5D=ACTIVE&status%5B1%5D=EXPIRED&type=FIXED"`; diff --git a/src/discounts/views/SaleList/filters.test.ts b/src/discounts/views/SaleList/filters.test.ts new file mode 100644 index 000000000..f6d7f7743 --- /dev/null +++ b/src/discounts/views/SaleList/filters.test.ts @@ -0,0 +1,76 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { SaleListUrlFilters } from "@saleor/discounts/urls"; +import { createFilterStructure } from "@saleor/discounts/components/SaleListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { + DiscountValueTypeEnum, + DiscountStatusEnum +} from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: SaleListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: SaleListUrlFilters = { + startedFrom: date.from, + startedTo: date.to, + status: [DiscountStatusEnum.ACTIVE, DiscountStatusEnum.EXPIRED], + type: DiscountValueTypeEnum.FIXED + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(3); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + saleType: { + active: false, + value: DiscountValueTypeEnum.FIXED + }, + started: { + active: false, + value: { + max: date.to, + min: date.from + } + }, + status: { + active: false, + value: [DiscountStatusEnum.ACTIVE, DiscountStatusEnum.EXPIRED] + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/discounts/views/SaleList/filters.ts b/src/discounts/views/SaleList/filters.ts index 3d70f2412..8af9549dc 100644 --- a/src/discounts/views/SaleList/filters.ts +++ b/src/discounts/views/SaleList/filters.ts @@ -12,7 +12,8 @@ import { import { createFilterTabUtils, createFilterUtils, - dedupeFilter + dedupeFilter, + getGteLteVariables } from "../../../utils/filters"; import { SaleListUrlFilters, @@ -63,10 +64,10 @@ export function getFilterVariables( saleType: params.type && findValueInEnum(params.type, DiscountValueTypeEnum), search: params.query, - started: { + started: getGteLteVariables({ gte: joinDateTime(params.startedFrom), lte: joinDateTime(params.startedTo) - }, + }), status: params.status && params.status.map(status => findValueInEnum(status, DiscountStatusEnum)) diff --git a/src/discounts/views/VoucherList/__snapshots__/filters.test.ts.snap b/src/discounts/views/VoucherList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..1926087dc --- /dev/null +++ b/src/discounts/views/VoucherList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "startedFrom": "2019-12-09", + "startedTo": "2019-12-38", + "status": Array [ + "ACTIVE", + "EXPIRED", + ], + "timesUsedFrom": "1", + "timesUsedTo": "6", + "type": Array [ + "FIXED", + "SHIPPING", + ], +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"startedFrom=2019-12-09&startedTo=2019-12-38×UsedFrom=1×UsedTo=6&status%5B0%5D=ACTIVE&status%5B1%5D=EXPIRED&type%5B0%5D=FIXED&type%5B1%5D=SHIPPING"`; diff --git a/src/discounts/views/VoucherList/filters.test.ts b/src/discounts/views/VoucherList/filters.test.ts new file mode 100644 index 000000000..0000a4e6b --- /dev/null +++ b/src/discounts/views/VoucherList/filters.test.ts @@ -0,0 +1,85 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { VoucherListUrlFilters } from "@saleor/discounts/urls"; +import { createFilterStructure } from "@saleor/discounts/components/VoucherListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { + DiscountStatusEnum, + VoucherDiscountType +} from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: VoucherListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: VoucherListUrlFilters = { + startedFrom: date.from, + startedTo: date.to, + status: [DiscountStatusEnum.ACTIVE, DiscountStatusEnum.EXPIRED], + timesUsedFrom: date.from, + timesUsedTo: date.to, + type: [VoucherDiscountType.FIXED, VoucherDiscountType.SHIPPING] + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(4); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + saleType: { + active: false, + value: [VoucherDiscountType.FIXED, VoucherDiscountType.SHIPPING] + }, + started: { + active: false, + value: { + max: date.to, + min: date.from + } + }, + status: { + active: false, + value: [DiscountStatusEnum.ACTIVE, DiscountStatusEnum.EXPIRED] + }, + timesUsed: { + active: false, + value: { + max: "6", + min: "1" + } + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/discounts/views/VoucherList/filters.ts b/src/discounts/views/VoucherList/filters.ts index 6f17e8ba7..d35c56111 100644 --- a/src/discounts/views/VoucherList/filters.ts +++ b/src/discounts/views/VoucherList/filters.ts @@ -12,7 +12,8 @@ import { import { createFilterTabUtils, createFilterUtils, - dedupeFilter + dedupeFilter, + getGteLteVariables } from "../../../utils/filters"; import { VoucherListUrlFilters, @@ -85,17 +86,17 @@ export function getFilterVariables( params.type && params.type.map(type => findValueInEnum(type, VoucherDiscountType)), search: params.query, - started: { + started: getGteLteVariables({ gte: joinDateTime(params.startedFrom), lte: joinDateTime(params.startedTo) - }, + }), status: params.status && params.status.map(status => findValueInEnum(status, DiscountStatusEnum)), - timesUsed: { + timesUsed: getGteLteVariables({ gte: parseInt(params.timesUsedFrom, 0), lte: parseInt(params.timesUsedTo, 0) - } + }) }; } diff --git a/src/orders/components/OrderListPage/index.ts b/src/orders/components/OrderListPage/index.ts index 69c5cc429..14183bccf 100644 --- a/src/orders/components/OrderListPage/index.ts +++ b/src/orders/components/OrderListPage/index.ts @@ -1,2 +1,3 @@ export { default } from "./OrderListPage"; export * from "./OrderListPage"; +export * from "./filters"; diff --git a/src/orders/views/OrderDraftList/__snapshots__/filters.test.ts.snap b/src/orders/views/OrderDraftList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..b48bb1405 --- /dev/null +++ b/src/orders/views/OrderDraftList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "createdFrom": "2019-12-09", + "createdTo": "2019-12-38", + "customer": "admin@example.com", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"createdFrom=2019-12-09&createdTo=2019-12-38&customer=admin%40example.com"`; diff --git a/src/orders/views/OrderDraftList/filters.test.ts b/src/orders/views/OrderDraftList/filters.test.ts new file mode 100644 index 000000000..bc0bd6e4c --- /dev/null +++ b/src/orders/views/OrderDraftList/filters.test.ts @@ -0,0 +1,67 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { OrderDraftListUrlFilters } from "@saleor/orders/urls"; +import { createFilterStructure } from "@saleor/orders/components/OrderDraftListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: OrderDraftListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: OrderDraftListUrlFilters = { + createdFrom: date.from, + createdTo: date.to, + customer: "admin@example.com" + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(2); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + created: { + active: false, + value: { + max: date.to, + min: date.from + } + }, + customer: { + active: false, + value: "admin@example.com" + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/orders/views/OrderDraftList/filters.ts b/src/orders/views/OrderDraftList/filters.ts index 151583a0e..ce1267c0c 100644 --- a/src/orders/views/OrderDraftList/filters.ts +++ b/src/orders/views/OrderDraftList/filters.ts @@ -12,7 +12,8 @@ import { } from "../../urls"; import { createFilterTabUtils, - createFilterUtils + createFilterUtils, + getGteLteVariables } from "../../../utils/filters"; export const ORDER_DRAFT_FILTERS_KEY = "orderDraftFilters"; @@ -45,10 +46,10 @@ export function getFilterVariables( params: OrderDraftListUrlFilters ): OrderDraftFilterInput { return { - created: { + created: getGteLteVariables({ gte: params.createdFrom, lte: params.createdTo - }, + }), customer: params.customer, search: params.query }; diff --git a/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap b/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap index 732d10dce..2983d5df4 100644 --- a/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap +++ b/src/orders/views/OrderList/__snapshots__/filters.test.ts.snap @@ -1,16 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Get filter variables 1`] = ` +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` Object { - "created": Object { - "gte": "2019-09-01", - "lte": "2019-09-10", - }, - "customer": "email@example.com", - "search": "24", + "createdFrom": "2019-12-09", + "createdTo": "2019-12-38", "status": Array [ "FULFILLED", "PARTIALLY_FULFILLED", ], } `; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"createdFrom=2019-12-09&createdTo=2019-12-38&status%5B0%5D=FULFILLED&status%5B1%5D=PARTIALLY_FULFILLED"`; diff --git a/src/orders/views/OrderList/filters.test.ts b/src/orders/views/OrderList/filters.test.ts index 793bbb94c..df4122e2a 100644 --- a/src/orders/views/OrderList/filters.test.ts +++ b/src/orders/views/OrderList/filters.test.ts @@ -1,17 +1,75 @@ -import { OrderStatus } from "@saleor/types/globalTypes"; -import { getFilterVariables } from "./filters"; +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; -test("Get filter variables", () => { - const filter = getFilterVariables({ - createdFrom: "2019-09-01", - createdTo: "2019-09-10", - email: "email@example.com", - query: "24", - status: [ - OrderStatus.FULFILLED.toString(), - OrderStatus.PARTIALLY_FULFILLED.toString() - ] +import { OrderListUrlFilters } from "@saleor/orders/urls"; +import { createFilterStructure } from "@saleor/orders/components/OrderListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { OrderStatusFilter } from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: OrderListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); }); - expect(filter).toMatchSnapshot(); + it("should not be empty object if params given", () => { + const params: OrderListUrlFilters = { + createdFrom: date.from, + createdTo: date.to, + email: "email@example.com", + status: [ + OrderStatusFilter.FULFILLED, + OrderStatusFilter.PARTIALLY_FULFILLED + ] + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(3); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + created: { + active: false, + value: { + max: date.to, + min: date.from + } + }, + status: { + active: false, + value: [ + OrderStatusFilter.FULFILLED, + OrderStatusFilter.PARTIALLY_FULFILLED + ] + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); }); diff --git a/src/orders/views/OrderList/filters.ts b/src/orders/views/OrderList/filters.ts index 28b549c7f..d4dc874f1 100644 --- a/src/orders/views/OrderList/filters.ts +++ b/src/orders/views/OrderList/filters.ts @@ -12,7 +12,8 @@ import { import { createFilterTabUtils, createFilterUtils, - dedupeFilter + dedupeFilter, + getGteLteVariables } from "../../../utils/filters"; import { OrderListUrlFilters, @@ -59,10 +60,10 @@ export function getFilterVariables( params: OrderListUrlFilters ): OrderFilterInput { return { - created: { + created: getGteLteVariables({ gte: params.createdFrom, lte: params.createdTo - }, + }), customer: params.email, search: params.query, status: maybe(() => diff --git a/src/plugins/views/PluginList/__snapshots__/filters.test.ts.snap b/src/plugins/views/PluginList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..79b6ca913 --- /dev/null +++ b/src/plugins/views/PluginList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "active": "true", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"active=true"`; diff --git a/src/plugins/views/PluginList/filters.test.ts b/src/plugins/views/PluginList/filters.test.ts new file mode 100644 index 000000000..fe14aa8b5 --- /dev/null +++ b/src/plugins/views/PluginList/filters.test.ts @@ -0,0 +1,57 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { PluginListUrlFilters } from "@saleor/plugins/urls"; +import { createFilterStructure } from "@saleor/plugins/components/PluginsListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: PluginListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: PluginListUrlFilters = { + active: true.toString() + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + isActive: { + active: false, + value: true + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/productTypes/views/ProductTypeList/__snapshots__/filters.test.ts.snap b/src/productTypes/views/ProductTypeList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..305a60be9 --- /dev/null +++ b/src/productTypes/views/ProductTypeList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "configurable": "CONFIGURABLE", + "type": "DIGITAL", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"configurable=CONFIGURABLE&type=DIGITAL"`; diff --git a/src/productTypes/views/ProductTypeList/filters.test.ts b/src/productTypes/views/ProductTypeList/filters.test.ts new file mode 100644 index 000000000..9911460a0 --- /dev/null +++ b/src/productTypes/views/ProductTypeList/filters.test.ts @@ -0,0 +1,66 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { ProductTypeListUrlFilters } from "@saleor/productTypes/urls"; +import { createFilterStructure } from "@saleor/productTypes/components/ProductTypeListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { + ProductTypeEnum, + ProductTypeConfigurable +} from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: ProductTypeListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: ProductTypeListUrlFilters = { + configurable: ProductTypeConfigurable.CONFIGURABLE, + type: ProductTypeEnum.DIGITAL + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(2); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + configurable: { + active: false, + value: ProductTypeConfigurable.CONFIGURABLE + }, + type: { + active: false, + value: ProductTypeEnum.DIGITAL + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/products/views/ProductList/__snapshots__/filters.test.ts.snap b/src/products/views/ProductList/__snapshots__/filters.test.ts.snap index 5f3c7e2c2..cb6472a86 100644 --- a/src/products/views/ProductList/__snapshots__/filters.test.ts.snap +++ b/src/products/views/ProductList/__snapshots__/filters.test.ts.snap @@ -1,13 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Get filter variables 1`] = ` +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` Object { - "isPublished": false, - "price": Object { - "gte": 10, - "lte": 20, - }, - "search": undefined, - "stockAvailability": "IN_STOCK", + "priceFrom": "10", + "priceTo": "20", + "status": "published", + "stockStatus": "IN_STOCK", } `; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"status=published&stockStatus=IN_STOCK&priceFrom=10&priceTo=20"`; diff --git a/src/products/views/ProductList/filters.test.ts b/src/products/views/ProductList/filters.test.ts index 83b9a8cbb..07a094dcd 100644 --- a/src/products/views/ProductList/filters.test.ts +++ b/src/products/views/ProductList/filters.test.ts @@ -1,13 +1,76 @@ -import { StockAvailability } from "@saleor/types/globalTypes"; -import { getFilterVariables } from "./filters"; +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; -test("Get filter variables", () => { - const filter = getFilterVariables({ - priceFrom: "10", - priceTo: "20", - status: "true", - stockStatus: StockAvailability.IN_STOCK +import { ProductListUrlFilters } from "@saleor/products/urls"; +import { + createFilterStructure, + ProductStatus +} from "@saleor/products/components/ProductListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { date } from "@saleor/fixtures"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { StockAvailability } from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: ProductListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); }); - expect(filter).toMatchSnapshot(); + it("should not be empty object if params given", () => { + const params: ProductListUrlFilters = { + priceFrom: "10", + priceTo: "20", + status: true.toString(), + stockStatus: StockAvailability.IN_STOCK + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(3); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + price: { + active: false, + value: { + max: "20", + min: "10" + } + }, + status: { + active: false, + value: ProductStatus.PUBLISHED + }, + stockStatus: { + active: false, + value: StockAvailability.IN_STOCK + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); }); diff --git a/src/products/views/ProductList/filters.ts b/src/products/views/ProductList/filters.ts index 476208e0d..1b94e5b62 100644 --- a/src/products/views/ProductList/filters.ts +++ b/src/products/views/ProductList/filters.ts @@ -11,7 +11,8 @@ import { } from "../../../types/globalTypes"; import { createFilterTabUtils, - createFilterUtils + createFilterUtils, + getGteLteVariables } from "../../../utils/filters"; import { ProductListUrlFilters, @@ -55,10 +56,10 @@ export function getFilterVariables( params.status !== undefined ? params.status === ProductStatus.PUBLISHED : null, - price: { + price: getGteLteVariables({ gte: parseFloat(params.priceFrom), lte: parseFloat(params.priceTo) - }, + }), search: params.query, stockAvailability: params.stockStatus !== undefined diff --git a/src/services/components/ServiceListPage/index.ts b/src/services/components/ServiceListPage/index.ts index 0cbe92960..44625afe2 100644 --- a/src/services/components/ServiceListPage/index.ts +++ b/src/services/components/ServiceListPage/index.ts @@ -1,2 +1,3 @@ export { default } from "./ServiceListPage"; export * from "./ServiceListPage"; +export * from "./filters"; diff --git a/src/services/views/ServiceList/__snapshots__/filters.test.ts.snap b/src/services/views/ServiceList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..c63a81372 --- /dev/null +++ b/src/services/views/ServiceList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "active": "false", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"active=false"`; diff --git a/src/services/views/ServiceList/filters.test.ts b/src/services/views/ServiceList/filters.test.ts new file mode 100644 index 000000000..e52fe2de1 --- /dev/null +++ b/src/services/views/ServiceList/filters.test.ts @@ -0,0 +1,57 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { ServiceListUrlFilters } from "@saleor/services/urls"; +import { createFilterStructure } from "@saleor/services/components/ServiceListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: ServiceListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: ServiceListUrlFilters = { + active: false.toString() + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + isActive: { + active: false, + value: false + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/staff/views/StaffList/__snapshots__/filters.test.ts.snap b/src/staff/views/StaffList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..124fbeb79 --- /dev/null +++ b/src/staff/views/StaffList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "status": "ACTIVE", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"status=ACTIVE"`; diff --git a/src/staff/views/StaffList/filters.test.ts b/src/staff/views/StaffList/filters.test.ts new file mode 100644 index 000000000..32a812b2d --- /dev/null +++ b/src/staff/views/StaffList/filters.test.ts @@ -0,0 +1,58 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { StaffListUrlFilters } from "@saleor/staff/urls"; +import { createFilterStructure } from "@saleor/staff/components/StaffListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { StaffMemberStatus } from "@saleor/types/globalTypes"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: StaffListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: StaffListUrlFilters = { + status: StaffMemberStatus.ACTIVE + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + status: { + active: false, + value: StaffMemberStatus.ACTIVE + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +}); diff --git a/src/utils/filters/filters.ts b/src/utils/filters/filters.ts index 63456e042..00d38887f 100644 --- a/src/utils/filters/filters.ts +++ b/src/utils/filters/filters.ts @@ -43,4 +43,17 @@ export function getFilterQueryParams< ); } +type GteLte = Partial>; +export function getGteLteVariables(variables: GteLte): GteLte | null { + if ( + !![variables.gte, variables.lte].some( + v => v !== undefined && v !== null && !(typeof v === "number" && isNaN(v)) + ) + ) { + return variables; + } + + return null; +} + export default createFilterUtils; diff --git a/src/webhooks/views/WebhookList/__snapshots__/filters.test.ts.snap b/src/webhooks/views/WebhookList/__snapshots__/filters.test.ts.snap new file mode 100644 index 000000000..c63a81372 --- /dev/null +++ b/src/webhooks/views/WebhookList/__snapshots__/filters.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Filtering URL params should not be empty if active filters are present 1`] = ` +Object { + "active": "false", +} +`; + +exports[`Filtering URL params should not be empty if active filters are present 2`] = `"active=false"`; diff --git a/src/webhooks/views/WebhookList/filters.test.ts b/src/webhooks/views/WebhookList/filters.test.ts new file mode 100644 index 000000000..2aa937136 --- /dev/null +++ b/src/webhooks/views/WebhookList/filters.test.ts @@ -0,0 +1,57 @@ +import { createIntl } from "react-intl"; +import { stringify as stringifyQs } from "qs"; + +import { WebhookListUrlFilters } from "@saleor/webhooks/urls"; +import { createFilterStructure } from "@saleor/webhooks/components/WebhooksListPage"; +import { getFilterQueryParams } from "@saleor/utils/filters"; +import { getExistingKeys, setFilterOptsStatus } from "@test/filters"; +import { config } from "@test/intl"; +import { getFilterVariables, getFilterQueryParam } from "./filters"; + +describe("Filtering query params", () => { + it("should be empty object if no params given", () => { + const params: WebhookListUrlFilters = {}; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(0); + }); + + it("should not be empty object if params given", () => { + const params: WebhookListUrlFilters = { + active: false.toString() + }; + const filterVariables = getFilterVariables(params); + + expect(getExistingKeys(filterVariables)).toHaveLength(1); + }); +}); + +describe("Filtering URL params", () => { + const intl = createIntl(config); + + const filters = createFilterStructure(intl, { + isActive: { + active: false, + value: false + } + }); + + it("should be empty if no active filters", () => { + const filterQueryParams = getFilterQueryParams( + filters, + getFilterQueryParam + ); + + expect(getExistingKeys(filterQueryParams)).toHaveLength(0); + }); + + it("should not be empty if active filters are present", () => { + const filterQueryParams = getFilterQueryParams( + setFilterOptsStatus(filters, true), + getFilterQueryParam + ); + + expect(filterQueryParams).toMatchSnapshot(); + expect(stringifyQs(filterQueryParams)).toMatchSnapshot(); + }); +});