diff --git a/.eslintrc b/.eslintrc index 2174660f1..f1fb0cb29 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,14 +1,29 @@ { "root": true, - "plugins": ["jest-dom"], - "extends": ["adslot", "plugin:jest-dom/recommended", "plugin:import/typescript"], + "extends": ["adslot", "plugin:import/typescript"], "settings": { "lodash": { "version": 4 + }, + "import/resolver": { + "alias": { + "map": [["testing", "./config/testing"]] + } } }, "rules": { "no-console": ["error", { "allow": ["warn", "error"] }], "@typescript-eslint/no-explicit-any": "off" - } + }, + + "overrides": [ + { + "files": ["**/?(*.)spec.js?(x)"], + "extends": ["plugin:jest/recommended", "plugin:jest-dom/recommended", "plugin:testing-library/react"], + "rules": { + "jest/expect-expect": "error", + "jest/no-commented-out-tests": "off" + } + } + ] } diff --git a/README.md b/README.md index 406b5a509..6434922ff 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,6 @@ window.Perf = Perf; - Interact the component in the way that feels slow. - Run `Perf.stop()` to stop recording. - Run `Perf.printWasted()` to see the nodes that are re–rendering but do not change the DOM. -- Use fastStatelessWrapper to wrap this component, passing in the properties to check. - Re-test to make sure you're improving performance. ## Design tokens diff --git a/codecov.yml b/codecov.yml index 135b37ff9..15f127db4 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,10 +1,10 @@ coverage: round: down precision: 2 - range: 98...100 + range: 95...100 ignore: - - 'src/components/**/*.spec.*' - - 'src/components/**/mocks.*' + - 'src/**/*.spec.*' + - 'src/**/mocks.*' status: project: default: diff --git a/config/testSetup.js b/config/testSetup.js index 232d4a58e..22a8de0c7 100644 --- a/config/testSetup.js +++ b/config/testSetup.js @@ -1,18 +1,43 @@ -import '@testing-library/jest-dom/extend-expect'; +import '@testing-library/jest-dom'; -window.matchMedia = jest.fn().mockImplementation((query) => { - return { +// for slick-carousel, date picker +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: (query) => ({ matches: false, media: query, onchange: null, addListener: jest.fn(), removeListener: jest.fn(), - }; + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + }), }); -Object.defineProperty(window, 'scrollTo', { value: () => {}, writable: true }); -window.ResizeObserver = class ResizeObserver { - observe = jest.fn(); - unobserve = jest.fn(); - disconnect = jest.fn(); -}; +// for RichTextEditor +Object.defineProperty(window, 'scrollTo', { + writable: true, + value: jest.fn(), +}); + +Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', { + writable: true, + value: jest.fn(), +}); + +// for Paragraph +Object.defineProperty(window, 'ResizeObserver', { + writable: true, + value: class ResizeObserver { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + }, +}); + +// for cropperjs +beforeEach(() => { + jest.spyOn(XMLHttpRequest.prototype, 'open').mockReturnValue(); + jest.spyOn(XMLHttpRequest.prototype, 'send').mockReturnValue(); +}); diff --git a/config/testing.d.ts b/config/testing.d.ts new file mode 100644 index 000000000..75a076c8f --- /dev/null +++ b/config/testing.d.ts @@ -0,0 +1,870 @@ +import { queryHelpers, queries } from '@testing-library/react'; +import type { RenderOptions } from '@testing-library/react'; +import * as pf from '@testing-library/dom/node_modules/pretty-format'; +declare const customWithin: (target: HTMLElement) => { + getByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T; + getAllByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_1[]; + queryByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_2; + queryAllByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_3[]; + findByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByLabelText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_6; + getAllByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_7[]; + queryByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_8; + queryAllByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_9[]; + findByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByPlaceholderText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_12; + getAllByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_13[]; + queryByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_14; + queryAllByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ): T_15[]; + findByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByText( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_18; + getAllByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_19[]; + queryByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_20; + queryAllByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_21[]; + findByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByAltText( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_24; + getAllByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_25[]; + queryByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_26; + queryAllByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_27[]; + findByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByTitle( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_30; + getAllByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_31[]; + queryByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_32; + queryAllByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_33[]; + findByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByDisplayValue( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ): T_36; + getAllByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ): T_37[]; + queryByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ): T_38; + queryAllByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ): T_39[]; + findByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByRole( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + getByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_42; + getAllByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_43[]; + queryByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_44; + queryAllByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ): T_45[]; + findByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; + findAllByTestId( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ): Promise; +} & { + queryAllByDts: (value: string) => HTMLElement[]; + queryByDts: (value: string) => HTMLElement; + getAllByDts: (value: string) => HTMLElement[]; + getByDts: (value: string) => HTMLElement; + findAllByDts: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + findByDts: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + queryAllByClass: (value: string) => HTMLElement[]; + queryByClass: (value: string) => HTMLElement; + getAllByClass: (value: string) => HTMLElement[]; + getByClass: (value: string) => HTMLElement; + findAllByClass: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + findByClass: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + getByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement; + getAllByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement[]; + queryByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement; + queryAllByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement[]; + findByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByLabelText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + getAllByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + queryByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + queryAllByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + findByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByPlaceholderText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement; + getAllByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement[]; + queryByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement; + queryAllByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => HTMLElement[]; + findByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByText: ( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + getAllByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + queryByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + queryAllByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + findByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByAltText: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + getAllByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + queryByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + queryAllByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + findByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByTitle: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + getAllByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + queryByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + queryAllByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + findByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByDisplayValue: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByRole: (role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement; + getAllByRole: ( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => HTMLElement[]; + queryByRole: (role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement; + queryAllByRole: ( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => HTMLElement[]; + findByRole: ( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByRole: ( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + getByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + getAllByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + queryByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement; + queryAllByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]; + findByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; + findAllByTestId: ( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise; +}; +declare const customScreen: { + queryAllByDts: (value: string) => HTMLElement[]; + queryByDts: (value: string) => HTMLElement; + getAllByDts: (value: string) => HTMLElement[]; + getByDts: (value: string) => HTMLElement; + findAllByDts: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + findByDts: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + queryAllByClass: (value: string) => HTMLElement[]; + queryByClass: (value: string) => HTMLElement; + getAllByClass: (value: string) => HTMLElement[]; + getByClass: (value: string) => HTMLElement; + findAllByClass: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + findByClass: ( + args_0: string, + args_1?: undefined, + args_2?: import('@testing-library/react').waitForOptions + ) => Promise; + getByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement); + getAllByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_1[]) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement[]); + queryByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_2) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement); + queryAllByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_3[]) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement[]); + findByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByLabelText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_6) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + getAllByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_7[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + queryByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_8) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + queryAllByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_9[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + findByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByPlaceholderText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_12) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement); + getAllByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_13[]) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement[]); + queryByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_14) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement); + queryAllByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions + ) => T_15[]) & + ((id: import('@testing-library/react').Matcher, options?: queryHelpers.SelectorMatcherOptions) => HTMLElement[]); + findByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByText: (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: queryHelpers.SelectorMatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_18) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + getAllByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_19[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + queryByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_20) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + queryAllByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_21[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + findByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByAltText: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_24) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + getAllByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_25[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + queryByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_26) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + queryAllByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_27[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + findByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByTitle: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_30) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + getAllByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_31[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + queryByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_32) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + queryAllByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_33[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + findByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByDisplayValue: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => T_36) & + ((role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement); + getAllByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => T_37[]) & + ((role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement[]); + queryByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => T_38) & + ((role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement); + queryAllByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions + ) => T_39[]) & + ((role: import('@testing-library/react').ByRoleMatcher, options?: queries.ByRoleOptions) => HTMLElement[]); + findByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByRole: (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + role: import('@testing-library/react').ByRoleMatcher, + options?: queries.ByRoleOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + getByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_42) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + getAllByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_43[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + queryByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_44) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement); + queryAllByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => T_45[]) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions + ) => HTMLElement[]); + findByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + findAllByTestId: (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise) & + (( + id: import('@testing-library/react').Matcher, + options?: import('@testing-library/react').MatcherOptions, + waitForElementOptions?: import('@testing-library/react').waitForOptions + ) => Promise); + debug: ( + element?: Element | HTMLDocument | (Element | HTMLDocument)[], + maxLength?: number, + options?: pf.PrettyFormatOptions + ) => void; + logTestingPlaygroundURL: (element?: Element | HTMLDocument) => string; +}; +declare let user: import('@testing-library/user-event/dist/types/setup/setup').UserEvent; +declare const customRender: ( + ui: React.ReactElement, + options?: Omit +) => import('@testing-library/react').RenderResult; +export * from '@testing-library/react'; +export { user }; +export { customWithin as within }; +export { customScreen as screen }; +export { customRender as render }; diff --git a/config/testing.js b/config/testing.js new file mode 100644 index 000000000..b8de24a27 --- /dev/null +++ b/config/testing.js @@ -0,0 +1,50 @@ +import { render, screen, queryHelpers, within, queries, buildQueries } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +const queryAllByClass = (container, value) => { + const matcher = (nodeClasses) => { + const classList = nodeClasses.split(' '); + return value.split(' ').every((entry) => classList.find((part) => part === entry)); + }; + + return queryHelpers.queryAllByAttribute('class', container, matcher, { exact: false }); +}; +const getClassMultipleError = (_c, value) => `Found multiple elements with the className of: ${value}`; +const getClassMissingError = (_c, value) => `Unable to find an element with the className of: ${value}`; +const [queryByClass, getAllByClass, getByClass, findAllByClass, findByClass] = buildQueries( + queryAllByClass, + getClassMultipleError, + getClassMissingError +); + +const queryAllByDts = (...args) => queryHelpers.queryAllByAttribute('data-test-selector', ...args); +const getDtsMultipleError = (_c, value) => `Found multiple elements with the data-test-selector of: ${value}`; +const getDtsMissingError = (_c, value) => `Unable to find an element with the data-test-selector of: ${value}`; +const [queryByDts, getAllByDts, getByDts, findAllByDts, findByDts] = buildQueries( + queryAllByDts, + getDtsMultipleError, + getDtsMissingError +); + +const byClass = { queryAllByClass, queryByClass, getAllByClass, getByClass, findAllByClass, findByClass }; +const byDts = { queryAllByDts, queryByDts, getAllByDts, getByDts, findAllByDts, findByDts }; +const customWithin = (ui) => within(ui, { ...queries, ...byClass, ...byDts }); + +const classQueries = within(document.body, byClass); +const dtsQueries = within(document.body, byDts); +const customScreen = { ...screen, ...classQueries, ...dtsQueries }; + +let user = userEvent.setup(); +beforeEach(() => { + user = userEvent.setup(); +}); +const customRender = (ui, options) => { + user = userEvent.setup(); + return render(ui, options); +}; + +export * from '@testing-library/react'; +export { user }; +export { customWithin as within }; +export { customScreen as screen }; +export { customRender as render }; diff --git a/jest.config.js b/jest.config.js index 80dae8311..b3e19e600 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,22 +1,26 @@ +/** @type {import('jest').Config} */ module.exports = { - verbose: true, - moduleFileExtensions: ['js', 'jsx', 'json'], transform: { - '^.+\\.(js|jsx)?$': 'babel-jest', - '^.+\\.css$': '/config/cssTransform.js', + '\\.jsx?$': 'babel-jest', + '\\.css$': '/config/cssTransform.js', }, transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$'], - clearMocks: true, - coverageDirectory: 'coverage', + resetMocks: true, // for global mocks in testSetup or __mocks__ + restoreMocks: true, + resetModules: true, testEnvironment: 'jsdom', setupFilesAfterEnv: ['/config/testSetup.js'], - collectCoverageFrom: ['src/**/*.{js,jsx}'], + coverageDirectory: 'coverage', + collectCoverageFrom: ['src/**/*.{js,jsx}', '!src/**/*.d.ts', '!src/invariant.js'], coverageThreshold: { global: { - statements: 100, + statements: 95, branches: 95, - functions: 100, - lines: 100, + functions: 95, + lines: 95, }, }, + moduleNameMapper: { + testing$: '/config/testing.js', + }, }; diff --git a/package-lock.json b/package-lock.json index 522f2460d..fe243adf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,8 +39,8 @@ "@mdx-js/loader": "^1.6.22", "@mdx-js/react": "^1.6.22", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^12.1.5", - "@testing-library/user-event": "^13.5.0", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", "axios": "^1.3.5", "babel-jest": "^29.3.1", "babel-loader": "^9.1.2", @@ -58,13 +58,16 @@ "css-minimizer-webpack-plugin": "^5.0.0", "date-fns": "^2.29.3", "eslint": "^8.38.0", - "eslint-config-adslot": "^1.5.1", + "eslint-config-adslot": "github:Adslot/eslint-config-adslot#no-snapshot", + "eslint-import-resolver-alias": "^1.1.2", + "eslint-plugin-jest": "^27.2.1", "eslint-plugin-jest-dom": "^4.0.3", + "eslint-plugin-testing-library": "^5.11.0", "glob": "^8.1.0", "html-webpack-plugin": "^5.5.0", "husky": "^8.0.3", - "jest": "^29.3.1", - "jest-environment-jsdom": "^29.3.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", "lint-staged": "^13.2.2", "mini-css-extract-plugin": "^2.7.5", "null-loader": "^4.0.1", @@ -109,8 +112,8 @@ "peerDependencies": { "lodash": "^4.17.21", "moment": "^2.29.4", - "react": "^16.14.0", - "react-dom": "^16.14.0" + "react": "^18.2.0", + "react-dom": "^18.2.0" } }, "node_modules/@adobe/css-tools": { @@ -1486,12 +1489,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.20.2" }, "engines": { "node": ">=6.9.0" @@ -1501,9 +1504,9 @@ } }, "node_modules/@babel/plugin-syntax-typescript/node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -4200,16 +4203,16 @@ } }, "node_modules/@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -4234,9 +4237,9 @@ } }, "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4322,37 +4325,37 @@ } }, "node_modules/@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -4386,9 +4389,9 @@ } }, "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4506,15 +4509,15 @@ } }, "node_modules/@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4538,9 +4541,9 @@ } }, "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4617,25 +4620,25 @@ } }, "node_modules/@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "dependencies": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.3" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4651,17 +4654,17 @@ } }, "node_modules/@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4685,9 +4688,9 @@ } }, "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4764,15 +4767,15 @@ } }, "node_modules/@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -4796,9 +4799,9 @@ } }, "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -4875,16 +4878,16 @@ } }, "node_modules/@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -4897,9 +4900,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -4935,9 +4938,9 @@ } }, "node_modules/@jest/reporters/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -4945,9 +4948,9 @@ } }, "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -5109,9 +5112,9 @@ } }, "node_modules/@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", @@ -5123,9 +5126,9 @@ } }, "node_modules/@jest/source-map/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -5133,13 +5136,13 @@ } }, "node_modules/@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -5165,9 +5168,9 @@ } }, "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -5244,14 +5247,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" }, "engines": { @@ -5268,26 +5271,26 @@ } }, "node_modules/@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -5761,40 +5764,40 @@ "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "node_modules/@testing-library/dom": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.1.tgz", - "integrity": "sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", + "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", + "@types/aria-query": "^5.0.1", "aria-query": "^5.0.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", + "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@testing-library/dom/node_modules/ansi-styles": { @@ -5989,33 +5992,30 @@ } }, "node_modules/@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", + "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" + "@testing-library/dom": "^9.0.0", + "@types/react-dom": "^18.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" }, "peerDependencies": { - "react": "<18.0.0", - "react-dom": "<18.0.0" + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, "engines": { - "node": ">=10", + "node": ">=12", "npm": ">=6" }, "peerDependencies": { @@ -6065,28 +6065,28 @@ "dev": true }, "node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "node_modules/@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "node_modules/@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" @@ -6217,9 +6217,9 @@ } }, "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "dependencies": { "@types/node": "*" @@ -6380,9 +6380,9 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "node_modules/@types/prop-types": { @@ -6424,9 +6424,9 @@ } }, "node_modules/@types/react-dom": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", - "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", + "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", "dev": true, "dependencies": { "@types/react": "*" @@ -7621,9 +7621,9 @@ } }, "node_modules/axe-core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", - "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "dev": true, "engines": { "node": ">=4" @@ -7675,15 +7675,15 @@ } }, "node_modules/babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "dependencies": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -7966,9 +7966,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -8095,12 +8095,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -10801,14 +10801,15 @@ }, "node_modules/eslint-config-adslot": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/eslint-config-adslot/-/eslint-config-adslot-1.5.1.tgz", - "integrity": "sha512-eHWduuEpSYBGtLCJ87aecKlMM8BUqeyTcIK86DPmG5KgJfVGirbE6S936Me1Xq2VBBBrzipZabPNca2Ecuq+KQ==", + "resolved": "git+ssh://git@github.com/Adslot/eslint-config-adslot.git#3239e7cae61a44fa3dcdeaaae5887be29b2b6784", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", "confusing-browser-globals": "^1.0.11", "eslint-config-prettier": "^8.8.0", + "eslint-plugin-adslot": "file:plugin", "eslint-plugin-chai-friendly": "^0.7.2", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jest": "^27.2.1", @@ -10824,6 +10825,12 @@ "eslint": "^8.38.0" } }, + "node_modules/eslint-config-adslot/plugin": { + "name": "eslint-plugin-adslot", + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, "node_modules/eslint-config-prettier": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", @@ -10836,6 +10843,18 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-import-resolver-alias": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz", + "integrity": "sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==", + "dev": true, + "engines": { + "node": ">= 4" + }, + "peerDependencies": { + "eslint-plugin-import": ">=1.4.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", @@ -10894,6 +10913,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, + "node_modules/eslint-plugin-adslot": { + "resolved": "node_modules/eslint-config-adslot/plugin", + "link": true + }, "node_modules/eslint-plugin-chai-friendly": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.2.tgz", @@ -11162,6 +11185,22 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.58.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -11642,16 +11681,16 @@ } }, "node_modules/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -14063,15 +14102,15 @@ } }, "node_modules/jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.5.0" }, "bin": { "jest": "bin/jest.js" @@ -14089,9 +14128,9 @@ } }, "node_modules/jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "dependencies": { "execa": "^5.0.0", @@ -14117,28 +14156,29 @@ } }, "node_modules/jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -14164,9 +14204,9 @@ } }, "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -14299,21 +14339,21 @@ } }, "node_modules/jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "dependencies": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -14350,9 +14390,9 @@ } }, "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -14429,31 +14469,31 @@ } }, "node_modules/jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -14491,9 +14531,9 @@ } }, "node_modules/jest-config/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -14725,9 +14765,9 @@ } }, "node_modules/jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -14737,16 +14777,16 @@ } }, "node_modules/jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -14770,9 +14810,9 @@ } }, "node_modules/jest-each/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -14890,18 +14930,18 @@ } }, "node_modules/jest-environment-jsdom": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.3.1.tgz", - "integrity": "sha512-G46nKgiez2Gy4zvYNhayfMEAFlVHhWfncqvqS6yCd0i+a4NsSUD2WtrKSaYQrYiLQaupHXxCRi8xxVL2M9PbhA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", "jsdom": "^20.0.0" }, "engines": { @@ -15013,17 +15053,17 @@ } }, "node_modules/jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -15047,9 +15087,9 @@ } }, "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -15135,20 +15175,20 @@ } }, "node_modules/jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -15177,9 +15217,9 @@ } }, "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -15286,13 +15326,13 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "dependencies": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -15340,15 +15380,15 @@ "dev": true }, "node_modules/jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -15490,18 +15530,18 @@ } }, "node_modules/jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -15527,9 +15567,9 @@ } }, "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -15647,14 +15687,14 @@ } }, "node_modules/jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -15678,9 +15718,9 @@ } }, "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -15774,28 +15814,28 @@ } }, "node_modules/jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "engines": { @@ -15803,13 +15843,13 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "dependencies": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -15895,30 +15935,30 @@ } }, "node_modules/jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "dependencies": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -15944,9 +15984,9 @@ } }, "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -16087,31 +16127,31 @@ } }, "node_modules/jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -16137,9 +16177,9 @@ } }, "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -16254,9 +16294,9 @@ } }, "node_modules/jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -16265,23 +16305,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "engines": { @@ -16306,9 +16345,9 @@ } }, "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -16438,9 +16477,9 @@ "dev": true }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -16578,17 +16617,17 @@ } }, "node_modules/jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "dependencies": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.5.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -16612,9 +16651,9 @@ } }, "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -16744,18 +16783,18 @@ } }, "node_modules/jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "dependencies": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "string-length": "^4.0.1" }, "engines": { @@ -16780,9 +16819,9 @@ } }, "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -17792,9 +17831,9 @@ } }, "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "bin": { "lz-string": "bin/bin.js" @@ -20393,6 +20432,22 @@ "node": ">=6" } }, + "node_modules/pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -20496,14 +20551,12 @@ } }, "node_modules/react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "peer": true, "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" @@ -20759,28 +20812,16 @@ "dev": true }, "node_modules/react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "^16.14.0" - } - }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "react": "^18.2.0" } }, "node_modules/react-error-overlay": { @@ -21682,9 +21723,9 @@ } }, "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, "engines": { "node": ">=10" @@ -21833,6 +21874,15 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -26141,18 +26191,18 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.20.2" }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", "dev": true } } @@ -28022,16 +28072,16 @@ "dev": true }, "@jest/console": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" }, "dependencies": { @@ -28050,9 +28100,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28116,37 +28166,37 @@ } }, "@jest/core": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/reporters": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.2.0", - "jest-config": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-resolve-dependencies": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", - "jest-watcher": "^29.3.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -28166,9 +28216,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28257,15 +28307,15 @@ } }, "@jest/environment": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "requires": { - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1" + "jest-mock": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -28283,9 +28333,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28343,22 +28393,22 @@ } }, "@jest/expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "requires": { - "expect": "^29.3.1", - "jest-snapshot": "^29.3.1" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" } }, "@jest/expect-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "requires": { - "jest-get-type": "^29.2.0" + "jest-get-type": "^29.4.3" }, "dependencies": { "jest-get-type": { @@ -28370,17 +28420,17 @@ } }, "@jest/fake-timers": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "requires": { - "@jest/types": "^29.3.1", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -28398,9 +28448,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28458,15 +28508,15 @@ } }, "@jest/globals": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/types": "^29.3.1", - "jest-mock": "^29.3.1" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -28484,9 +28534,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28544,16 +28594,16 @@ } }, "@jest/reporters": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", @@ -28566,9 +28616,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -28590,9 +28640,9 @@ } }, "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "requires": { "@jridgewell/resolve-uri": "3.1.0", @@ -28600,9 +28650,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28723,9 +28773,9 @@ } }, "@jest/source-map": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "requires": { "@jridgewell/trace-mapping": "^0.3.15", @@ -28734,9 +28784,9 @@ }, "dependencies": { "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "requires": { "@jridgewell/resolve-uri": "3.1.0", @@ -28746,13 +28796,13 @@ } }, "@jest/test-result": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -28772,9 +28822,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -28832,14 +28882,14 @@ } }, "@jest/test-sequencer": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "slash": "^3.0.0" }, "dependencies": { @@ -28852,26 +28902,26 @@ } }, "@jest/transform": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" + "write-file-atomic": "^4.0.2" }, "dependencies": { "@jest/types": { @@ -29236,36 +29286,36 @@ "dev": true }, "@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^2.0.0" } }, "@testing-library/dom": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.1.tgz", - "integrity": "sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz", + "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", + "@types/aria-query": "^5.0.1", "aria-query": "^5.0.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", + "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, "dependencies": { @@ -29414,24 +29464,22 @@ } }, "@testing-library/react": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", - "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.0.0.tgz", + "integrity": "sha512-S04gSNJbYE30TlIMLTzv6QCTzt9AqIF5y6s6SzVFILNcNvbV/jU96GeiTPillGQo+Ny64M/5PV7klNYYgv5Dfg==", "dev": true, "requires": { "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0", - "@types/react-dom": "<18.0.0" + "@testing-library/dom": "^9.0.1", + "@types/react-dom": "^18.0.0" } }, "@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", + "version": "14.4.3", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", + "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", "dev": true, - "requires": { - "@babel/runtime": "^7.12.5" - } + "requires": {} }, "@tootallnate/once": { "version": "2.0.0", @@ -29470,28 +29518,28 @@ "dev": true }, "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", "dev": true }, "@types/babel__core": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", - "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, "requires": { "@babel/types": "^7.0.0" @@ -29622,9 +29670,9 @@ } }, "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "requires": { "@types/node": "*" @@ -29778,9 +29826,9 @@ "dev": true }, "@types/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", "dev": true }, "@types/prop-types": { @@ -29822,9 +29870,9 @@ } }, "@types/react-dom": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", - "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "version": "18.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.4.tgz", + "integrity": "sha512-G2mHoTMTL4yoydITgOGwWdWMVd8sNgyEP85xVmMKAPUBwQWm9wBPQUmvbeF4V3WBY1P7mmL4BkjQ0SqUpf1snw==", "dev": true, "requires": { "@types/react": "*" @@ -30723,9 +30771,9 @@ "dev": true }, "axe-core": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", - "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "dev": true }, "axios": { @@ -30773,15 +30821,15 @@ } }, "babel-jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "requires": { - "@jest/transform": "^29.3.1", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.2.0", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -30984,9 +31032,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -31092,12 +31140,12 @@ } }, "babel-preset-jest": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^29.2.0", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -33279,15 +33327,15 @@ } }, "eslint-config-adslot": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/eslint-config-adslot/-/eslint-config-adslot-1.5.1.tgz", - "integrity": "sha512-eHWduuEpSYBGtLCJ87aecKlMM8BUqeyTcIK86DPmG5KgJfVGirbE6S936Me1Xq2VBBBrzipZabPNca2Ecuq+KQ==", + "version": "git+ssh://git@github.com/Adslot/eslint-config-adslot.git#3239e7cae61a44fa3dcdeaaae5887be29b2b6784", "dev": true, + "from": "eslint-config-adslot@github:Adslot/eslint-config-adslot#no-snapshot", "requires": { "@typescript-eslint/eslint-plugin": "^5.58.0", "@typescript-eslint/parser": "^5.58.0", "confusing-browser-globals": "^1.0.11", "eslint-config-prettier": "^8.8.0", + "eslint-plugin-adslot": "file:plugin", "eslint-plugin-chai-friendly": "^0.7.2", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jest": "^27.2.1", @@ -33304,6 +33352,13 @@ "dev": true, "requires": {} }, + "eslint-import-resolver-alias": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz", + "integrity": "sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==", + "dev": true, + "requires": {} + }, "eslint-import-resolver-node": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", @@ -33358,6 +33413,9 @@ } } }, + "eslint-plugin-adslot": { + "version": "file:node_modules/eslint-config-adslot/plugin" + }, "eslint-plugin-chai-friendly": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.7.2.tgz", @@ -33436,7 +33494,7 @@ "dev": true, "requires": { "@babel/runtime": "^7.16.3", - "@testing-library/dom": "^8.11.1", + "@testing-library/dom": "^9.0.1", "requireindex": "^1.2.0" } }, @@ -33551,6 +33609,15 @@ "dev": true, "requires": {} }, + "eslint-plugin-testing-library": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz", + "integrity": "sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^5.58.0" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -33722,16 +33789,16 @@ "dev": true }, "expect": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "requires": { - "@jest/expect-utils": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "dependencies": { "jest-get-type": { @@ -35459,15 +35526,15 @@ } }, "jest": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^29.3.1" + "jest-cli": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -35545,9 +35612,9 @@ } }, "jest-changed-files": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "requires": { "execa": "^5.0.0", @@ -35566,28 +35633,29 @@ } }, "jest-circus": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/expect": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "p-limit": "^3.1.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -35607,9 +35675,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -35707,21 +35775,21 @@ } }, "jest-cli": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "requires": { - "@jest/core": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", "yargs": "^17.3.1" }, @@ -35741,9 +35809,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -35801,31 +35869,31 @@ } }, "jest-config": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.3.1", - "@jest/types": "^29.3.1", - "babel-jest": "^29.3.1", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.3.1", - "jest-environment-node": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-runner": "^29.3.1", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -35845,9 +35913,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36019,25 +36087,25 @@ } }, "jest-docblock": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", - "jest-util": "^29.3.1", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -36055,9 +36123,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36146,18 +36214,18 @@ } }, "jest-environment-jsdom": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.3.1.tgz", - "integrity": "sha512-G46nKgiez2Gy4zvYNhayfMEAFlVHhWfncqvqS6yCd0i+a4NsSUD2WtrKSaYQrYiLQaupHXxCRi8xxVL2M9PbhA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/jsdom": "^20.0.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", "jsdom": "^20.0.0" }, "dependencies": { @@ -36236,17 +36304,17 @@ } }, "jest-environment-node": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^29.3.1", - "jest-util": "^29.3.1" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -36264,9 +36332,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36330,21 +36398,21 @@ "dev": true }, "jest-haste-map": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.2.0", - "jest-util": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -36364,9 +36432,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36447,13 +36515,13 @@ } }, "jest-leak-detector": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "requires": { - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -36488,15 +36556,15 @@ } }, "jest-matcher-utils": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "pretty-format": "^29.3.1" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "ansi-styles": { @@ -36600,18 +36668,18 @@ } }, "jest-message-util": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -36631,9 +36699,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36722,14 +36790,14 @@ } }, "jest-mock": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-util": "^29.3.1" + "jest-util": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -36747,9 +36815,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -36814,25 +36882,25 @@ "requires": {} }, "jest-regex-util": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true }, "jest-resolve": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.3.1", - "jest-validate": "^29.3.1", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "dependencies": { @@ -36894,40 +36962,40 @@ } }, "jest-resolve-dependencies": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "requires": { - "jest-regex-util": "^29.2.0", - "jest-snapshot": "^29.3.1" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" } }, "jest-runner": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "requires": { - "@jest/console": "^29.3.1", - "@jest/environment": "^29.3.1", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.2.0", - "jest-environment-node": "^29.3.1", - "jest-haste-map": "^29.3.1", - "jest-leak-detector": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-resolve": "^29.3.1", - "jest-runtime": "^29.3.1", - "jest-util": "^29.3.1", - "jest-watcher": "^29.3.1", - "jest-worker": "^29.3.1", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -36947,9 +37015,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -37055,31 +37123,31 @@ } }, "jest-runtime": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", - "dev": true, - "requires": { - "@jest/environment": "^29.3.1", - "@jest/fake-timers": "^29.3.1", - "@jest/globals": "^29.3.1", - "@jest/source-map": "^29.2.0", - "@jest/test-result": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-mock": "^29.3.1", - "jest-regex-util": "^29.2.0", - "jest-resolve": "^29.3.1", - "jest-snapshot": "^29.3.1", - "jest-util": "^29.3.1", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -37099,9 +37167,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -37185,9 +37253,9 @@ } }, "jest-snapshot": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -37196,23 +37264,22 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.3.1", - "@jest/transform": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.3.1", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.3.1", - "jest-get-type": "^29.2.0", - "jest-haste-map": "^29.3.1", - "jest-matcher-utils": "^29.3.1", - "jest-message-util": "^29.3.1", - "jest-util": "^29.3.1", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.3.1", + "pretty-format": "^29.5.0", "semver": "^7.3.5" }, "dependencies": { @@ -37231,9 +37298,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -37329,9 +37396,9 @@ "dev": true }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -37437,17 +37504,17 @@ } }, "jest-validate": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "requires": { - "@jest/types": "^29.3.1", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.2.0", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^29.3.1" + "pretty-format": "^29.5.0" }, "dependencies": { "@jest/types": { @@ -37465,9 +37532,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -37562,18 +37629,18 @@ } }, "jest-watcher": { - "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "requires": { - "@jest/test-result": "^29.3.1", - "@jest/types": "^29.3.1", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.3.1", + "jest-util": "^29.5.0", "string-length": "^4.0.1" }, "dependencies": { @@ -37592,9 +37659,9 @@ } }, "@types/yargs": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", - "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -38279,9 +38346,9 @@ } }, "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true }, "magic-string": { @@ -40033,6 +40100,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -40102,14 +40175,12 @@ } }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "peer": true, "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "loose-envify": "^1.1.0" } }, "react-datepicker": { @@ -40293,27 +40364,13 @@ } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "peer": true, "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - }, - "dependencies": { - "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", - "peer": true, - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - } + "scheduler": "^0.23.0" } }, "react-error-overlay": { @@ -41031,9 +41088,9 @@ } }, "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true }, "restore-cursor": { @@ -41139,6 +41196,15 @@ "xmlchars": "^2.2.0" } }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", diff --git a/package.json b/package.json index c208abe63..e56622aae 100644 --- a/package.json +++ b/package.json @@ -91,8 +91,8 @@ "@mdx-js/loader": "^1.6.22", "@mdx-js/react": "^1.6.22", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^12.1.5", - "@testing-library/user-event": "^13.5.0", + "@testing-library/react": "^14.0.0", + "@testing-library/user-event": "^14.4.3", "axios": "^1.3.5", "babel-jest": "^29.3.1", "babel-loader": "^9.1.2", @@ -110,13 +110,16 @@ "css-minimizer-webpack-plugin": "^5.0.0", "date-fns": "^2.29.3", "eslint": "^8.38.0", - "eslint-config-adslot": "^1.5.1", + "eslint-config-adslot": "github:Adslot/eslint-config-adslot#no-snapshot", + "eslint-import-resolver-alias": "^1.1.2", + "eslint-plugin-jest": "^27.2.1", "eslint-plugin-jest-dom": "^4.0.3", + "eslint-plugin-testing-library": "^5.11.0", "glob": "^8.1.0", "html-webpack-plugin": "^5.5.0", "husky": "^8.0.3", - "jest": "^29.3.1", - "jest-environment-jsdom": "^29.3.1", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", "lint-staged": "^13.2.2", "mini-css-extract-plugin": "^2.7.5", "null-loader": "^4.0.1", @@ -176,12 +179,17 @@ "peerDependencies": { "lodash": "^4.17.21", "moment": "^2.29.4", - "react": "^16.14.0", - "react-dom": "^16.14.0" + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "engines": { "node": "^18" }, + "overrides": { + "@testing-library/dom": "^9.0.1", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, "browserslist": [ "last 2 versions", "> 5%", diff --git a/scripts/babel-build.js b/scripts/babel-build.js index 74f98b1a5..899d4decb 100644 --- a/scripts/babel-build.js +++ b/scripts/babel-build.js @@ -1,5 +1,4 @@ const childProcess = require('child_process'); -const glob = require('glob'); const path = require('path'); const { promisify } = require('util'); @@ -11,7 +10,6 @@ const outDirs = { }; async function run() { - const relativeOutDir = '..'; const env = { NODE_ENV: process.env.BABEL_ENV || process.env.NODE_ENV, }; @@ -22,12 +20,7 @@ async function run() { const srcDir = path.resolve(__dirname, '../src'); const extensions = ['.js', '.jsx']; - const ignore = ['**/*.spec.js', '**/*.spec.jsx', '**/*.test.js', '**/*.test.jsx']; - - const topLevelNonIndexFiles = glob.sync(`*{${extensions.join(',')}}`, { cwd: srcDir, ignore }).filter((file) => { - return path.basename(file, path.extname(file)) !== 'index'; - }); - const topLevelPathImportsCanBePackages = topLevelNonIndexFiles.length === 0; + const ignore = ['**/__mocks__/*', '**/*.spec.js', '**/*.spec.jsx', '**/*.test.js', '**/*.test.jsx']; const outDir = path.resolve(__dirname, '..', outDirs[env.NODE_ENV]); @@ -43,7 +36,7 @@ async function run() { const command = ['npx babel', ...babelArgs].join(' '); - const { stderr, stdout } = await exec(command, { env: { ...process.env, ...env } }); + const { stderr } = await exec(command, { env: { ...process.env, ...env } }); if (stderr) { throw new Error(`'${command}' failed with \n${stderr}`); } diff --git a/scripts/generateDocs.js b/scripts/generateDocs.js index 947d0ac93..e7dda2e92 100644 --- a/scripts/generateDocs.js +++ b/scripts/generateDocs.js @@ -9,16 +9,16 @@ const glob = require('glob'); const handlers = reactDocgen.defaultHandlers.concat(displayNameHandler); const sourcePath = path.join(__dirname, '..'); -const filesToIgnore = ['fastStatelessWrapper', 'mocks.jsx', 'spec.jsx', 'test.jsx', 'BlockStyleButtons', 'InlineStyleButtons']; +const filesToIgnore = ['mocks.jsx', 'spec.jsx', 'test.jsx', 'BlockStyleButtons', 'InlineStyleButtons']; const outputFilePath = path.join(__dirname, '../www/containers/props.json'); (async () => { - const files = _.reject(await promisify(glob)('src/components/**/*.jsx', { cwd: sourcePath }), filePath => - _.some(filesToIgnore, ignoreFile => _.includes(filePath, ignoreFile)) + const files = _.reject(await promisify(glob)('src/components/**/*.jsx', { cwd: sourcePath }), (filePath) => + _.some(filesToIgnore, (ignoreFile) => _.includes(filePath, ignoreFile)) ); const result = {}; - files.forEach(filePath => { + files.forEach((filePath) => { const absolutePath = path.join(sourcePath, filePath); try { result[filePath] = reactDocgen.parse( diff --git a/src/__mocks__/invariant.js b/src/__mocks__/invariant.js new file mode 100644 index 000000000..a6c1a6498 --- /dev/null +++ b/src/__mocks__/invariant.js @@ -0,0 +1,3 @@ +const invariant = jest.fn(); + +export default invariant; diff --git a/src/components/Accordion/__snapshots__/index.spec.jsx.snap b/src/components/Accordion/__snapshots__/index.spec.jsx.snap deleted file mode 100644 index 980d9f230..000000000 --- a/src/components/Accordion/__snapshots__/index.spec.jsx.snap +++ /dev/null @@ -1,41 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` should have default props 1`] = ` -
-
-
- -
-
-`; diff --git a/src/components/Accordion/index.jsx b/src/components/Accordion/index.jsx index 5f6ef383e..7ee5ab1ae 100644 --- a/src/components/Accordion/index.jsx +++ b/src/components/Accordion/index.jsx @@ -3,6 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import Card from '../Card'; import Panel from '../Panel'; +import invariant from '../../invariant'; const Accordion = ({ dts, children, maxExpand, defaultActivePanelIds, onPanelClick }) => { const [activePanelIds, setActivePanelIds] = React.useState(() => { @@ -42,8 +43,10 @@ const Accordion = ({ dts, children, maxExpand, defaultActivePanelIds, onPanelCli }); }; - if ((_.isNumber(maxExpand) && maxExpand <= 0) || (_.isString(maxExpand) && maxExpand !== 'max')) - throw new Error("maxExpand must be a positive number or 'max'"); + invariant( + (_.isNumber(maxExpand) && maxExpand > 0) || (_.isString(maxExpand) && maxExpand === 'max'), + "maxExpand must be a positive number or 'max'" + ); return ( diff --git a/src/components/Accordion/index.spec.jsx b/src/components/Accordion/index.spec.jsx index 439534540..5c7b4bfea 100644 --- a/src/components/Accordion/index.spec.jsx +++ b/src/components/Accordion/index.spec.jsx @@ -1,172 +1,158 @@ import _ from 'lodash'; import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Accordion from '.'; import PanelMocks from '../Panel/mocks'; - -beforeEach(() => { - jest.spyOn(console, 'error').mockImplementation(_.noop); +import invariant from '../../invariant'; + +jest.mock('../../invariant'); + +const { panel1, panel2, panel3 } = PanelMocks; + +const makeProps = (override) => + _.merge( + { + dts: 'my-accordion', + onPanelClick: jest.fn(), + defaultActivePanelIds: [], + maxExpand: 'max', + }, + override + ); + +it('should render with defaults', () => { + render( + + {panel1.content} + + ); + expect(screen.getByTestId('card-container-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('card-container-wrapper')).toHaveAttribute('data-test-selector', 'my-accordion'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('card-content-wrapper')).toHaveTextContent('Panel 1'); }); -afterEach(() => console.error.mockRestore()); -afterEach(cleanup); - -describe('', () => { - const { panel1, panel2, panel3 } = PanelMocks; - - const makeProps = (override) => - _.merge( - { - dts: 'my-accordion', - onPanelClick: jest.fn(), - defaultActivePanelIds: [], - maxExpand: 'max', - }, - override - ); - - it('should render with defaults', () => { - const { queryByTestId, getByTestId } = render( - - {panel1.content} - - ); - expect(queryByTestId('card-container-wrapper')).toBeInTheDocument(); - expect(getByTestId('card-container-wrapper')).toHaveAttribute('data-test-selector', 'my-accordion'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); - expect(getByTestId('card-content-wrapper')).toHaveTextContent('Panel 1'); - }); +it('should render with props', () => { + render( + + {panel1.content} + {panel2.content} + {panel3.content} + + ); + + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); + expect(screen.queryAllByTestId('panel-wrapper')).toHaveLength(3); + + // generate a dts from panel id + expect(screen.queryAllByTestId('panel-wrapper')[0]).toHaveAttribute('data-test-selector', 'panel-1'); + expect(screen.queryAllByTestId('panel-wrapper')[0]).toHaveTextContent('Panel 1'); + expect(screen.queryAllByTestId('panel-wrapper')[1]).toHaveAttribute('data-test-selector', 'panel-2'); + expect(screen.queryAllByTestId('panel-wrapper')[1]).toHaveTextContent('Panel 2'); + expect(screen.queryAllByTestId('panel-wrapper')[2]).toHaveAttribute('data-test-selector', 'panel-3'); + expect(screen.queryAllByTestId('panel-wrapper')[2]).toHaveTextContent('Panel 3'); +}); - it('should have default props', () => { - const { getByTestId } = render( - - {panel1.content} - - ); - expect(getByTestId('card-container-wrapper')).toMatchSnapshot(); - }); +it('should expand or collapse any panels', async () => { + render( + + {panel1.content} + {panel2.content} + {panel3.content} + + ); + + await user.click(screen.queryAllByTestId('panel-header')[0]); + expect(screen.queryAllByTestId('panel-wrapper')[0]).not.toHaveClass('collapsed'); + await user.click(screen.queryAllByTestId('panel-header')[0]); + expect(screen.queryAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); +}); - it('should render with props', () => { - const { queryByTestId, queryAllByTestId } = render( - - {panel1.content} - {panel2.content} - {panel3.content} - - ); - - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); - expect(queryAllByTestId('panel-wrapper')).toHaveLength(3); - - // generate a dts from panel id - expect(queryAllByTestId('panel-wrapper')[0]).toHaveAttribute('data-test-selector', 'panel-1'); - expect(queryAllByTestId('panel-wrapper')[0]).toHaveTextContent('Panel 1'); - expect(queryAllByTestId('panel-wrapper')[1]).toHaveAttribute('data-test-selector', 'panel-2'); - expect(queryAllByTestId('panel-wrapper')[1]).toHaveTextContent('Panel 2'); - expect(queryAllByTestId('panel-wrapper')[2]).toHaveAttribute('data-test-selector', 'panel-3'); - expect(queryAllByTestId('panel-wrapper')[2]).toHaveTextContent('Panel 3'); +it('should expand or collapse any panels with a restriction of `maxExpand`', async () => { + const panel = (id) => ({ + id, + title: `Panel ${id}`, + dts: `panel-${id}`, + onClick: _.noop, }); - it('should expand or collapse any panels', () => { - const { queryAllByTestId } = render( - - {panel1.content} - {panel2.content} - {panel3.content} - - ); - - fireEvent.click(queryAllByTestId('panel-header')[0]); - expect(queryAllByTestId('panel-wrapper')[0]).not.toHaveClass('collapsed'); - fireEvent.click(queryAllByTestId('panel-header')[0]); - expect(queryAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); - }); + render( + + {panel1.content} + {panel2.content} + {panel3.content} + + ); + + await user.click(screen.queryAllByTestId('panel-header')[0]); + expect(screen.queryAllByTestId('panel-wrapper')[0]).not.toHaveClass('collapsed'); + expect(screen.queryAllByTestId('panel-wrapper')[1]).toHaveClass('collapsed'); + + await user.click(screen.queryAllByTestId('panel-header')[1]); + expect(screen.queryAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); + expect(screen.queryAllByTestId('panel-wrapper')[1]).not.toHaveClass('collapsed'); +}); - it('should expand or collapse any panels with a restriction of `maxExpand`', () => { - const panel = (id) => ({ - id, - title: `Panel ${id}`, - dts: `panel-${id}`, - onClick: _.noop, - }); - - const { queryAllByTestId } = render( - - {panel1.content} - {panel2.content} - {panel3.content} - - ); - - fireEvent.click(queryAllByTestId('panel-header')[0]); - expect(queryAllByTestId('panel-wrapper')[0]).not.toHaveClass('collapsed'); - expect(queryAllByTestId('panel-wrapper')[1]).toHaveClass('collapsed'); - - fireEvent.click(queryAllByTestId('panel-header')[1]); - expect(queryAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); - expect(queryAllByTestId('panel-wrapper')[1]).not.toHaveClass('collapsed'); - }); +it('should pass onPanelClick down to panels', async () => { + const props = makeProps(); + render( + + {panel1.content} + {panel2.content} + {panel3.content} + + ); + expect(screen.getAllByTestId('panel-wrapper')).toHaveLength(3); + + await user.click(screen.getAllByTestId('panel-header')[0]); + expect(props.onPanelClick).toHaveBeenCalledTimes(1); + expect(props.onPanelClick).toHaveBeenLastCalledWith('1'); + + await user.click(screen.getAllByTestId('panel-header')[1]); + expect(props.onPanelClick).toHaveBeenCalledTimes(2); + expect(props.onPanelClick).toHaveBeenLastCalledWith('2'); + + await user.click(screen.getAllByTestId('panel-header')[2]); + expect(props.onPanelClick).toHaveBeenCalledTimes(3); + expect(props.onPanelClick).toHaveBeenLastCalledWith('3'); +}); - it('should pass onPanelClick down to panels', () => { - const props = makeProps(); - const { queryAllByTestId } = render( - - {panel1.content} - {panel2.content} - {panel3.content} - - ); - expect(queryAllByTestId('panel-wrapper')).toHaveLength(3); - - fireEvent.click(queryAllByTestId('panel-header')[0]); - expect(props.onPanelClick).toHaveBeenCalledTimes(1); - expect(props.onPanelClick).toHaveBeenLastCalledWith('1'); - - fireEvent.click(queryAllByTestId('panel-header')[1]); - expect(props.onPanelClick).toHaveBeenCalledTimes(2); - expect(props.onPanelClick).toHaveBeenLastCalledWith('2'); - - fireEvent.click(queryAllByTestId('panel-header')[2]); - expect(props.onPanelClick).toHaveBeenCalledTimes(3); - expect(props.onPanelClick).toHaveBeenLastCalledWith('3'); - }); +it('should respect isCollapsed in Panel children', async () => { + const props = makeProps(); + delete props.onPanelClick; + + render( + + + {panel1.content} + + {panel2.content} + {panel3.content} + + ); + await user.click(screen.getAllByTestId('panel-header')[0]); + expect(screen.getAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); +}); - it('should respect isCollapsed in Panel children', () => { - const props = makeProps(); - delete props.onPanelClick; - - const { queryAllByTestId } = render( - - - {panel1.content} - - {panel2.content} - {panel3.content} - - ); - fireEvent.click(queryAllByTestId('panel-header')[0]); - expect(queryAllByTestId('panel-wrapper')[0]).toHaveClass('collapsed'); - }); +it('should throw error if props.maxExpand has invalid value', () => { + render( + + {panel1.content} + + ); - it('should throw error if props.maxExpand has invalid value', () => { - expect(() => - render( - - {panel1.content} - - ) - ).toThrowError(new Error("maxExpand must be a positive number or 'max'")); - }); + expect(invariant).toHaveBeenCalledTimes(1); + expect(invariant).toHaveBeenCalledWith(false, "maxExpand must be a positive number or 'max'"); +}); - it('should ignore children that are not an instance of Accordion.Panel', () => { - const { queryByTestId } = render( - -
test
- {panel1.content} -
- ); +it('should ignore children that are not an instance of Accordion.Panel', () => { + render( + +
test
+ {panel1.content} +
+ ); - expect(queryByTestId('should-not-render')).not.toBeInTheDocument(); - }); + expect(screen.queryByTestId('should-not-render')).not.toBeInTheDocument(); }); diff --git a/src/components/ActionPanel/index.spec.jsx b/src/components/ActionPanel/index.spec.jsx index 7314697f2..a276b9aba 100644 --- a/src/components/ActionPanel/index.spec.jsx +++ b/src/components/ActionPanel/index.spec.jsx @@ -1,85 +1,71 @@ import _ from 'lodash'; import React from 'react'; -import { act, render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import Button from '../Button'; import ActionPanel from '.'; -afterEach(cleanup); +const makeProps = (override) => + _.merge( + { + title: 'Action Panel', + size: 'small', + onClose: _.noop, + children:
content
, + }, + override + ); -describe('', () => { - const makeProps = (override) => - _.merge( - { - title: 'Action Panel', - size: 'small', - onClose: _.noop, - children:
content
, - }, - override - ); +it('should render with defaults', () => { + const view = render(); + expect(screen.getByTestId('action-panel-header')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-header')).toHaveClass('aui--action-panel-header'); + expect(screen.getByTestId('action-panel-title')).toHaveClass('title'); + expect(screen.getByTestId('action-panel-title')).toHaveTextContent('Action Panel'); - it('should render with defaults', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('action-panel-header')).toBeInTheDocument(); - expect(getByTestId('action-panel-header')).toHaveClass('aui--action-panel-header'); - expect(getByTestId('action-panel-title')).toHaveClass('title'); - expect(getByTestId('action-panel-title')).toHaveTextContent('Action Panel'); + expect(screen.getByTestId('action-panel-body')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-body')).toHaveClass('aui--action-panel-body'); - expect(queryByTestId('action-panel-body')).toBeInTheDocument(); - expect(getByTestId('action-panel-body')).toHaveClass('aui--action-panel-body'); - - expect(document.body).not.toHaveClass('modal-open'); - }); - - it('should render as a modal', () => { - let wrapper; - act(() => { - wrapper = render( - Action })} /> - ); - }); + expect(view.baseElement).not.toHaveClass('modal-open'); +}); - expect(document.body).toHaveClass('modal-open'); - expect(wrapper.queryByTestId('action-panel-modal-wrapper')).toBeInTheDocument(); - expect(wrapper.getByTestId('action-panel-wrapper')).toHaveClass('aui--action-panel is-large action-modal'); - expect(wrapper.getAllByTestId('button-wrapper')[0]).toHaveTextContent('Cancel'); // default cancel text is 'Cancel' - wrapper.unmount(); - expect(document.body).not.toHaveClass('modal-open'); - }); +it('should render as a modal', () => { + const view = render( + Action })} /> + ); - it('should not render modal when isModal is false', () => { - let wrapper; - act(() => { - wrapper = render( - Action })} /> - ); - }); - expect(document.body).not.toHaveClass('modal-open'); + expect(view.baseElement).toHaveClass('modal-open'); + expect(screen.getByTestId('action-panel-modal-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('aui--action-panel is-large action-modal'); + expect(screen.getAllByTestId('button-wrapper')[0]).toHaveTextContent('Cancel'); // default cancel text is 'Cancel' + view.unmount(); + expect(view.baseElement).not.toHaveClass('modal-open'); +}); - wrapper.unmount(); - expect(document.body).not.toHaveClass('modal-open'); - }); +it('should not render modal when isModal is false', () => { + const view = render( + Action })} /> + ); + expect(view.baseElement).not.toHaveClass('modal-open'); + view.unmount(); + expect(view.baseElement).not.toHaveClass('modal-open'); +}); - it('should hide the modal with the visuallyHidden prop', () => { - const { getByTestId } = render(); +it('should hide the modal with the visuallyHidden prop', () => { + render(); - expect(getByTestId('action-panel-modal-wrapper')).toHaveClass('visually-hidden'); - }); + expect(screen.getByTestId('action-panel-modal-wrapper')).toHaveClass('visually-hidden'); +}); - it('should render a user specified text on the cancel button', () => { - let wrapper; - act(() => { - wrapper = render( - Action, - cancelButton: , - })} - /> - ); - }); - expect(wrapper.getAllByTestId('button-wrapper')[0]).toHaveTextContent('This is a cancel text'); - }); +it('should render a user specified text on the cancel button', () => { + render( + Action, + cancelButton: , + })} + /> + ); + expect(screen.getAllByTestId('button-wrapper')[0]).toHaveTextContent('This is a cancel text'); }); diff --git a/src/components/Alert/index.spec.jsx b/src/components/Alert/index.spec.jsx index 23568b41e..0769eb648 100644 --- a/src/components/Alert/index.spec.jsx +++ b/src/components/Alert/index.spec.jsx @@ -1,43 +1,39 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import Alert from '.'; -afterEach(cleanup); +it('should render default info type', () => { + render( + +
+ + ); + expect(screen.getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-info'); +}); -describe('', () => { - it('should render default info type', () => { - const { getByTestId } = render( - -
- - ); - expect(getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-info'); - expect(getByTestId('alert-wrapper').firstChild).toMatchInlineSnapshot(`
`); - }); - it('should render success type', () => { - const { getByTestId } = render( - -
- - ); - expect(getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-success'); - }); +it('should render success type', () => { + render( + +
+ + ); + expect(screen.getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-success'); +}); - it('should render warning type', () => { - const { getByTestId } = render( - -
- - ); - expect(getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-warning'); - }); +it('should render warning type', () => { + render( + +
+ + ); + expect(screen.getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-warning'); +}); - it('should render danger type', () => { - const { getByTestId } = render( - -
- - ); - expect(getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-danger'); - }); +it('should render danger type', () => { + render( + +
+ + ); + expect(screen.getByTestId('alert-wrapper')).toHaveClass('alert-component alert-component-danger'); }); diff --git a/src/components/AlertInput/index.spec.jsx b/src/components/AlertInput/index.spec.jsx index 615efb286..692f4a7fe 100644 --- a/src/components/AlertInput/index.spec.jsx +++ b/src/components/AlertInput/index.spec.jsx @@ -1,256 +1,174 @@ import React from 'react'; -import { - createEvent, - render, - cleanup, - fireEvent, - queryByAttribute, - queryAllByAttribute, - act, -} from '@testing-library/react'; +import { render, screen, user } from 'testing'; import AlertInput from '.'; -beforeEach(() => { - jest.useFakeTimers(); +describe('handleMouseEnter() and handleMouseLeave()', () => { + it('should set `isPopoverVisible` to true/false if alert message exists', async () => { + render(); + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + + await user.hover(screen.getByTestId('alert-input-wrapper')); + + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('popover-wrapper')).toBeInTheDocument(); + + await user.unhover(screen.getByTestId('alert-input-wrapper')); + + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + }); + + it('should not set `isPopoverVisible` to true if no alert message exists', async () => { + render(); + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + + await user.hover(screen.getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + + await user.unhover(screen.getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + }); }); -afterEach(() => { - jest.useRealTimers(); +describe('handleInputFocus()', () => { + it('should set `isFocused` to true, and `isPopoverVisible` if there is an alert message', async () => { + const onFocus = jest.fn(); + render(); + + await user.click(screen.getByClass('aui--alert-input__input')); + + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--focused'); + expect(screen.getByTestId('popover-wrapper')).toHaveClass('aui--popover-wrapper aui--alert-input__popover'); + expect(onFocus).toHaveBeenCalledTimes(1); + }); + + it('should set `isFocused` to true, but not `isPopoverVisible` if no alert message', async () => { + const onFocus = jest.fn(); + render(); + + await user.click(screen.getByClass('aui--alert-input__input')); + + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--focused'); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + expect(onFocus).toHaveBeenCalledTimes(1); + }); }); -afterEach(cleanup); -const getByClass = queryByAttribute.bind(null, 'class'); -const queryAllByClass = queryAllByAttribute.bind(null, 'class'); +describe('handleInputBlur ()', () => { + it('should set `isFocused` and `isPopoverVisible` to false', async () => { + render(); -describe('', () => { - describe('handleMouseEnter() and handleMouseLeave()', () => { - it('should set `isPopoverVisible` to true/false if alert message exists', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + await user.click(screen.getByClass('aui--alert-input__input')); + await user.tab(); - fireEvent.mouseEnter(getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('alert-input-wrapper')).not.toHaveClass('aui--alert-input--focused'); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + }); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); + it('should call `onBlur` if exists', async () => { + const onBlur = jest.fn(); + render(); - fireEvent.mouseLeave(getByTestId('alert-input-wrapper')); + await user.click(screen.getByClass('aui--alert-input__input')); + await user.tab(); + expect(onBlur).toHaveBeenCalledTimes(1); + }); +}); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); +describe('render()', () => { + it('should render with input props', () => { + const props = { + value: 100, + type: 'number', + min: 0, + placeholder: 'Type a number', + onValueChange: jest.fn(), + onBlur: jest.fn(), + }; + render(); + + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input'); + expect(screen.getByTestId('alert-input-wrapper')).not.toBeEmptyDOMElement(); + + expect(screen.getByPlaceholderText('Type a number')).toBeInTheDocument(); + expect(screen.getByPlaceholderText('Type a number')).toHaveClass('aui--alert-input__input'); + expect(screen.getByPlaceholderText('Type a number')).toHaveAttribute('min', '0'); + expect(screen.getByPlaceholderText('Type a number')).toHaveAttribute('type', 'number'); + expect(screen.getByPlaceholderText('Type a number')).toHaveValue(100); + }); - it('should not set `isPopoverVisible` to true if no alert message exists', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + it('should also render with default props', async () => { + render(); - fireEvent.mouseEnter(getByTestId('alert-input-wrapper')); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); + await user.hover(screen.getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('alert-input-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('success'); + expect(screen.getByTestId('popover-wrapper')).toHaveAttribute('placement', 'bottom'); + }); + + it('should render with addons', () => { + const props = { + prefixAddon: '$', + suffixAddon: '.00', + }; + render(); + + expect(screen.queryAllByClass('aui--alert-input__addon')).toHaveLength(2); + expect(screen.queryAllByClass('aui--alert-input__input')).toHaveLength(1); + expect(screen.getByText('$')).toHaveClass('aui--alert-input__addon'); + expect(screen.getByText('.00')).toHaveClass('aui--alert-input__addon'); + }); - fireEvent.mouseLeave(getByTestId('alert-input-wrapper')); - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); + it('should render with disabled input', () => { + const props = { + value: 10000, + disabled: true, + prefixAddon: '$', + suffixAddon: '.00', + }; + render(); + + expect(screen.queryAllByClass('aui--alert-input__addon')).toHaveLength(2); + expect(screen.queryAllByClass('aui--alert-input__input')).toHaveLength(1); + expect(screen.getByText('$')).toHaveClass('aui--alert-input__addon'); + expect(screen.getByText('.00')).toHaveClass('aui--alert-input__addon'); + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--disabled'); }); - describe('handleInputFocus()', () => { - it('should set `isFocused` to true, and `isPopoverVisible` if there is an alert message', () => { - const { container, getByTestId } = render(); - const onSelect = jest.fn(); - console.error = jest.fn(); - - fireEvent( - getByClass(container, 'aui--alert-input__input'), - createEvent.focus(getByClass(container, 'aui--alert-input__input'), { - target: { select: onSelect }, - }) - ); - - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--focused'); - expect(getByTestId('popover-wrapper')).toHaveClass('aui--popover-wrapper aui--alert-input__popover'); - expect(onSelect).toHaveBeenCalledTimes(1); - }); - - it('should set `isFocused` to true, but not `isPopoverVisible` if no alert message', () => { - const { container, getByTestId, queryByTestId } = render(); - const onSelect = jest.fn(); - console.error = jest.fn(); - - act(() => { - fireEvent( - getByClass(container, 'aui--alert-input__input'), - createEvent.focus(getByClass(container, 'aui--alert-input__input'), { - target: { select: onSelect }, - }) - ); - jest.runAllTimers(); - }); - - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--focused'); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - expect(onSelect).toHaveBeenCalledTimes(1); - }); - - it('should call prop `onFocus` if exists', () => { - const onFocus = jest.fn(); - const onSelect = jest.fn(); - console.error = jest.fn(); - const { container, getByTestId, queryByTestId } = render(); - - act(() => { - fireEvent( - getByClass(container, 'aui--alert-input__input'), - createEvent.focus(getByClass(container, 'aui--alert-input__input'), { - target: { select: onSelect }, - }) - ); - jest.runAllTimers(); - }); - - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--focused'); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - expect(onSelect).toHaveBeenCalledTimes(1); - expect(onFocus).toHaveBeenCalledTimes(1); - }); + it('should render with alert status', () => { + const props = { + alertStatus: 'error', + }; + render(); + expect(screen.getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input error'); }); - describe('handleInputBlur ()', () => { - it('should set `isFocused` and `isPopoverVisible` to false', () => { - const onSelect = jest.fn(); - console.error = jest.fn(); - const { container, getByTestId, queryByTestId } = render(); - act(() => { - fireEvent( - getByClass(container, 'aui--alert-input__input'), - createEvent.focus(getByClass(container, 'aui--alert-input__input'), { - target: { select: onSelect }, - }) - ); - jest.runAllTimers(); - }); - - act(() => { - fireEvent.blur(getByClass(container, 'aui--alert-input__input')); - jest.runAllTimers(); - }); - - expect(getByTestId('alert-input-wrapper')).not.toHaveClass('aui--alert-input--focused'); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); - - it('should call `onBlur` if exists', () => { - const onBlur = jest.fn(); - console.error = jest.fn(); - const { container } = render(); - - act(() => { - fireEvent.blur(getByClass(container, 'aui--alert-input__input')); - jest.runAllTimers(); - }); - - expect(onBlur).toHaveBeenCalledTimes(1); - }); + it('should set correct theme for popover', async () => { + let props = { + alertStatus: 'error', + alertMessage: 'something is wrong', + }; + const view = render(); + await user.hover(screen.getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('popover-wrapper')).toHaveClass('popover-error'); + + props.alertStatus = 'warning'; + view.rerender(); + expect(screen.getByTestId('popover-wrapper')).toHaveClass('popover-warn'); }); - describe('render()', () => { - it('should render with input props', () => { - const props = { - value: 100, - type: 'number', - min: 0, - placeholder: 'Type a number', - onValueChange: jest.fn(), - onBlur: jest.fn(), - }; - const { getByTestId, queryByTestId, getByPlaceholderText, queryByPlaceholderText } = render( - - ); - - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input'); - expect(getByTestId('alert-input-wrapper')).not.toBeEmptyDOMElement(); - - expect(queryByPlaceholderText('Type a number')).toBeInTheDocument(); - expect(getByPlaceholderText('Type a number')).toHaveClass('aui--alert-input__input'); - expect(getByPlaceholderText('Type a number')).toHaveAttribute('min', '0'); - expect(getByPlaceholderText('Type a number')).toHaveAttribute('type', 'number'); - expect(getByPlaceholderText('Type a number')).toHaveValue(100); - }); - - it('should also render with default props', () => { - const { getByTestId, queryByTestId } = render(); - console.error = jest.fn(); - act(() => { - fireEvent.mouseEnter(getByTestId('alert-input-wrapper')); - jest.runAllTimers(); - }); - - expect(queryByTestId('alert-input-wrapper')).toBeInTheDocument(); - expect(getByTestId('alert-input-wrapper')).toHaveClass('success'); - expect(getByTestId('popover-wrapper')).toHaveAttribute('placement', 'bottom'); - }); - - it('should render with addons', () => { - const props = { - prefixAddon: '$', - suffixAddon: '.00', - }; - const { getByTestId, getByText } = render(); - - expect(queryAllByClass(getByTestId('alert-input-wrapper'), 'aui--alert-input__addon')).toHaveLength(2); - expect(queryAllByClass(getByTestId('alert-input-wrapper'), 'aui--alert-input__input')).toHaveLength(1); - expect(getByText('$')).toHaveClass('aui--alert-input__addon'); - expect(getByText('.00')).toHaveClass('aui--alert-input__addon'); - }); - - it('should render with disabled input', () => { - const props = { - value: 10000, - disabled: true, - prefixAddon: '$', - suffixAddon: '.00', - }; - const { getByTestId, getByText } = render(); - - expect(queryAllByClass(getByTestId('alert-input-wrapper'), 'aui--alert-input__addon')).toHaveLength(2); - expect(queryAllByClass(getByTestId('alert-input-wrapper'), 'aui--alert-input__input')).toHaveLength(1); - expect(getByText('$')).toHaveClass('aui--alert-input__addon'); - expect(getByText('.00')).toHaveClass('aui--alert-input__addon'); - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input--disabled'); - }); - - it('should render with alert status', () => { - const props = { - alertStatus: 'error', - }; - const { getByTestId } = render(); - expect(getByTestId('alert-input-wrapper')).toHaveClass('aui--alert-input error'); - }); - - it('should set correct theme for popover', () => { - let props = { - alertStatus: 'error', - alertMessage: 'something is wrong', - }; - const { getByTestId, rerender } = render(); - fireEvent.mouseEnter(getByTestId('alert-input-wrapper')); - expect(getByTestId('popover-wrapper')).toHaveClass('popover-error'); - - props.alertStatus = 'warning'; - rerender(); - expect(getByTestId('popover-wrapper')).toHaveClass('popover-warn'); - }); - - it('should set correct popoverPlacement position for popover', () => { - const props = { - popoverPlacement: 'left', - alertMessage: 'something is wrong', - }; - const { getByTestId } = render(); - fireEvent.mouseEnter(getByTestId('alert-input-wrapper')); - expect(getByTestId('popover-wrapper')).toHaveAttribute('placement', 'left'); - }); + it('should set correct popoverPlacement position for popover', async () => { + const props = { + popoverPlacement: 'left', + alertMessage: 'something is wrong', + }; + render(); + await user.hover(screen.getByTestId('alert-input-wrapper')); + expect(screen.getByTestId('popover-wrapper')).toHaveAttribute('placement', 'left'); }); }); diff --git a/src/components/Anchor/index.jsx b/src/components/Anchor/index.jsx index e979988c3..f9f11524b 100644 --- a/src/components/Anchor/index.jsx +++ b/src/components/Anchor/index.jsx @@ -2,7 +2,8 @@ import _ from 'lodash'; import classNames from 'classnames'; import React from 'react'; import PropTypes from 'prop-types'; -import { expandDts, invariant } from '../../utils'; +import { expandDts } from '../../utils'; +import invariant from '../../invariant'; import { buttonSharedClasses, colors, variants, sizes } from '../Button'; const Anchor = (props) => { diff --git a/src/components/Anchor/index.spec.jsx b/src/components/Anchor/index.spec.jsx index 3f28e4354..9820417f9 100644 --- a/src/components/Anchor/index.spec.jsx +++ b/src/components/Anchor/index.spec.jsx @@ -1,80 +1,79 @@ -import _ from 'lodash'; import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; +import invariant from '../../invariant'; import Anchor from './'; -afterEach(cleanup); +jest.mock('../../invariant'); -describe('', () => { - let props = {}; +let props = {}; +beforeEach(() => { + props = { + href: 'www.some.url.com', + onClick: jest.fn().mockImplementation((event) => event.preventDefault()), + }; +}); + +it('should render with default props', () => { + render(); + expect(screen.getByRole('link')).toHaveAttribute('href', 'www.some.url.com'); + expect(screen.getByRole('link')).toHaveClass('aui--anchor aui-default aui-inverse'); +}); + +it('should trigger `props.onClick` when clicking on the component', async () => { + render(); + await user.click(screen.getByRole('link')); + expect(props.onClick).toHaveBeenCalledTimes(1); +}); - beforeEach(() => { - props = { - href: 'www.some.url.com', - onClick: jest.fn(), - }; - }); +it('should throw if using color on link variant', () => { + render( + + Test + + ); - it('should render with default props', () => { - const { getByRole } = render(); - expect(getByRole('link')).toHaveAttribute('href', 'www.some.url.com'); - expect(getByRole('link')).toHaveClass('aui--anchor aui-default aui-inverse'); - }); + expect(invariant).toHaveBeenCalledWith( + false, + 'Anchor: anchors with the "link" variant do not inherit size and color properties.' + ); +}); - it('should trigger `props.onClick` when clicking on the component', () => { - jest.spyOn(console, 'error').mockImplementation(_.noop); - const { getByRole } = render(); - fireEvent.click(getByRole('link')); - expect(props.onClick).toHaveBeenCalledTimes(1); - }); +it('should throw if using size on link variant', () => { + render( + + Test + + ); - it('should throw if using color on link variant', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => - render( - - Test - - ) - ).toThrow('AdslotUI Anchor: anchors with the "link" variant do not inherit size and color properties.'); - }); + expect(invariant).toHaveBeenCalledWith( + false, + 'Anchor: anchors with the "link" variant do not inherit size and color properties.' + ); +}); - it('should throw when round with child or no icon', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => - render( - - Test - - ) - ).toThrow('AdslotUI Anchor: round can only be used with an icon and no children.'); - }); +it('should throw when round with child or no icon', () => { + render( + + Test + + ); + expect(invariant).toHaveBeenCalledWith(false, 'Anchor: round can only be used with an icon and no children.'); +}); - it('should remove href when disabled', () => { - console.error = (err) => { - throw new Error(err); - }; - const { getByTestId } = render(); - expect(getByTestId('anchor-wrapper')).toHaveClass('aui--anchor aui-default disabled'); - }); +it('should remove href when disabled', () => { + render(); + expect(screen.getByTestId('anchor-wrapper')).toHaveClass('aui--anchor aui-default disabled'); +}); - it('should apply round anchor when icon exists and no child', () => { - const { getByTestId } = render( - icon
} /> - ); - expect(getByTestId('anchor-wrapper')).toHaveClass('aui--anchor aui-primary aui-round'); - }); +it('should apply round anchor when icon exists and no child', () => { + render(icon
} />); + expect(screen.getByTestId('anchor-wrapper')).toHaveClass('aui--anchor aui-primary aui-round'); +}); - it('should throw when an aria-label or aria-labelledby is required', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => render(} />)).toThrow( - 'AdslotUI Anchor: an aria-label or aria-labelledby is required on icon anchors.' - ); - }); +it('should throw when an aria-label or aria-labelledby is required', () => { + render(} />); + expect(invariant).toHaveBeenCalledWith( + false, + 'Anchor: an aria-label or aria-labelledby is required on icon anchors.' + ); }); diff --git a/src/components/Avatar/index.spec.jsx b/src/components/Avatar/index.spec.jsx index 8343e11c7..f4b81485d 100644 --- a/src/components/Avatar/index.spec.jsx +++ b/src/components/Avatar/index.spec.jsx @@ -1,61 +1,55 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import Avatar from '.'; -afterEach(cleanup); - -describe('', () => { - it('should render with defaults', () => { - const { getByTestId, queryByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', ' '); - expect(queryByTestId('avatar-image')).not.toBeInTheDocument(); - expect(getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); - expect(getByTestId('avatar-initials')).toHaveTextContent(''); - }); +it('should render with defaults', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', ' '); + expect(screen.queryByTestId('avatar-image')).not.toBeInTheDocument(); + expect(screen.getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); + expect(screen.getByTestId('avatar-initials')).toHaveTextContent(''); +}); - it('should render with names given', () => { - const { getByTestId, queryByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); - expect(queryByTestId('avatar-image')).not.toBeInTheDocument(); - expect(getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); - expect(getByTestId('avatar-initials')).toHaveTextContent('JD'); - }); +it('should render with names given', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); + expect(screen.queryByTestId('avatar-image')).not.toBeInTheDocument(); + expect(screen.getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); + expect(screen.getByTestId('avatar-initials')).toHaveTextContent('JD'); +}); - it('should render with different color', () => { - const { getByTestId, queryByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveClass('avatar-component avatar-component-blue'); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); - expect(queryByTestId('avatar-image')).not.toBeInTheDocument(); - expect(getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); - expect(getByTestId('avatar-initials')).toHaveTextContent('JD'); - }); +it('should render with different color', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveClass('avatar-component avatar-component-blue'); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); + expect(screen.queryByTestId('avatar-image')).not.toBeInTheDocument(); + expect(screen.getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); + expect(screen.getByTestId('avatar-initials')).toHaveTextContent('JD'); +}); - it('should render with avatar', () => { - const { getByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); - expect(getByTestId('avatar-image')).toHaveClass('avatar-component-image'); - expect(getByTestId('avatar-image')).toHaveAttribute('src', '//avatar.com'); - expect(getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); - expect(getByTestId('avatar-initials')).toHaveTextContent('JD'); - }); +it('should render with avatar', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveClass('avatar-component'); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', 'John Doe'); + expect(screen.getByTestId('avatar-image')).toHaveClass('avatar-component-image'); + expect(screen.getByTestId('avatar-image')).toHaveAttribute('src', '//avatar.com'); + expect(screen.getByTestId('avatar-initials')).toHaveClass('avatar-component-initials'); + expect(screen.getByTestId('avatar-initials')).toHaveTextContent('JD'); +}); - it('should render with default title of givenName surname', () => { - const { getByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', 'Firstname Surname'); - }); +it('should render with default title of givenName surname', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', 'Firstname Surname'); +}); - it('should render with custom title property when tooltip with custom text supplied', () => { - const { getByTestId } = render( - - ); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', 'Name of logged-in user'); - }); +it('should render with custom title property when tooltip with custom text supplied', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', 'Name of logged-in user'); +}); - it('should render with empty title property when tooltip with empty text supplied', () => { - const { getByTestId } = render(); - expect(getByTestId('avatar-wrapper')).toHaveAttribute('title', ''); - }); +it('should render with empty title property when tooltip with empty text supplied', () => { + render(); + expect(screen.getByTestId('avatar-wrapper')).toHaveAttribute('title', ''); }); diff --git a/src/components/BorderedWell/index.spec.jsx b/src/components/BorderedWell/index.spec.jsx index b35b72133..7fe1bd3c2 100644 --- a/src/components/BorderedWell/index.spec.jsx +++ b/src/components/BorderedWell/index.spec.jsx @@ -1,26 +1,22 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import BorderedWell from '.'; -afterEach(cleanup); - -describe('', () => { - it('should have its component name as default className', () => { - const { getByTestId } = render(); - expect(getByTestId('borderedwell-wrapper')).toHaveClass('borderedwell-component'); - expect(getByTestId('borderedwell-wrapper')).toBeEmptyDOMElement(); - }); +it('should have its component name as default className', () => { + render(); + expect(screen.getByTestId('borderedwell-wrapper')).toHaveClass('borderedwell-component'); + expect(screen.getByTestId('borderedwell-wrapper')).toBeEmptyDOMElement(); +}); - it('should pass through children', () => { - const children = ( -
- Party town -
- ); - const { getByTestId, queryByTestId } = render({children}); - expect(getByTestId('borderedwell-wrapper')).toHaveClass('borderedwell-component'); - expect(queryByTestId('borderedwell-wrapper')).toBeInTheDocument(); - expect(getByTestId('borderedwell-children')).toHaveClass('test-class'); - expect(getByTestId('borderedwell-children')).toHaveTextContent('Party town'); - }); +it('should pass through children', () => { + const children = ( +
+ Party town +
+ ); + render({children}); + expect(screen.getByTestId('borderedwell-wrapper')).toHaveClass('borderedwell-component'); + expect(screen.getByTestId('borderedwell-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('borderedwell-children')).toHaveClass('test-class'); + expect(screen.getByTestId('borderedwell-children')).toHaveTextContent('Party town'); }); diff --git a/src/components/Breadcrumb/Node/index.spec.jsx b/src/components/Breadcrumb/Node/index.spec.jsx index 2f25c9806..a61a7568d 100644 --- a/src/components/Breadcrumb/Node/index.spec.jsx +++ b/src/components/Breadcrumb/Node/index.spec.jsx @@ -1,45 +1,41 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import BreadcrumbNode from '.'; -afterEach(cleanup); +let node; +let onClick; -describe('', () => { - let node; - let onClick; - - beforeEach(() => { - node = { id: 'a', label: 'Canada' }; - onClick = jest.fn(); - }); +beforeEach(() => { + node = { id: 'a', label: 'Canada' }; + onClick = jest.fn(); +}); - it('should render a link node', () => { - const props = { isLast: false, onClick, node }; - const { getByTestId } = render(); +it('should render a link node', () => { + const props = { isLast: false, onClick, node }; + render(); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node aui--breadcrumb-node-link'); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveTextContent('Canada'); - }); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node aui--breadcrumb-node-link'); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveTextContent('Canada'); +}); - it('should render a last node', () => { - const props = { isLast: true, onClick, node }; - const { getByTestId } = render(); +it('should render a last node', async () => { + const props = { isLast: true, onClick, node }; + render(); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node'); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveTextContent('Canada'); - fireEvent.click(getByTestId('breadcrumb-node-wrapper')); - expect(onClick).toHaveBeenCalledTimes(0); - }); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node'); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveTextContent('Canada'); + await user.click(screen.getByTestId('breadcrumb-node-wrapper')); + expect(onClick).toHaveBeenCalledTimes(0); +}); - it('should trigger onClick when clicking a node', () => { - const props = { isLast: false, onClick: onClick, node }; - const { getByTestId } = render(); +it('should trigger onClick when clicking a node', async () => { + const props = { isLast: false, onClick: onClick, node }; + render(); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node aui--breadcrumb-node-link'); - expect(getByTestId('breadcrumb-node-wrapper')).toHaveTextContent(node.label); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveClass('aui--breadcrumb-node aui--breadcrumb-node-link'); + expect(screen.getByTestId('breadcrumb-node-wrapper')).toHaveTextContent(node.label); - fireEvent.click(getByTestId('breadcrumb-node-wrapper')); - expect(onClick).toHaveBeenCalledTimes(1); - expect(onClick).toHaveBeenCalledWith('a'); - }); + await user.click(screen.getByTestId('breadcrumb-node-wrapper')); + expect(onClick).toHaveBeenCalledTimes(1); + expect(onClick).toHaveBeenCalledWith('a'); }); diff --git a/src/components/Breadcrumb/index.d.ts b/src/components/Breadcrumb/index.d.ts index efe98a2da..e232c6835 100644 --- a/src/components/Breadcrumb/index.d.ts +++ b/src/components/Breadcrumb/index.d.ts @@ -14,7 +14,7 @@ export interface BreadcrumbProps { rootNode?: BreadcrumbRootNode; divider?: React.ReactNode; nodes?: BreadcrumbNodes[]; - onClick?: (...args: any[]) => any; + onClick: (...args: any[]) => any; disabled?: boolean; className?: string; } diff --git a/src/components/Breadcrumb/index.jsx b/src/components/Breadcrumb/index.jsx index 1e696ea91..c7dcd7f14 100644 --- a/src/components/Breadcrumb/index.jsx +++ b/src/components/Breadcrumb/index.jsx @@ -41,7 +41,7 @@ Breadcrumb.propTypes = { label: PropTypes.string.isRequired, }) ), - onClick: PropTypes.func, + onClick: PropTypes.func.isRequired, disabled: PropTypes.bool, className: PropTypes.string, }; @@ -50,9 +50,6 @@ Breadcrumb.defaultProps = { rootNode: { id: 'all', label: 'All' }, divider: '>', nodes: [], - onClick: (newActiveId) => { - throw new Error(`Breadcrumb needs an onClick handler to take ${newActiveId}`); - }, disabled: false, }; diff --git a/src/components/Breadcrumb/index.spec.jsx b/src/components/Breadcrumb/index.spec.jsx index c759b6eb3..b02837516 100644 --- a/src/components/Breadcrumb/index.spec.jsx +++ b/src/components/Breadcrumb/index.spec.jsx @@ -1,81 +1,63 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Breadcrumb from '.'; -afterEach(cleanup); - -describe('', () => { - let nodes; - const onClick = jest.fn(); - beforeEach(() => { - nodes = [ - { id: 'a', label: 'Canada' }, - { id: 'b', label: 'British Columbia' }, - { id: 'c', label: 'Victoria' }, - ]; - }); - - it('should render empty with the component className when no nodes', () => { - const { getByTestId, queryByTestId } = render(); - - expect(getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb'); - expect(getByTestId('breadcrumb-wrapper')).not.toHaveClass('aui--breadcrumb--disabled'); - expect(queryByTestId('breadcrumb-node-wrapper')).not.toBeInTheDocument(); - }); - - it('should render nodes', () => { - const { getByTestId, queryAllByTestId } = render(); +let nodes; +beforeEach(() => { + nodes = [ + { id: 'a', label: 'Canada' }, + { id: 'b', label: 'British Columbia' }, + { id: 'c', label: 'Victoria' }, + ]; +}); - expect(getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb'); - expect(getByTestId('breadcrumb-wrapper')).not.toHaveClass('aui--breadcrumb--disabled'); - expect(queryAllByTestId('breadcrumb-node-wrapper')).toHaveLength(4); - expect(queryAllByTestId('breadcrumb-node-wrapper')[0]).toHaveTextContent('All'); +it('should render empty with the component className when no nodes', () => { + render(); - expect(queryAllByTestId('breadcrumb-node-divider')).toHaveLength(nodes.length); - queryAllByTestId('breadcrumb-node-divider').forEach((node) => - expect(node).toHaveTextContent('/', { normalizeSpaces: false }) - ); + expect(screen.getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb'); + expect(screen.getByTestId('breadcrumb-wrapper')).not.toHaveClass('aui--breadcrumb--disabled'); + expect(screen.queryByTestId('breadcrumb-node-wrapper')).not.toBeInTheDocument(); +}); - queryAllByTestId('breadcrumb-node-wrapper').forEach((node, index) => { - expect(node).toHaveClass('aui--breadcrumb-node'); - if (index === nodes.length) expect(node).not.toHaveClass('aui--breadcrumb-node-link'); - if (index !== nodes.length) expect(node).toHaveClass('aui--breadcrumb-node-link'); - }); - }); +it('should render nodes', () => { + render(); + + expect(screen.getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb'); + expect(screen.getByTestId('breadcrumb-wrapper')).not.toHaveClass('aui--breadcrumb--disabled'); + expect(screen.queryAllByTestId('breadcrumb-node-wrapper')).toHaveLength(4); + expect(screen.queryAllByTestId('breadcrumb-node-wrapper')[0]).toHaveTextContent('All'); + + expect(screen.queryAllByTestId('breadcrumb-node-divider')).toHaveLength(nodes.length); + screen + .queryAllByTestId('breadcrumb-node-divider') + .forEach((node) => expect(node).toHaveTextContent('/', { normalizeSpaces: false })); + + const nodeLinks = screen.queryAllByTestId('breadcrumb-node-wrapper'); + expect(nodeLinks).toHaveLength(4); + expect(nodeLinks[0]).toHaveClass('aui--breadcrumb-node-link'); + expect(nodeLinks[1]).toHaveClass('aui--breadcrumb-node-link'); + expect(nodeLinks[2]).toHaveClass('aui--breadcrumb-node-link'); + expect(nodeLinks[3]).not.toHaveClass('aui--breadcrumb-node-link'); +}); - it('should error when clicking a node with no onClick handler', () => { - const { queryAllByTestId } = render(); - console.error = (err) => { - throw new Error(err); - }; - expect(() => fireEvent.click(queryAllByTestId('breadcrumb-node-wrapper')[0])).toThrow( - 'Breadcrumb needs an onClick handler to take all' - ); - }); +it('should call props.onClick when clicking a node with onClick handler', async () => { + const onClick = jest.fn(); + render(); - it('should call props.onClick when clicking a node with onClick handler', () => { - const props = { onClick, nodes }; - const { queryAllByTestId } = render(); + await user.click(screen.queryAllByTestId('breadcrumb-node-wrapper')[0]); + expect(onClick).toHaveBeenCalledTimes(1); +}); - fireEvent.click(queryAllByTestId('breadcrumb-node-wrapper')[0]); - expect(onClick).toHaveBeenCalledTimes(1); +describe('disabled', () => { + it('should have disabled class', () => { + render(); + expect(screen.getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb--disabled'); }); - describe('disabled', () => { - const props = { - onClick, - nodes, - disabled: true, - }; - - it('should have disabled class', () => { - const { getByTestId } = render(); - expect(getByTestId('breadcrumb-wrapper')).toHaveClass('aui--breadcrumb--disabled'); - }); - it('should not have any breadcrumb node', () => { - const { queryByTestId } = render(); - expect(queryByTestId('breadcrumb-node-wrapper')).not.toBeInTheDocument(); - expect(queryByTestId('breadcrumb-node')).not.toBeInTheDocument(); - }); + it('should not trigger onclick', async () => { + const onClick = jest.fn(); + render(); + await user.click(screen.queryAllByTestId('breadcrumb-node-wrapper')[0]); + expect(onClick).toHaveBeenCalledTimes(0); }); }); diff --git a/src/components/Button/index.jsx b/src/components/Button/index.jsx index 36aa242ac..ebe10967f 100644 --- a/src/components/Button/index.jsx +++ b/src/components/Button/index.jsx @@ -3,7 +3,8 @@ import classNames from 'classnames'; import React from 'react'; import PropTypes from 'prop-types'; import Spinner from '../Spinner'; -import { expandDts, invariant } from '../../utils'; +import { expandDts } from '../../utils'; +import invariant from '../../invariant'; import './styles.css'; export const buttonSharedClasses = ({ size, inverse, variant, fullWidth, round, icon, children, disabled, color }) => ({ @@ -51,7 +52,7 @@ const Button = (props) => { invariant( !(isLink && (color !== 'default' || size === 'large')), - `Button: buttons with the "link" variant do not inherit size and color properties.${isLink} ${color} ${size}` + `Button: buttons with the "link" variant do not inherit size and color properties.` ); const baseClass = 'aui--button'; diff --git a/src/components/Button/index.spec.jsx b/src/components/Button/index.spec.jsx index 09f4ecad7..c3b13edc5 100644 --- a/src/components/Button/index.spec.jsx +++ b/src/components/Button/index.spec.jsx @@ -1,114 +1,109 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen, within } from 'testing'; import Button from './'; +import invariant from '../../invariant'; -afterEach(cleanup); - -describe('); - expect(queryByTestId('button-wrapper')).toBeInTheDocument(); - }); - - it('should support className prop', () => { - const { getByTestId } = render(); - expect(getByTestId('button-wrapper')).toHaveClass('aui--button all the-classes'); - }); - - it('should support valid html attributes', () => { - const { getByTestId } = render(); - - expect(getByTestId('button-wrapper')).toHaveAttribute('id', 'button-id'); - }); - - it('should render inverse button with inverse variant', () => { - const { getByTestId } = render(); - expect(getByTestId('button-wrapper')).toHaveClass('aui--button aui-inverse aui-default'); - }); - - it('should render large button with size="large" prop', () => { - const { getByTestId } = render(); - expect(getByTestId('button-wrapper')).toHaveClass('aui--button aui-large aui-default aui-inverse'); - }); - - it('should throw if using color on link variant', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => - render( - - ) - ).toThrow('AdslotUI Button: buttons with the "link" variant do not inherit size and color properties.'); - }); - - it('should throw when round with child or no icon', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => render()).toThrow( - 'AdslotUI Button: round can only be used with an icon and no children.' - ); - }); - - it('should apply round button when icon exists and no child', () => { - const { getByTestId } = render(
} />); - expect(getByTestId('button-wrapper')).toHaveClass('aui--button aui-primary aui-round'); - }); - - it('should throw when an aria-label is required', () => { - console.error = (err) => { - throw new Error(err); - }; - expect(() => render()).toThrow( - 'AdslotUI Button: The theme prop has been deprecated. Please use color instead.' - ); - expect(() => render()).toThrow( - 'AdslotUI Button: The inverse prop has been deprecated. Please use variant="inverse" instead.' - ); - }); - - it('should apply icon', () => { - const { getByTestId } = render(
}>Test); - expect(getByTestId('icon-content').parentElement).toHaveClass('aui-icon-container'); - expect(getByTestId('button-wrapper')).toHaveClass('aui--button aui-default aui-inverse'); - }); - - it('should apply loading class to non-round icon container', () => { - const { getByTestId } = render( -
} /> - ); - expect(getByTestId('icon-content').parentElement).toHaveClass('aui-icon-container is-loading'); - }); - - it('should support data-test-selectors', () => { - const { getByTestId } = render(); - expect(getByTestId('button-wrapper')).toHaveAttribute('data-test-selector', 'test-button'); - }); - - it('should render disabled button', () => { - const { getByTestId } = render(); - expect(getByTestId('button-wrapper')).toBeDisabled(); - }); - - it('should render Spinner if isLoading is true', () => { - const { queryByTestId } = render(); + expect(screen.getByTestId('button-wrapper')).toBeInTheDocument(); +}); + +it('should support className prop', () => { + render(); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui--button all the-classes'); +}); + +it('should support valid html attributes', () => { + render(); + + expect(screen.getByTestId('button-wrapper')).toHaveAttribute('id', 'button-id'); +}); + +it('should render inverse button with inverse variant', () => { + render(); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui--button aui-inverse aui-default'); +}); + +it('should render large button with size="large" prop', () => { + render(); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui--button aui-large aui-default aui-inverse'); +}); + +it('should throw if using color on link variant', () => { + render( + + ); + expect(invariant).toHaveBeenCalledWith( + false, + 'Button: buttons with the "link" variant do not inherit size and color properties.' + ); +}); + +it('should throw when round with child or no icon', () => { + render(); + expect(invariant).toHaveBeenCalledWith(false, 'Button: round can only be used with an icon and no children.'); +}); + +it('should apply round button when icon exists and no child', () => { + render(
} />); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui--button aui-primary aui-round'); +}); + +it('should throw when an aria-label is required', () => { + render(); + expect(invariant).toHaveBeenCalledWith( + false, + 'Button: The theme prop has been deprecated. Please use color instead.' + ); +}); + +it('should throw for deprecated inverse props', () => { + render(); + expect(invariant).toHaveBeenCalledWith( + false, + 'Button: The inverse prop has been deprecated. Please use variant="inverse" instead.' + ); +}); + +it('should apply icon', () => { + render(
}>Test); + expect(within(screen.getByClass('aui-icon-container')).getByTestId('icon-content')).toBeInTheDocument(); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui--button aui-default aui-inverse'); +}); + +it('should apply loading class to non-round icon container', () => { + render(
} />); + expect(screen.getByTestId('icon-content').parentElement).toHaveClass('aui-icon-container is-loading'); +}); + +it('should support data-test-selectors', () => { + render(); + expect(screen.getByTestId('button-wrapper')).toHaveAttribute('data-test-selector', 'test-button'); +}); + +it('should render disabled button', () => { + render(); + expect(screen.getByTestId('button-wrapper')).toBeDisabled(); +}); + +it('should render Spinner if isLoading is true', () => { + render( + + + ); + expect(screen.getByTestId('button-group-wrapper')).toBeInTheDocument(); +}); -describe('', () => { - it('should render Button Group', () => { - const { queryByTestId } = render( - - - - - ); - expect(queryByTestId('button-group-wrapper')).toBeInTheDocument(); - }); +it('should override child Button style', () => { + render( + + + + + ); + expect(screen.queryAllByTestId('button-wrapper')[0]).toHaveClass('aui-borderless aui-success'); + expect(screen.queryAllByTestId('button-wrapper')[1]).toHaveClass('aui-borderless aui-success'); +}); - it('should override child Button style', () => { - const { queryAllByTestId } = render( - - - - - ); - expect(queryAllByTestId('button-wrapper')[0]).toHaveClass('aui-borderless aui-success'); - expect(queryAllByTestId('button-wrapper')[1]).toHaveClass('aui-borderless aui-success'); - }); +it('should disable child buttons', () => { + render( + + + + + ); + expect(screen.queryAllByTestId('button-wrapper')[0]).toBeDisabled(); + expect(screen.queryAllByTestId('button-wrapper')[1]).toBeDisabled(); +}); - it('should disable child buttons', () => { - const { queryAllByTestId } = render( - +it('should inject props to Button at any nested level', () => { + render( + +
+
foo
- - - ); - expect(queryAllByTestId('button-wrapper')[0]).toBeDisabled(); - expect(queryAllByTestId('button-wrapper')[1]).toBeDisabled(); - }); - - it('should inject props to Button at any nested level', () => { - const { getByTestId } = render( - -
-
foo
- -
-
- ); - expect(getByTestId('button-wrapper')).toBeDisabled(); - expect(getByTestId('button-wrapper')).toHaveClass('aui-large'); - }); +
+
+ ); + expect(screen.getByTestId('button-wrapper')).toBeDisabled(); + expect(screen.getByTestId('button-wrapper')).toHaveClass('aui-large'); +}); - it('should not crash when child is null', () => { - const { queryByTestId } = render( - -
- {null} - - ); - expect(queryByTestId('button-group-wrapper')).toBeInTheDocument(); - }); +it('should not crash when child is null', () => { + render( + +
+ {null} + + ); + expect(screen.getByTestId('button-group-wrapper')).toBeInTheDocument(); }); diff --git a/src/components/Card/index.spec.jsx b/src/components/Card/index.spec.jsx index 4ccb0c585..936e6b709 100644 --- a/src/components/Card/index.spec.jsx +++ b/src/components/Card/index.spec.jsx @@ -1,9 +1,7 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import Card from '.'; -afterEach(cleanup); - describe('', () => { it('should render and pass through children', () => { const children = ( @@ -11,41 +9,44 @@ describe('', () => { Test Text
); - const { getByTestId, queryByTestId } = render({children}); + render({children}); - expect(getByTestId('card-container-wrapper')).toHaveClass('card-component'); - expect(queryByTestId('card-container-wrapper')).toBeInTheDocument(); - expect(getByTestId('card-container-test-children')).toHaveClass('test-class'); - expect(getByTestId('card-container-test-children')).toHaveTextContent('Test Text'); + expect(screen.getByTestId('card-container-wrapper')).toHaveClass('card-component'); + expect(screen.getByTestId('card-container-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('card-container-test-children')).toHaveClass('test-class'); + expect(screen.getByTestId('card-container-test-children')).toHaveTextContent('Test Text'); }); it('should render with classNames', () => { - const { getByTestId, queryByTestId } = render(Test Text); - expect(getByTestId('card-container-wrapper')).toHaveClass('card-component red blue'); - expect(queryByTestId('card-container-wrapper')).toBeInTheDocument(); + render(Test Text); + expect(screen.getByTestId('card-container-wrapper')).toHaveClass('card-component red blue'); + expect(screen.getByTestId('card-container-wrapper')).toBeInTheDocument(); }); it('should render with accent', () => { - const { getByTestId } = render(Test Text); - expect(getByTestId('card-container-wrapper')).toHaveClass('card-component accent accent-foo'); + render(Test Text); + expect(screen.getByTestId('card-container-wrapper')).toHaveClass('card-component accent accent-foo'); }); it('should render with appended and nested children', () => { - const { getByTestId, queryByText, queryAllByTestId } = render( + render( Nested Appended ); - expect(queryAllByTestId('card-content-wrapper')).toHaveLength(2); // Should have two card contents - expect(getByTestId('card-content-container-wrapper')).toHaveTextContent('Nested'); - expect(getByTestId('card-container-wrapper')).toContainElement(queryByText(/Appended/i)); + expect(screen.queryAllByTestId('card-content-wrapper')).toHaveLength(2); // Should have two card contents + expect(screen.getByTestId('card-content-container-wrapper')).toHaveTextContent('Nested'); + expect(screen.getByTestId('card-container-wrapper')).toContainElement(screen.queryByText(/Appended/i)); }); it('should apply data-test-selector', () => { - const { getByTestId } = render(Test); - expect(getByTestId('card-container-wrapper')).toHaveAttribute('data-test-selector', 'card-component-container'); + render(Test); + expect(screen.getByTestId('card-container-wrapper')).toHaveAttribute( + 'data-test-selector', + 'card-component-container' + ); }); }); @@ -57,44 +58,44 @@ describe('', () => {
); - const { getByTestId, queryByTestId } = render({children}); + render({children}); - expect(getByTestId('card-content-wrapper')).toHaveClass('card-component-content'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); - expect(getByTestId('card-content-test-children')).toHaveClass('test-class'); - expect(getByTestId('card-content-test-children')).toHaveTextContent('Test Text'); + expect(screen.getByTestId('card-content-wrapper')).toHaveClass('card-component-content'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('card-content-test-children')).toHaveClass('test-class'); + expect(screen.getByTestId('card-content-test-children')).toHaveTextContent('Test Text'); }); it('should render with "stretch" class', () => { - const { getByTestId, queryByTestId } = render(Test Text); - expect(getByTestId('card-content-wrapper')).toHaveClass('card-component-content stretch'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); + render(Test Text); + expect(screen.getByTestId('card-content-wrapper')).toHaveClass('card-component-content stretch'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); }); it('should render with "fill" class', () => { - const { getByTestId, queryByTestId } = render(Test Text); - expect(getByTestId('card-content-wrapper')).toHaveClass('card-component-content fill'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); + render(Test Text); + expect(screen.getByTestId('card-content-wrapper')).toHaveClass('card-component-content fill'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); }); it('should render with appended content', () => { - const { getByTestId, queryByTestId } = render(Test Text); - expect(getByTestId('card-content-wrapper')).toHaveClass('card-component-content append'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); + render(Test Text); + expect(screen.getByTestId('card-content-wrapper')).toHaveClass('card-component-content append'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); }); it('should render with custom classNames', () => { - const { getByTestId, queryByTestId } = render( + render( Test Text ); - expect(getByTestId('card-content-wrapper')).toHaveClass('card-component-content fill some classes'); - expect(queryByTestId('card-content-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('card-content-wrapper')).toHaveClass('card-component-content fill some classes'); + expect(screen.getByTestId('card-content-wrapper')).toBeInTheDocument(); }); it('should apply data-test-selector', () => { - const { getByTestId } = render(Test); - expect(getByTestId('card-content-wrapper')).toHaveAttribute('data-test-selector', 'card-component-content'); + render(Test); + expect(screen.getByTestId('card-content-wrapper')).toHaveAttribute('data-test-selector', 'card-component-content'); }); }); diff --git a/src/components/Carousel/index.spec.jsx b/src/components/Carousel/index.spec.jsx index 7b80b7899..0d4b2e630 100644 --- a/src/components/Carousel/index.spec.jsx +++ b/src/components/Carousel/index.spec.jsx @@ -1,135 +1,121 @@ import _ from 'lodash'; import React from 'react'; -import { render, cleanup, fireEvent, queryByAttribute, queryAllByAttribute } from '@testing-library/react'; +import { render, screen, within, user } from 'testing'; import Carousel from '.'; -afterEach(cleanup); - -const getByDataIndex = queryByAttribute.bind(null, 'data-index'); -const getById = queryByAttribute.bind(null, 'id'); -const queryAllByClass = queryAllByAttribute.bind(null, 'class'); - const CarouselHookTest = React.forwardRef(({ onClick }, ref) => { const props = Carousel.usePreventSwipeClicks(); return ( {_.map(new Array(5), (_value, index) => ( - ))} ); }); -describe('', () => { - it('should render with defaults', () => { - const { container } = render(); - expect(container.firstChild).toHaveClass('aui--carousel-component'); - expect(container).toHaveTextContent(''); - }); +it('should render with defaults', () => { + render(); + expect(screen.getByClass('aui--carousel-component')).toBeInTheDocument(); +}); - it('should render with slides', () => { - const { getAllByTestId, container } = render( - - 1 - 2 - - ); - getAllByTestId('carousel-image-wrapper').forEach((each) => expect(container).toContainElement(each)); - getAllByTestId('carousel-image-wrapper').forEach((each, index) => - expect(each).toHaveAttribute('src', `path/to/image-${index + 1}.jpg`) - ); +it('should render with slides', () => { + render( + + 1 + 2 + + ); + screen.getAllByTestId('carousel-image-wrapper').forEach((each) => { + expect(each).toBeInTheDocument(); }); - - it('should be able to navigate to the next image', () => { - const { container, getByText } = render( - - {_.map(new Array(5), (_value, index) => ( - {index} - ))} - - ); - - expect(getByText('Next')).toHaveClass('slick-next'); - expect(getByDataIndex(container, '0')).toHaveClass('slick-active'); - expect(getById(getByDataIndex(container, '0'), 'img-0')).toBeTruthy(); - - fireEvent.click(getByText('Next')); - expect(getByDataIndex(container, '1')).toHaveClass('slick-active'); - expect(getById(getByDataIndex(container, '1'), 'img-1')).toBeTruthy(); + screen.getAllByTestId('carousel-image-wrapper').forEach((each, index) => { + expect(each).toHaveAttribute('src', `path/to/image-${index + 1}.jpg`); }); +}); - it('should be able to navigate to the previous image', () => { - const { container, getByText } = render( - - {_.map(new Array(5), (_value, index) => ( - {index} - ))} - - ); - - expect(getByText('Previous')).toHaveClass('slick-prev'); - expect(getByDataIndex(container, '0')).toHaveClass('slick-active'); - expect(getById(getByDataIndex(container, '0'), 'img-0')).toBeTruthy(); - - fireEvent.click(getByText('Previous')); - expect(getByDataIndex(container, '4')).toHaveClass('slick-active'); - expect(getById(getByDataIndex(container, '-1'), 'img-4')).toBeTruthy(); - }); +it('should be able to navigate to the next image', async () => { + render( + + {_.map(new Array(5), (_value, index) => ( + {index} + ))} + + ); - it('should display dots', () => { - const { container } = render( - - {_.map(new Array(5), (_value, index) => ( - {index} - ))} - - ); - expect(queryAllByClass(container, 'slick-dots')).toHaveLength(1); - }); + expect(screen.getByText('Next')).toHaveClass('slick-next'); + expect(within(screen.getByClass('slick-slide slick-active')).getByTestId('img-0')).toBeInTheDocument(); - it('should change slide when dots are clicked', () => { - const { container, getByText } = render( - - {_.map(new Array(5), (_value, index) => ( - {index} - ))} - - ); - - fireEvent.click(getByText('3')); - expect(getByDataIndex(container, '2')).toHaveClass('slick-current'); - expect(getById(getByDataIndex(container, '3'), 'img-3')).toBeTruthy(); - }); + await user.click(screen.getByText('Next')); + expect(within(screen.getByClass('slick-slide slick-active')).getByTestId('img-1')).toBeInTheDocument(); +}); - it('should not fire click events when swiping with usePreventSwipeClicks', () => { - const onClick = jest.fn(); - const ref = { current: false }; - const { container } = render(); +it('should be able to navigate to the previous image', async () => { + render( + + {_.map(new Array(5), (_value, index) => ( + {index} + ))} + + ); - fireEvent.mouseDown(getById(getByDataIndex(container, '1'), 'btn-1'), { - clientX: 0, - clientY: 0, - }); + expect(screen.getByText('Previous')).toHaveClass('slick-prev'); + expect(within(screen.getByClass('slick-slide slick-active')).getByTestId('img-0')).toBeInTheDocument(); - fireEvent.click(getById(getByDataIndex(container, '1'), 'btn-1'), { - clientX: 100, - clientY: 0, - }); + await user.click(screen.getByText('Previous')); + expect(within(screen.getByClass('slick-slide slick-active')).getByTestId('img-4')).toBeInTheDocument(); +}); - expect(onClick).toHaveBeenCalledTimes(0); +it('should display dots', () => { + render( + + {_.map(new Array(5), (_value, index) => ( + {index} + ))} + + ); + expect(screen.queryAllByClass('slick-dots')).toHaveLength(1); +}); - fireEvent.mouseDown(getById(getByDataIndex(container, '1'), 'btn-1'), { - clientX: 0, - clientY: 0, - }); +it('should change slide when dots are clicked', async () => { + render( + + {_.map(new Array(5), (_value, index) => ( + {index} + ))} + + ); - fireEvent.click(getById(getByDataIndex(container, '1'), 'btn-1'), { - clientX: 3, - clientY: 0, - }); + await user.click(screen.getByText('3')); + expect(within(screen.getByClass('slick-slide slick-active')).getByTestId('img-2')).toBeInTheDocument(); +}); - expect(onClick).toHaveBeenCalledTimes(1); - }); +it('should not fire click events when swiping with usePreventSwipeClicks', async () => { + const onClick = jest.fn(); + const ref = { current: false }; + render(); + + await user.pointer([ + { + keys: '[MouseLeft>]', + target: screen.getAllByTestId('btn-1')[0], + coords: { clientX: 10, clientY: 20 }, + }, + { + target: screen.getAllByTestId('btn-1')[0], + coords: { clientX: 17, clientY: 20 }, + }, + { + keys: '[/MouseLeft]', + coords: { clientX: 19, clientY: 20 }, + }, + ]); + + expect(onClick).toHaveBeenCalledTimes(0); + + await user.pointer([{ keys: '[MouseLeft]', target: screen.getAllByTestId('btn-1')[0] }]); + + expect(onClick).toHaveBeenCalledTimes(1); }); diff --git a/src/components/Checkbox/index.jsx b/src/components/Checkbox/index.jsx index 0ead31813..231d9d289 100644 --- a/src/components/Checkbox/index.jsx +++ b/src/components/Checkbox/index.jsx @@ -1,7 +1,8 @@ import React from 'react'; import classnames from 'classnames'; import PropTypes from 'prop-types'; -import { expandDts, invariant } from '../../utils'; +import { expandDts } from '../../utils'; +import invariant from '../../invariant'; import './styles.css'; const SELECTION_KEYS = ['Enter', ' ']; diff --git a/src/components/Checkbox/index.spec.jsx b/src/components/Checkbox/index.spec.jsx index e598e400e..41e301f9c 100644 --- a/src/components/Checkbox/index.spec.jsx +++ b/src/components/Checkbox/index.spec.jsx @@ -1,59 +1,55 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Checkbox from '.'; -afterEach(cleanup); - -describe('', () => { - it('should render with props', () => { - const { getByTestId, queryByTestId } = render( -
- - - ); - expect(queryByTestId('checkbox-input')).toBeInTheDocument(); - expect(getByTestId('checkbox-input')).toBeChecked(); - expect(getByTestId('checkbox-input')).toHaveAttribute('name', 'movies'); - expect(getByTestId('checkbox')).toHaveAttribute('data-test-selector', 'checkbox-terminator'); - expect(getByTestId('checkbox-label')).toHaveTextContent('The Terminator'); - }); +it('should render with props', () => { + render( +
+ + + ); + expect(screen.getByTestId('checkbox-input')).toBeInTheDocument(); + expect(screen.getByTestId('checkbox-input')).toBeChecked(); + expect(screen.getByTestId('checkbox-input')).toHaveAttribute('name', 'movies'); + expect(screen.getByTestId('checkbox')).toHaveAttribute('data-test-selector', 'checkbox-terminator'); + expect(screen.getByTestId('checkbox-label')).toHaveTextContent('The Terminator'); +}); - it('should render with just label', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('checkbox-input')).toBeInTheDocument(); - expect(getByTestId('checkbox-label')).toHaveTextContent('Label goes here'); - }); +it('should render with just label', () => { + render(); + expect(screen.getByTestId('checkbox-input')).toBeInTheDocument(); + expect(screen.getByTestId('checkbox-label')).toHaveTextContent('Label goes here'); +}); - it('should render with id, className', () => { - const { getByTestId } = render(); - expect(getByTestId('checkbox')).toHaveClass('checkboxClass'); - expect(getByTestId('checkbox-input')).toHaveAttribute('id', 'checkboxId'); - }); +it('should render with id, className', () => { + render(); + expect(screen.getByTestId('checkbox')).toHaveClass('checkboxClass'); + expect(screen.getByTestId('checkbox-input')).toHaveAttribute('id', 'checkboxId'); +}); - it('should render without a label', () => { - const { queryByTestId } = render(); - expect(queryByTestId('checkbox-label')).not.toBeInTheDocument(); - }); +it('should render without a label', () => { + render(); + expect(screen.queryByTestId('checkbox-label')).not.toBeInTheDocument(); +}); - it('should be disabled when "disable" prop is true', () => { - const { getByTestId, rerender } = render(); - expect(getByTestId('checkbox')).not.toHaveClass('disabled'); - rerender(); - expect(getByTestId('checkbox')).toHaveClass('disabled'); - }); +it('should be disabled when "disable" prop is true', () => { + const view = render(); + expect(screen.getByTestId('checkbox')).not.toHaveClass('disabled'); + view.rerender(); + expect(screen.getByTestId('checkbox')).toHaveClass('disabled'); +}); - it('should pass next state value to the onChange function', () => { - const handleChange = jest.fn(); - const { getByTestId, rerender } = render(); - fireEvent.click(getByTestId('checkbox-input')); - expect(handleChange).toHaveBeenCalledWith(true, 'name', 'value'); - rerender(); - fireEvent.click(getByTestId('checkbox-input')); - expect(handleChange).toHaveBeenCalledTimes(2); - expect(handleChange).toHaveBeenCalledWith(false, 'name', 'value'); - rerender(); - fireEvent.click(getByTestId('checkbox-input')); - expect(handleChange).toHaveBeenCalledTimes(3); - expect(handleChange).toHaveBeenCalledWith(false, 'name', 'value'); - }); +it('should pass next state value to the onChange function', async () => { + const handleChange = jest.fn(); + const view = render(); + await user.click(screen.getByTestId('checkbox-input')); + expect(handleChange).toHaveBeenCalledWith(true, 'name', 'value'); + view.rerender(); + await user.click(screen.getByTestId('checkbox-input')); + expect(handleChange).toHaveBeenCalledTimes(2); + expect(handleChange).toHaveBeenCalledWith(false, 'name', 'value'); + view.rerender(); + await user.click(screen.getByTestId('checkbox-input')); + expect(handleChange).toHaveBeenCalledTimes(3); + expect(handleChange).toHaveBeenCalledWith(false, 'name', 'value'); }); diff --git a/src/components/CheckboxGroup/index.jsx b/src/components/CheckboxGroup/index.jsx index cb5e26167..a2fd33df3 100644 --- a/src/components/CheckboxGroup/index.jsx +++ b/src/components/CheckboxGroup/index.jsx @@ -2,7 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import _ from 'lodash'; -import { expandDts, invariant } from '../../utils'; +import { expandDts } from '../../utils'; +import invariant from '../../invariant'; import Checkbox, { shareCheckboxPropTypes } from '../Checkbox'; import CheckboxGroupProvider, { useCheckboxGroup } from './CheckboxGroupContext'; import '../RadioGroup/style.css'; diff --git a/src/components/CheckboxGroup/index.spec.jsx b/src/components/CheckboxGroup/index.spec.jsx index 0e5e2c363..ad60b4572 100644 --- a/src/components/CheckboxGroup/index.spec.jsx +++ b/src/components/CheckboxGroup/index.spec.jsx @@ -1,345 +1,340 @@ import React from 'react'; -import { render, cleanup, fireEvent, queryByAttribute, getByTestId as getByTestIdGlobal } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render, screen, within, user } from 'testing'; import CheckboxGroup from '.'; +import invariant from '../../invariant'; + +jest.mock('../../invariant'); + +let props; +beforeEach(() => { + props = { + name: 'checkbox-group-name', + dts: 'checkbox-group-dts', + id: 'checkbox-group-id', + className: 'checkbox-class', + value: 'checkbox-value-1', + onChange: jest.fn(), + }; +}); -afterEach(cleanup); -const getByDts = queryByAttribute.bind(null, 'data-test-selector'); - -describe('', () => { - let props; - - beforeEach(() => { - props = { - name: 'checkbox-group-name', - dts: 'checkbox-group-dts', - id: 'checkbox-group-id', - className: 'checkbox-class', - value: 'checkbox-value-1', - onChange: jest.fn(), - }; - }); - - it('should trigger `props.onChange` when the checkbox is clicked', () => { - const { getAllByTestId } = render( - - - - - ); - fireEvent.click(getAllByTestId('checkbox-input')[1]); - expect(props.onChange).toHaveBeenCalledTimes(1); - }); - - it('should use getIsChecked function', () => { - const getIsCheckedMock = jest.fn(); - const { getAllByTestId } = render( - - - - - - ); +it('should trigger `props.onChange` when the checkbox is clicked', async () => { + render( + + + + + ); + await user.click(screen.getAllByTestId('checkbox-input')[1]); + expect(props.onChange).toHaveBeenCalledTimes(1); +}); - fireEvent.click(getAllByTestId('checkbox-input')[1]); - expect(getIsCheckedMock).toHaveBeenCalled(); - }); - - it('should work for partial checkbox state', () => { - const mockoOnChange = jest.fn(); - - const getIsChecked = (v) => { - return v === 'checkbox-value-2' ? 'partial' : false; - }; - - const { container } = render( - - - - - - - ); - expect(getByDts(container, 'test-p')).toBePartiallyChecked(); +it('should use getIsChecked function', async () => { + const getIsCheckedMock = jest.fn(); + render( + + + + + + ); + + await user.click(screen.getAllByTestId('checkbox-input')[1]); + expect(getIsCheckedMock).toHaveBeenCalled(); +}); - const checkbox2 = getByDts(container, 'test-2'); +it('should work for partial checkbox state', async () => { + const mockOnChange = jest.fn(); + const getIsChecked = (v) => { + return v === 'checkbox-value-2' ? 'partial' : false; + }; + + render( + + + + + + + ); + expect(screen.getByDts('test-p')).toBePartiallyChecked(); + + const checkbox2 = screen.getByDts('test-2'); + + checkbox2.focus(); + expect(checkbox2).toBePartiallyChecked(); + await user.keyboard('[Enter]'); + + expect(mockOnChange).toHaveBeenCalledTimes(1); + expect(mockOnChange).toHaveBeenCalledWith( + ['checkbox-value-1', 'checkbox-value-2'], + 'checkbox-group-name', + 'checkbox-value-2' + ); +}); - checkbox2.focus(); - expect(checkbox2).toBePartiallyChecked(); - userEvent.keyboard('[Enter]'); +it('should trigger onChange with checkbox type', async () => { + render( + + + + + + ); + const checkbox1 = screen.getByDts('test-1'); + await user.tab(); + expect(checkbox1).toHaveFocus(); + expect(checkbox1).toBeChecked(); + await user.tab(); + await user.keyboard('[Enter]'); + expect(props.onChange).toHaveBeenCalledTimes(1); +}); - expect(mockoOnChange).toHaveBeenCalledTimes(1); - expect(mockoOnChange).toHaveBeenCalledWith( - ['checkbox-value-1', 'checkbox-value-2'], - 'checkbox-group-name', - 'checkbox-value-2' - ); - }); - - it('should trigger onChange with checkbox type', () => { - const { container } = render( - - - - - - ); - const checkbox1 = getByDts(container, 'test-1'); - userEvent.tab(); - expect(checkbox1).toHaveFocus(); - expect(checkbox1).toBeChecked(); - userEvent.tab(); - userEvent.keyboard('[Enter]'); - expect(props.onChange).toHaveBeenCalledTimes(1); - }); - - it('should render checkbox group with props', () => { - const { container, getAllByTestId } = render( - - - - - ); - expect(getByDts(container, 'test-1')).toHaveTextContent('Checkbox 1'); - expect(getByDts(container, 'test-2')).toHaveTextContent('Checkbox 2'); - - expect(getAllByTestId('checkbox-input')[0]).toHaveAttribute('type', 'checkbox'); - expect(getAllByTestId('checkbox-input')[0]).toHaveAttribute('name', 'checkbox-group-name'); - expect(getAllByTestId('checkbox-input')[0]).toBeChecked(); - }); - - it('should render with props', () => { - const { getByTestId, queryAllByTestId } = render( - - - - - - ); +it('should render checkbox group with props', () => { + render( + + + + + ); + expect(screen.getByDts('test-1')).toHaveTextContent('Checkbox 1'); + expect(screen.getByDts('test-2')).toHaveTextContent('Checkbox 2'); + + expect(screen.getAllByTestId('checkbox-input')[0]).toHaveAttribute('type', 'checkbox'); + expect(screen.getAllByTestId('checkbox-input')[0]).toHaveAttribute('name', 'checkbox-group-name'); + expect(screen.getAllByTestId('checkbox-input')[0]).toBeChecked(); +}); - expect(getByTestId('checkbox-group')).toHaveClass('custom-class'); - expect(queryAllByTestId('checkbox')).toHaveLength(3); - }); - - it('should render checkbox with icons and text', () => { - const { getByText } = render( - - - - - ); - expect(getByText('text description')).toBeInTheDocument(); - expect(getByText('Icon')).toBeInTheDocument(); - }); - - it('should override checkbox items prop', () => { - jest.spyOn(console, 'error').mockReturnValue(); - expect(() => - render( - - - - ) - ).toThrow('AdslotUI CheckboxGroup.Item: variant will be overridden by CheckboxGroup variant'); - }); - - it('should handle checkbox change events when adding selection', () => { - const onChangeGroup = jest.fn(); - const { queryAllByTestId } = render( - - - - - - ); +it('should render with props', () => { + render( + + + + + + ); + + expect(screen.getByTestId('checkbox-group')).toHaveClass('custom-class'); + expect(screen.getAllByTestId('checkbox')).toHaveLength(3); +}); - fireEvent.click(queryAllByTestId('checkbox-input')[0]); - expect(onChangeGroup).toHaveBeenCalledTimes(1); - expect(onChangeGroup).toHaveBeenCalledWith(['predator'], 'movies', 'terminator'); - }); - - it('should handle checkbox change events when removing selection', () => { - const onChangeGroup = jest.fn(); - const { queryAllByTestId } = render( - - - - - - ); +it('should render checkbox with icons and text', () => { + render( + + + + + ); + expect(screen.getByText('text description')).toBeInTheDocument(); + expect(screen.getByText('Icon')).toBeInTheDocument(); +}); - fireEvent.click(queryAllByTestId('checkbox-input')[2]); - expect(onChangeGroup).toHaveBeenCalledTimes(1); - expect(onChangeGroup).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies', 'soundofmusic'); - }); - - it('should return null if there is a boolean child', () => { - console.error = jest.fn(); - const { queryByTestId } = render( - - {false && } - - - ); +it('should override checkbox items prop', () => { + render( + + + + ); + + expect(invariant).toHaveBeenCalledWith( + false, + 'CheckboxGroup.Item: variant will be overridden by CheckboxGroup variant' + ); +}); - expect(queryByTestId('checkbox-group')).toBeInTheDocument(); - expect(console.error).toHaveBeenCalledTimes(0); - }); - - it('should be able to check all options when none is checked', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - - - ); +it('should handle checkbox change events when adding selection', async () => { + const onChangeGroup = jest.fn(); + render( + + + + + + ); + + await user.click(screen.getAllByTestId('checkbox-input')[0]); + expect(onChangeGroup).toHaveBeenCalledTimes(1); + expect(onChangeGroup).toHaveBeenCalledWith(['predator'], 'movies', 'terminator'); +}); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies'); - }); - - it('should be able to uncheck all options when all are checked', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - - - ); +it('should handle checkbox change events when removing selection', async () => { + const onChangeGroup = jest.fn(); + render( + + + + + + ); + + await user.click(screen.getAllByTestId('checkbox-input')[2]); + expect(onChangeGroup).toHaveBeenCalledTimes(1); + expect(onChangeGroup).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies', 'soundofmusic'); +}); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith([], 'movies'); - }); - - it('should be able to uncheck all options when some is checked', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - - - ); +it('should return null if there is a boolean child', () => { + render( + + {false && } + + + ); + + expect(screen.getByTestId('checkbox-group')).toBeInTheDocument(); +}); + +it('should be able to check all options when none is checked', async () => { + const onChange = jest.fn(); + render( + + + + + + + ); + + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + await user.click(checkbox); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies'); +}); + +it('should be able to uncheck all options when all are checked', async () => { + const onChange = jest.fn(); + render( + + + + + + + ); + + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + await user.click(checkbox); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith([], 'movies'); +}); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies'); - }); - - it('should work with nested checkbox group', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - - - - - +it('should be able to uncheck all options when some is checked', async () => { + const onChange = jest.fn(); + render( + + + + + + + ); + + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + await user.click(checkbox); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(['terminator', 'predator', 'soundofmusic'], 'movies'); +}); + +it('should work with nested checkbox group', async () => { + const onChange = jest.fn(); + render( + + + + + + + + - ); + + ); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith(['Lung Cancer Late'], 'movies', 'Lung Cancer Late'); - }); - - it('should be able to select nested all', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - - - - - - + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + await user.click(checkbox); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(['Lung Cancer Late'], 'movies', 'Lung Cancer Late'); +}); + +it('should be able to select nested all', async () => { + const onChange = jest.fn(); + render( + + + + + + + + + - ); + + ); + + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + await user.click(checkbox); + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(['Lung Cancer Late', 'Lung Cancer Early'], 'movies'); +}); + +it('should work when there is an initial value', async () => { + const onChange = jest.fn(); + render( + + + + + + + ); + + const checkbox = within(screen.getByDts('target')).getByTestId('checkbox-input'); + expect(checkbox.checked).toBe(true); +}); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - fireEvent.click(checkbox); - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange).toHaveBeenCalledWith(['Lung Cancer Late', 'Lung Cancer Early'], 'movies'); - }); - - it('should work when there is an initial value', () => { - const onChange = jest.fn(); - const { container } = render( - - - - - +it('should work when the values are updated', async () => { + const Component = () => { + const [value, setValue] = React.useState([]); + const [allValues, setAllValues] = React.useState(['terminator', 'predator', 'soundofmusic']); + + return ( + + + {allValues.map((item) => ( + + ))} + ); + }; + + render(); + + const items = screen.queryAllByTestId('checkbox'); + expect(items[0]).toHaveAttribute('aria-checked', 'false'); + + await user.click(within(items[1]).getByTestId('checkbox-input')); + await user.click(within(items[2]).getByTestId('checkbox-input')); + await user.click(within(items[3]).getByTestId('checkbox-input')); + expect(items[0]).toHaveAttribute('aria-checked', 'true'); + + await user.click(screen.getByTestId('button')); - const checkbox = getByTestIdGlobal(getByDts(container, 'target'), 'checkbox-input'); - expect(checkbox.checked).toBe(true); - }); - - it('should work when the values are updated', () => { - const Component = () => { - const [value, setValue] = React.useState([]); - const [allValues, setAllValues] = React.useState(['terminator', 'predator', 'soundofmusic']); - - return ( - - - {allValues.map((item) => ( - - ))} - - - ); - }; - - const { queryAllByTestId, getByTestId } = render(); - - const items = queryAllByTestId('checkbox'); - expect(items[0]).toHaveAttribute('aria-checked', 'false'); - - fireEvent.click(getByTestIdGlobal(items[1], 'checkbox-input')); - fireEvent.click(getByTestIdGlobal(items[2], 'checkbox-input')); - fireEvent.click(getByTestIdGlobal(items[3], 'checkbox-input')); - expect(items[0]).toHaveAttribute('aria-checked', 'true'); - - fireEvent.click(getByTestId('button')); - - expect(items[0]).toHaveAttribute('aria-checked', 'mixed'); - }); + expect(items[0]).toHaveAttribute('aria-checked', 'mixed'); }); diff --git a/src/components/ConfirmModal/__snapshots__/index.spec.jsx.snap b/src/components/ConfirmModal/__snapshots__/index.spec.jsx.snap deleted file mode 100644 index 27c25b444..000000000 --- a/src/components/ConfirmModal/__snapshots__/index.spec.jsx.snap +++ /dev/null @@ -1,54 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` should show modal when \`show\` is true 1`] = ` -
-
-
- - - - -
-
-

- Are you sure? -

-
-
-`; diff --git a/src/components/ConfirmModal/index.d.ts b/src/components/ConfirmModal/index.d.ts index f9e41fba2..566969780 100644 --- a/src/components/ConfirmModal/index.d.ts +++ b/src/components/ConfirmModal/index.d.ts @@ -12,7 +12,7 @@ export interface ConfirmModalProps { /** * function called when modalApply event is fired */ - modalApply?: (...args: any[]) => any; + modalApply: (...args: any[]) => any; /** * function called when modalClose event is fired */ diff --git a/src/components/ConfirmModal/index.jsx b/src/components/ConfirmModal/index.jsx index 0efb51b7d..ef954b296 100644 --- a/src/components/ConfirmModal/index.jsx +++ b/src/components/ConfirmModal/index.jsx @@ -66,7 +66,7 @@ ConfirmModal.propTypes = { /** * function called when modalApply event is fired */ - modalApply: PropTypes.func, + modalApply: PropTypes.func.isRequired, /** * function called when modalClose event is fired */ @@ -89,9 +89,6 @@ ConfirmModal.propTypes = { ConfirmModal.defaultProps = { buttonCancelLabel: 'Cancel', buttonConfirmLabel: 'Confirm', - modalApply: () => { - throw new Error('AdslotUi ConfirmModal needs a modalApply handler'); - }, modalTitle: '', modalDescription: 'Are you sure?', show: false, diff --git a/src/components/ConfirmModal/index.spec.jsx b/src/components/ConfirmModal/index.spec.jsx index de7b75b26..182780df4 100644 --- a/src/components/ConfirmModal/index.spec.jsx +++ b/src/components/ConfirmModal/index.spec.jsx @@ -1,84 +1,71 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import ConfirmModal from '.'; -afterEach(cleanup); +it('should render with defaults', () => { + render(); -describe('', () => { - it('should render with defaults', () => { - const { getByTestId, queryByTestId } = render(); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('confirm-modal-component'); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('action-modal'); + expect(screen.getByTestId('action-panel-header')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-body')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-body')).toHaveTextContent('Are you sure?'); - expect(getByTestId('action-panel-wrapper')).toHaveClass('confirm-modal-component'); - expect(getByTestId('action-panel-wrapper')).toHaveClass('action-modal'); - expect(queryByTestId('action-panel-header')).toBeInTheDocument(); - expect(queryByTestId('action-panel-body')).toBeInTheDocument(); - expect(getByTestId('action-panel-body')).toHaveTextContent('Are you sure?'); - - expect(queryByTestId('action-panel-header')).toBeInTheDocument(); - expect(getByTestId('action-panel-header')).toContainElement(getByTestId('confirm-modal-confirm')); - expect(getByTestId('confirm-modal-confirm')).toHaveClass('aui-primary'); - expect(getByTestId('confirm-modal-confirm')).toHaveAttribute('data-test-selector', 'confirm-modal-confirm'); - expect(getByTestId('confirm-modal-confirm')).toHaveTextContent('Confirm'); - }); - - it('should render with props', () => { - const props = { - show: true, - buttonConfirmLabel: 'OK', - modalClose: jest.fn(), - modalDescription: 'If sure, please click confirm.', - modalTitle: 'Please Confirm', - }; - const { getByTestId, queryByTestId, getByText } = render(); + expect(screen.getByTestId('action-panel-header')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByTestId('confirm-modal-confirm')); + expect(screen.getByTestId('confirm-modal-confirm')).toHaveClass('aui-primary'); + expect(screen.getByTestId('confirm-modal-confirm')).toHaveAttribute('data-test-selector', 'confirm-modal-confirm'); + expect(screen.getByTestId('confirm-modal-confirm')).toHaveTextContent('Confirm'); +}); - expect(getByTestId('action-panel-wrapper')).toHaveClass('confirm-modal-component'); - expect(queryByTestId('action-panel-header')).toBeInTheDocument(); - expect(queryByTestId('action-panel-title')).toBeInTheDocument(); - expect(getByTestId('action-panel-title')).toHaveTextContent('Please Confirm'); +it('should render with props', () => { + const props = { + show: true, + buttonConfirmLabel: 'OK', + modalClose: jest.fn(), + modalDescription: 'If sure, please click confirm.', + modalTitle: 'Please Confirm', + modalApply: jest.fn(), + }; + render(); - expect(queryByTestId('action-panel-body')).toBeInTheDocument(); - expect(getByTestId('action-panel-body')).toHaveTextContent('If sure, please click confirm.'); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('confirm-modal-component'); + expect(screen.getByTestId('action-panel-header')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-title')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-title')).toHaveTextContent('Please Confirm'); - expect(queryByTestId('action-panel-header')).toBeInTheDocument(); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Cancel')); - expect(getByTestId('action-panel-header')).toContainElement(getByText('OK')); - }); + expect(screen.getByTestId('action-panel-body')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-body')).toHaveTextContent('If sure, please click confirm.'); - it('should show modal when `show` is true', () => { - const { getByTestId } = render(); - expect(getByTestId('action-panel-wrapper')).toMatchSnapshot(); - }); + expect(screen.getByTestId('action-panel-header')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Cancel')); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('OK')); +}); - it('should hide modal when `show` is false', () => { - const { queryByTestId } = render(); - expect(queryByTestId('action-panel-wrapper')).not.toBeInTheDocument(); - }); +it('should show modal when `show` is true', () => { + render(); + expect(screen.getByTestId('action-panel-wrapper')).toBeInTheDocument(); +}); - it('should call `modalApply` and `modalClose` when we click Apply', () => { - const applyMock = jest.fn(); - const closeMock = jest.fn(); - const { getByTestId } = render(); +it('should hide modal when `show` is false', () => { + render(); + expect(screen.queryByTestId('action-panel-wrapper')).not.toBeInTheDocument(); +}); - fireEvent.click(getByTestId('confirm-modal-confirm')); - expect(applyMock).toHaveBeenCalledTimes(1); - expect(closeMock).toHaveBeenCalledTimes(1); - }); +it('should call `modalApply` and `modalClose` when we click Apply', async () => { + const applyMock = jest.fn(); + const closeMock = jest.fn(); + render(); - it('should throw when we click Apply without a handler', () => { - const { getByTestId } = render(); - console.error = (err) => { - throw new Error(err); - }; - expect(() => fireEvent.click(getByTestId('confirm-modal-confirm'))).toThrow( - 'AdslotUi ConfirmModal needs a modalApply handler' - ); - }); + await user.click(screen.getByTestId('confirm-modal-confirm')); + expect(applyMock).toHaveBeenCalledTimes(1); + expect(closeMock).toHaveBeenCalledTimes(1); +}); - it('should call `modalClose` when we click Cancel', () => { - const closeMock = jest.fn(); - const { getByText } = render(); +it('should call `modalClose` when we click Cancel', async () => { + const closeMock = jest.fn(); + render(); - fireEvent.click(getByText('Cancel')); - expect(closeMock).toHaveBeenCalledTimes(1); - }); + await user.click(screen.getByText('Cancel')); + expect(closeMock).toHaveBeenCalledTimes(1); }); diff --git a/src/components/CountBadge/index.spec.jsx b/src/components/CountBadge/index.spec.jsx index 7f0d6266e..1436d1f2e 100644 --- a/src/components/CountBadge/index.spec.jsx +++ b/src/components/CountBadge/index.spec.jsx @@ -1,35 +1,31 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import CountBadge from '.'; -afterEach(cleanup); - -describe('', () => { - it('should render with defaults', () => { - const { getByTestId } = render(); - expect(getByTestId('count-badge-wrapper')).toHaveAttribute('data-test-selector', 'count-badge-one'); - expect(getByTestId('count-badge-wrapper')).toHaveTextContent('1'); - expect(getByTestId('count-badge-wrapper')).toHaveClass('status-default'); - expect(getByTestId('count-badge-wrapper')).toHaveClass('count-badge-font-size-normal'); - }); +it('should render with defaults', () => { + render(); + expect(screen.getByTestId('count-badge-wrapper')).toHaveAttribute('data-test-selector', 'count-badge-one'); + expect(screen.getByTestId('count-badge-wrapper')).toHaveTextContent('1'); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('status-default'); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('count-badge-font-size-normal'); +}); - it('should render with status info', () => { - const { getByTestId } = render(); - expect(getByTestId('count-badge-wrapper')).toHaveClass('status-info'); - }); +it('should render with status info', () => { + render(); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('status-info'); +}); - it('should render with status warning', () => { - const { getByTestId } = render(); - expect(getByTestId('count-badge-wrapper')).toHaveClass('status-warning'); - }); +it('should render with status warning', () => { + render(); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('status-warning'); +}); - it('should render with status danger', () => { - const { getByTestId } = render(); - expect(getByTestId('count-badge-wrapper')).toHaveClass('status-danger'); - }); +it('should render with status danger', () => { + render(); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('status-danger'); +}); - it('should render with a smaller font size if the value is greater than 99', () => { - const { getByTestId } = render(); - expect(getByTestId('count-badge-wrapper')).toHaveClass('count-badge-font-size-small'); - }); +it('should render with a smaller font size if the value is greater than 99', () => { + render(); + expect(screen.getByTestId('count-badge-wrapper')).toHaveClass('count-badge-font-size-small'); }); diff --git a/src/components/DatePicker/index.spec.jsx b/src/components/DatePicker/index.spec.jsx index f414ba746..500ea3b93 100644 --- a/src/components/DatePicker/index.spec.jsx +++ b/src/components/DatePicker/index.spec.jsx @@ -1,93 +1,69 @@ import React from 'react'; import moment from 'moment'; -import { render, cleanup, fireEvent, queryByAttribute } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import DatePicker from '.'; -afterEach(cleanup); +it('should render with defaults', () => { + render(); -const getByClass = queryByAttribute.bind(null, 'class'); - -describe('', () => { - it('should render with defaults', () => { - const { getByTestId } = render(); - - expect(getByTestId('date-picker-wrapper')).toHaveClass('aui--date-picker'); - expect(getByTestId('date-picker-wrapper')).toHaveAttribute('data-test-selector', 'test'); - expect(getByTestId('date-picker-wrapper')).not.toBeEmptyDOMElement(); - }); - - it('should handle input change', () => { - const onChange = jest.fn(); - const { container } = render( - - ); - - const datePickerInput = getByClass(container, 'test'); - - fireEvent.change(datePickerInput, { target: { value: '11 Oct 2021' } }); - expect(datePickerInput).toHaveValue('11 Oct 2021'); - }); - - it('should prevent inline editing when `disableInlineEditing`', () => { - const onChange = jest.fn(); - const { container } = render( - - ); - - const datePickerInput = getByClass(container, 'test'); + expect(screen.getByTestId('date-picker-wrapper')).toHaveClass('aui--date-picker'); + expect(screen.getByTestId('date-picker-wrapper')).toHaveAttribute('data-test-selector', 'test'); + expect(screen.getByTestId('date-picker-wrapper')).not.toBeEmptyDOMElement(); +}); - fireEvent.change(datePickerInput, { target: { value: '11 Oct 2021' } }); - expect(datePickerInput).toHaveValue('11 Oct 2020'); - }); +it('should handle input change', async () => { + const onChange = jest.fn(); + render( + + ); - it('should support Date object value', () => { - const onChange = jest.fn(); - const { container } = render( - - ); + const datePickerInput = screen.getByClass('test'); - const datePickerInput = getByClass(container, 'test'); + await user.click(datePickerInput); + await user.keyboard('11 Oct 2021'); + expect(datePickerInput).toHaveValue('11 Oct 2021'); +}); - fireEvent.change(datePickerInput, { target: { value: '12 Oct 2020' } }); - expect(datePickerInput).toHaveValue('12 Oct 2020'); - }); +it('should prevent inline editing when `disableInlineEditing`', async () => { + const onChange = jest.fn(); + render( + + ); + + const datePickerInput = screen.getByClass('test'); + await user.click(datePickerInput); + await user.keyboard('11 Oct 2021'); + + expect(datePickerInput).toHaveValue('11 Oct 2020'); +}); - it('should disable momentjs format', () => { - const onChange = jest.fn(); - const { container } = render( - - ); +it('should support Date object value', async () => { + const onChange = jest.fn(); + render( + + ); + expect(screen.getByClass('test')).toHaveValue('11 Oct 2020'); +}); - const datePickerInput = getByClass(container, 'test'); +it('should disable momentjs format', async () => { + const onChange = jest.fn(); + render(); - fireEvent.change(datePickerInput, { target: { value: '12 Oct 2020' } }); - expect(datePickerInput).toHaveValue('12 Oct 2020'); - }); + const datePickerInput = screen.getByClass('test'); + await user.click(datePickerInput); + await user.keyboard('12 Oct 2020'); + expect(datePickerInput).toHaveValue('12 Oct 2020'); }); diff --git a/src/components/DatePicker/transformFormat.spec.js b/src/components/DatePicker/transformFormat.spec.js index 155c96a72..90fe7003b 100644 --- a/src/components/DatePicker/transformFormat.spec.js +++ b/src/components/DatePicker/transformFormat.spec.js @@ -2,40 +2,38 @@ import moment from 'moment'; import { format } from 'date-fns'; import { transform } from './transformFormat'; -describe('', () => { - const date = new Date('2021-11-10T02:42:58.797Z'); +const date = new Date('2021-11-10T02:42:58.797Z'); - it('should format common format correctly', () => { - const formats = [ - 'YYYY-MM-DD', - 'YYYY-MM-DDThh:mm', - 'YYYY-MM-DD hh:mm:ss:SSS', - 'DD MMM YY', - 'MMM YYYY', - 'MMMM YYYY', - 'DD/MM/YYYY HH:mm:ss', - 'DD MMM YY [at] HH:mm:ssA [UTC]Z', - 'ddd, DD MMM YYYY HH:mm:ss [GMT]', - 'MMM-YYYY', - 'MMM DD YYYY', - 'DD MMM YYYY', - ]; +it('should format common format correctly', () => { + const formats = [ + 'YYYY-MM-DD', + 'YYYY-MM-DDThh:mm', + 'YYYY-MM-DD hh:mm:ss:SSS', + 'DD MMM YY', + 'MMM YYYY', + 'MMMM YYYY', + 'DD/MM/YYYY HH:mm:ss', + 'DD MMM YY [at] HH:mm:ssA [UTC]Z', + 'ddd, DD MMM YYYY HH:mm:ss [GMT]', + 'MMM-YYYY', + 'MMM DD YYYY', + 'DD MMM YYYY', + ]; - for (const fmt of formats) { - expect(moment(date).format(fmt)).toEqual(format(date, transform(fmt))); - } - }); + for (const fmt of formats) { + expect(moment(date).format(fmt)).toEqual(format(date, transform(fmt))); + } +}); - it('should escape correctly', () => { - const formats = ['[foobar]', '[YYYY-MM-DD]', '\\foo', '\\\\foo', '[\\foobar]', '\\[foobar\\]', '[[foobar]]', "''"]; +it('should escape correctly', () => { + const formats = ['[foobar]', '[YYYY-MM-DD]', '\\foo', '\\\\foo', '[\\foobar]', '\\[foobar\\]', '[[foobar]]', "''"]; - for (const fmt of formats) { - expect(moment(date).format(fmt)).toEqual(format(date, transform(fmt))); - } - }); + for (const fmt of formats) { + expect(moment(date).format(fmt)).toEqual(format(date, transform(fmt))); + } +}); - it('should return nil if input is nil', () => { - expect(transform(undefined)).toBeUndefined(); - expect(transform(null)).toBeNull(); - }); +it('should return nil if input is nil', () => { + expect(transform(undefined)).toBeUndefined(); + expect(transform(null)).toBeNull(); }); diff --git a/src/components/Empty/index.spec.jsx b/src/components/Empty/index.spec.jsx index 36194d33f..79bf3c806 100644 --- a/src/components/Empty/index.spec.jsx +++ b/src/components/Empty/index.spec.jsx @@ -1,38 +1,32 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import SvgSymbol from '../SvgSymbol'; import Empty from '.'; -afterEach(cleanup); - -describe('', () => { - it('should render with defaults', () => { - const { getByTestId } = render(); - expect(getByTestId('empty-wrapper')).toHaveClass('empty-component'); - expect(getByTestId('empty-text')).toHaveClass('empty-component-text'); - expect(getByTestId('empty-text')).toHaveTextContent('Nothing to show.'); - }); +it('should render with defaults', () => { + render(); + expect(screen.getByTestId('empty-wrapper')).toHaveClass('empty-component'); + expect(screen.getByTestId('empty-text')).toHaveClass('empty-component-text'); + expect(screen.getByTestId('empty-text')).toHaveTextContent('Nothing to show.'); +}); - it('should render an empty div when passed a non-empty collection Array', () => { - const { container, getByTestId } = render(); - const snapshot = getByTestId('empty-wrapper'); - expect(container.firstChild).toMatchObject(snapshot); - }); +it('should render an empty div when passed a non-empty collection Array', () => { + render(); + expect(screen.queryByTestId('empty-text')).not.toBeInTheDocument(); +}); - it('should render an empty div when passed a non-empty collection Object', () => { - const { container, getByTestId } = render(); - const snapshot = getByTestId('empty-wrapper'); - expect(container.firstChild).toMatchObject(snapshot); - }); +it('should render an empty div when passed a non-empty collection Object', () => { + render(); + expect(screen.queryByTestId('empty-text')).not.toBeInTheDocument(); +}); - it('should render with custom SVG symbol', () => { - const svgSymbol = ; - const props = { icon: svgSymbol, text: 'Where is everybody?' }; - const { getByTestId } = render(); - expect(getByTestId('empty-wrapper')).toHaveClass('empty-component'); - expect(getByTestId('empty-text')).toHaveClass('empty-component-text'); - expect(getByTestId('empty-text')).toHaveTextContent('Where is everybody?'); - expect(getByTestId('svg-symbol-wrapper')).toHaveClass('aui--svg-symbol-component-class'); - expect(getByTestId('svg-symbol-use')).toHaveAttribute('href', '//wherever.svg#id'); - }); +it('should render with custom SVG symbol', () => { + const svgSymbol = ; + const props = { icon: svgSymbol, text: 'Where is everybody?' }; + render(); + expect(screen.getByTestId('empty-wrapper')).toHaveClass('empty-component'); + expect(screen.getByTestId('empty-text')).toHaveClass('empty-component-text'); + expect(screen.getByTestId('empty-text')).toHaveTextContent('Where is everybody?'); + expect(screen.getByTestId('svg-symbol-wrapper')).toHaveClass('aui--svg-symbol-component-class'); + expect(screen.getByTestId('svg-symbol-use')).toHaveAttribute('href', '//wherever.svg#id'); }); diff --git a/src/components/FilePicker/index.jsx b/src/components/FilePicker/index.jsx index 78acdc8b1..c4bcc1a1a 100644 --- a/src/components/FilePicker/index.jsx +++ b/src/components/FilePicker/index.jsx @@ -30,7 +30,7 @@ class FilePicker extends React.PureComponent { }; removeFile = () => { - this.fileInput.current.value = null; + this.fileInput.current.value = ''; this.setState({ isFileSelected: false, fileName: '' }); if (this.props.onRemove) { this.props.onRemove(); diff --git a/src/components/FilePicker/index.spec.jsx b/src/components/FilePicker/index.spec.jsx index e65266bc5..dd424524c 100644 --- a/src/components/FilePicker/index.spec.jsx +++ b/src/components/FilePicker/index.spec.jsx @@ -1,96 +1,91 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render, screen, user } from 'testing'; import FilePicker from '.'; -afterEach(cleanup); +it('should render with defaults', () => { + render(); + expect(screen.getByTestId('file-picker-wrapper')).toHaveClass('filepicker-component input-group'); -describe('', () => { - it('should render with defaults', () => { - const { getByTestId } = render(); - expect(getByTestId('file-picker-wrapper')).toHaveClass('filepicker-component input-group'); + expect(screen.getByTestId('file-picker-form-control')).toHaveClass('form-control'); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('placeholder', 'No file selected'); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); - expect(getByTestId('file-picker-form-control')).toHaveClass('form-control'); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('placeholder', 'No file selected'); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); - - expect(getByTestId('file-picker-input-button-label')).toHaveTextContent('Select'); - expect(getByTestId('file-picker-input-button-input')).toHaveAttribute('type', 'file'); - }); - - it('should show remove button and call `onSelect` when file selected', () => { - const onSelect = jest.fn(); - const { getByTestId, queryByTestId } = render(); - - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('placeholder', 'No file selected'); + expect(screen.getByTestId('file-picker-input-button-label')).toHaveTextContent('Select'); + expect(screen.getByTestId('file-picker-input-button-input')).toHaveAttribute('type', 'file'); +}); - expect(queryByTestId('file-picker-remove-button')).not.toBeInTheDocument(); - expect(getByTestId('file-picker-input-button')).toBeEnabled(); +it('should show remove button and call `onSelect` when file selected', async () => { + const onSelect = jest.fn(); + render(); - expect(getByTestId('file-picker-input-button-input')).toHaveAttribute( - 'data-test-selector', - 'test-file-picker-input' - ); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('placeholder', 'No file selected'); - fireEvent.change(getByTestId('file-picker-input-button-input'), { target: { files: [{ name: 'selected file' }] } }); - expect(onSelect).toHaveBeenCalledTimes(1); - expect(onSelect).toHaveBeenCalledWith({ name: 'selected file' }); + expect(screen.queryByTestId('file-picker-remove-button')).not.toBeInTheDocument(); + expect(screen.getByTestId('file-picker-input-button')).toBeEnabled(); - expect(queryByTestId('file-picker-remove-button')).toBeInTheDocument(); - expect(getByTestId('file-picker-input-button')).toBeDisabled(); + expect(screen.getByTestId('file-picker-input-button-input')).toHaveAttribute( + 'data-test-selector', + 'test-file-picker-input' + ); - // onChange() should do nothing if isFileSelected is true - fireEvent.change(getByTestId('file-picker-input-button-input')); - expect(onSelect).toHaveBeenCalledTimes(1); + const file = new File(['test'], 'test.png', { type: 'image/png' }); + await user.upload(screen.getByTestId('file-picker-input-button-input'), file); + expect(onSelect).toHaveBeenCalledTimes(1); + expect(onSelect).toHaveBeenCalledWith(file); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', 'selected file'); - }); + expect(screen.getByTestId('file-picker-remove-button')).toBeInTheDocument(); + expect(screen.getByTestId('file-picker-input-button')).toBeDisabled(); - it('should upload a file when input-button is clicked', () => { - const onSelect = jest.fn(); - const file = new File(['test'], 'test.png', { type: 'image/png' }); - const { getByTestId } = render(); + // onChange() should do nothing if isFileSelected is true + await user.click(screen.getByTestId('file-picker-input-button-input')); + await user.keyboard('test'); + expect(onSelect).toHaveBeenCalledTimes(1); - userEvent.upload(getByTestId('file-picker-input-button-input'), file); - expect(onSelect).toHaveBeenCalledTimes(1); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); +}); - expect(getByTestId('file-picker-input-button-input').files[0]).toStrictEqual(file); - expect(getByTestId('file-picker-input-button-input').files.item(0)).toStrictEqual(file); - expect(getByTestId('file-picker-input-button-input').files).toHaveLength(1); +it('should upload a file when input-button is clicked', async () => { + const onSelect = jest.fn(); + render(); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); - expect(getByTestId('file-picker-form-control')).toHaveValue('test.png'); - }); + const file = new File(['test'], 'test.png', { type: 'image/png' }); + await user.upload(screen.getByTestId('file-picker-input-button-input'), file); + expect(onSelect).toHaveBeenCalledTimes(1); - it('should remove file selected when remove file button is clicked', () => { - const onSelect = jest.fn(); - const file = new File(['test'], 'test.png', { type: 'image/png' }); - const { getByTestId } = render(); + expect(screen.getByTestId('file-picker-input-button-input').files[0]).toStrictEqual(file); + expect(screen.getByTestId('file-picker-input-button-input').files.item(0)).toStrictEqual(file); + expect(screen.getByTestId('file-picker-input-button-input').files).toHaveLength(1); - userEvent.upload(getByTestId('file-picker-input-button-input'), file); - expect(onSelect).toHaveBeenCalledTimes(1); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); + expect(screen.getByTestId('file-picker-form-control')).toHaveValue('test.png'); +}); - fireEvent.click(getByTestId('file-picker-remove-button')); +it('should remove file selected when remove file button is clicked', async () => { + const onSelect = jest.fn(); + render(); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); - expect(getByTestId('file-picker-form-control')).toHaveValue(''); - }); + const file = new File(['test'], 'test.png', { type: 'image/png' }); + await user.upload(screen.getByTestId('file-picker-input-button-input'), file); + expect(onSelect).toHaveBeenCalledTimes(1); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); - it('should call `onRemove` when remove file button is clicked', () => { - const onSelect = jest.fn(); - const onRemove = jest.fn(); - const file = new File(['test'], 'test.png', { type: 'image/png' }); - const { getByTestId } = render(); + await user.click(screen.getByTestId('file-picker-remove-button')); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); + expect(screen.getByTestId('file-picker-form-control')).toHaveValue(''); +}); - userEvent.upload(getByTestId('file-picker-input-button-input'), file); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); - expect(onRemove).not.toHaveBeenCalled(); +it('should call `onRemove` when remove file button is clicked', async () => { + const onSelect = jest.fn(); + const onRemove = jest.fn(); + render(); - fireEvent.click(getByTestId('file-picker-remove-button')); + const file = new File(['test'], 'test.png', { type: 'image/png' }); + await user.upload(screen.getByTestId('file-picker-input-button-input'), file); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', 'test.png'); + expect(onRemove).not.toHaveBeenCalled(); - expect(getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); - expect(onRemove).toHaveBeenCalledTimes(1); - }); + await user.click(screen.getByTestId('file-picker-remove-button')); + expect(screen.getByTestId('file-picker-form-control')).toHaveAttribute('title', ''); + expect(onRemove).toHaveBeenCalledTimes(1); }); diff --git a/src/components/FlexibleSpacer/index.spec.jsx b/src/components/FlexibleSpacer/index.spec.jsx index a91d5bf91..04e9a53e0 100644 --- a/src/components/FlexibleSpacer/index.spec.jsx +++ b/src/components/FlexibleSpacer/index.spec.jsx @@ -1,12 +1,8 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import FlexibleSpacer from '.'; -afterEach(cleanup); - -describe('', () => { - it('should have its component name as className', () => { - const { getByTestId } = render(); - expect(getByTestId('flexible-spacer-wrapper')).toHaveClass('flexible-spacer-component'); - }); +it('should have its component name as className', () => { + render(); + expect(screen.getByTestId('flexible-spacer-wrapper')).toHaveClass('flexible-spacer-component'); }); diff --git a/src/components/FormGroup/index.spec.jsx b/src/components/FormGroup/index.spec.jsx index 8e783716f..88bbb7675 100644 --- a/src/components/FormGroup/index.spec.jsx +++ b/src/components/FormGroup/index.spec.jsx @@ -1,76 +1,71 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import FormGroup from '.'; -afterEach(cleanup); +const helpText = "Help me if you can I'm feeling down."; +const label = 'Sweet Caroline'; -describe('', () => { - const helpText = "Help me if you can I'm feeling down."; - const label = 'Sweet Caroline'; +it('should render with required props', () => { + render(); - it('should render with required props', () => { - const { getByTestId, queryByTestId } = render( - - ); + expect(screen.getByTestId('form-group-wrapper')).toHaveClass('form-group'); - expect(getByTestId('form-group-wrapper')).toHaveClass('form-group'); + expect(screen.getByTestId('form-group-label')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-label')).toHaveAttribute('for', 'sweet-caroline'); + expect(screen.getByTestId('form-group-label')).toHaveClass('control-label col-xs-3'); + expect(screen.getByTestId('form-group-label')).toHaveTextContent('Sweet Caroline'); - expect(queryByTestId('form-group-label')).toBeInTheDocument(); - expect(getByTestId('form-group-label')).toHaveAttribute('for', 'sweet-caroline'); - expect(getByTestId('form-group-label')).toHaveClass('control-label col-xs-3'); - expect(getByTestId('form-group-label')).toHaveTextContent('Sweet Caroline'); + expect(screen.getByTestId('form-group-input-group-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-input-group-wrapper')).toHaveClass('col-xs-5'); - expect(queryByTestId('form-group-input-group-wrapper')).toBeInTheDocument(); - expect(getByTestId('form-group-input-group-wrapper')).toHaveClass('col-xs-5'); + expect(screen.getByTestId('form-group-input-group')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-input-group')).toHaveClass('input-group col-xs-12'); - expect(queryByTestId('form-group-input-group')).toBeInTheDocument(); - expect(getByTestId('form-group-input-group')).toHaveClass('input-group col-xs-12'); + expect(screen.getByTestId('form-group-input')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-input')).toHaveClass('form-control'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('type', 'text'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('id', 'sweet-caroline'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('placeholder', 'baz'); + expect(screen.getByTestId('form-group-input')).toHaveValue(''); - expect(queryByTestId('form-group-input')).toBeInTheDocument(); - expect(getByTestId('form-group-input')).toHaveClass('form-control'); - expect(getByTestId('form-group-input')).toHaveAttribute('type', 'text'); - expect(getByTestId('form-group-input')).toHaveAttribute('id', 'sweet-caroline'); - expect(getByTestId('form-group-input')).toHaveAttribute('placeholder', 'baz'); - expect(getByTestId('form-group-input')).toHaveValue(''); - - expect(getByTestId('form-group-help')).toHaveClass('help-block'); - expect(queryByTestId('form-group-help')).toBeInTheDocument(); - expect(getByTestId('form-group-help')).toHaveTextContent(helpText); - }); + expect(screen.getByTestId('form-group-help')).toHaveClass('help-block'); + expect(screen.getByTestId('form-group-help')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-help')).toHaveTextContent(helpText); +}); - it('should render with an addon and a value', () => { - const onChangeMock = jest.fn(); - const { getByTestId, queryByTestId } = render( - - ); +it('should render with an addon and a value', async () => { + const onChangeMock = jest.fn(); + render( + + ); - expect(getByTestId('form-group-wrapper')).toHaveClass('form-group'); - expect(getByTestId('form-group-input-group')).toContainElement(getByTestId('form-group-input')); - expect(queryByTestId('form-group-input')).toBeInTheDocument(); - expect(getByTestId('form-group-input')).toHaveClass('form-control'); - expect(getByTestId('form-group-input')).toHaveAttribute('type', 'text'); - expect(getByTestId('form-group-input')).toHaveAttribute('id', 'sweet-caroline'); - expect(getByTestId('form-group-input')).toHaveAttribute('placeholder', '5.00'); - expect(getByTestId('form-group-input')).toHaveValue('10.00'); + expect(screen.getByTestId('form-group-wrapper')).toHaveClass('form-group'); + expect(screen.getByTestId('form-group-input-group')).toContainElement(screen.getByTestId('form-group-input')); + expect(screen.getByTestId('form-group-input')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-input')).toHaveClass('form-control'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('type', 'text'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('id', 'sweet-caroline'); + expect(screen.getByTestId('form-group-input')).toHaveAttribute('placeholder', '5.00'); + expect(screen.getByTestId('form-group-input')).toHaveValue('10.00'); - fireEvent.change(getByTestId('form-group-input'), { target: { value: 'a' } }); - expect(onChangeMock).toHaveBeenCalledTimes(1); - }); + await user.click(screen.getByTestId('form-group-input')); + await user.keyboard('a'); + expect(onChangeMock).toHaveBeenCalledTimes(1); +}); - it('should render as disabled', () => { - const onChangeMock = jest.fn(); - const { getByTestId, queryByTestId } = render( - - ); +it('should render as disabled', () => { + const onChangeMock = jest.fn(); + render( + + ); - expect(queryByTestId('form-group-input')).toBeInTheDocument(); - expect(getByTestId('form-group-input')).toBeDisabled(); - }); + expect(screen.getByTestId('form-group-input')).toBeInTheDocument(); + expect(screen.getByTestId('form-group-input')).toBeDisabled(); }); diff --git a/src/components/Grid/Cell/index.spec.jsx b/src/components/Grid/Cell/index.spec.jsx index cb5a175a2..8fada665c 100644 --- a/src/components/Grid/Cell/index.spec.jsx +++ b/src/components/Grid/Cell/index.spec.jsx @@ -1,67 +1,62 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import { classSuffixHelper } from '../../../utils'; import GridCell from '.'; -afterEach(cleanup); - -describe('', () => { - const componentClass = 'grid-component-cell'; - const getClassNames = (classSuffixes) => { - const classNames = classSuffixHelper({ classSuffixes, componentClass }); - return `${componentClass}${classNames}`; - }; - - it('should have its component name as default className and no data-test-selector', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(componentClass); - expect(getByTestId('grid-cell-wrapper')).toBeEmpty; - expect(getByTestId('grid-cell-wrapper')).not.toHaveAttribute('data-test-selector'); - }); - - it('should pass through children', () => { - const children = ( -
- Party town -
- ); - const { getByTestId } = render({children}); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(componentClass); - expect(getByTestId('grid-cell-children')).toHaveClass('test-class'); - expect(getByTestId('grid-cell-children')).toHaveTextContent('Party town'); - }); +const componentClass = 'grid-component-cell'; +const getClassNames = (classSuffixes) => { + const classNames = classSuffixHelper({ classSuffixes, componentClass }); + return `${componentClass}${classNames}`; +}; + +it('should have its component name as default className and no data-test-selector', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(componentClass); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveTextContent(''); + expect(screen.getByTestId('grid-cell-wrapper')).not.toHaveAttribute('data-test-selector'); +}); - it('should apply stretch class when stretch is true', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['stretch'])); - }); +it('should pass through children', () => { + const children = ( +
+ Party town +
+ ); + render({children}); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(componentClass); + expect(screen.getByTestId('grid-cell-children')).toHaveClass('test-class'); + expect(screen.getByTestId('grid-cell-children')).toHaveTextContent('Party town'); +}); - it('should handle onClick when passed', () => { - const onClick = jest.fn(); +it('should apply stretch class when stretch is true', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['stretch'])); +}); - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['clickable'])); - fireEvent.click(getByTestId('grid-cell-wrapper')); - expect(onClick).toHaveBeenCalledTimes(1); - }); +it('should handle onClick when passed', async () => { + const onClick = jest.fn(); + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['clickable'])); + await user.click(screen.getByTestId('grid-cell-wrapper')); + expect(onClick).toHaveBeenCalledTimes(1); +}); - it('should apply extra classes when passed classSuffixes', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['foo', 'bar'])); - }); +it('should apply extra classes when passed classSuffixes', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['foo', 'bar'])); +}); - it('should apply extra classes and stretch when passed classSuffixes and stretch', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['foo', 'bar', 'stretch'])); - }); +it('should apply extra classes and stretch when passed classSuffixes and stretch', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass(getClassNames(['foo', 'bar', 'stretch'])); +}); - it('should apply data-test-selector', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveAttribute('data-test-selector', 'this-has-data-test-selector'); - }); +it('should apply data-test-selector', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveAttribute('data-test-selector', 'this-has-data-test-selector'); +}); - it('should add custom classes when passed addonClassNames', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-cell-wrapper')).toHaveClass('grid-component-cell addonClass1 addonClass2'); - }); +it('should add custom classes when passed addonClassNames', () => { + render(); + expect(screen.getByTestId('grid-cell-wrapper')).toHaveClass('grid-component-cell addonClass1 addonClass2'); }); diff --git a/src/components/Grid/Row/index.spec.jsx b/src/components/Grid/Row/index.spec.jsx index 3c75946dd..09ef4e077 100644 --- a/src/components/Grid/Row/index.spec.jsx +++ b/src/components/Grid/Row/index.spec.jsx @@ -1,70 +1,66 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import { classSuffixHelper } from '../../../utils'; import GridRow from '.'; -afterEach(cleanup); +const componentClass = 'grid-component-row'; +const getClassNames = (classSuffixes) => { + const classNames = classSuffixHelper({ classSuffixes, componentClass }); + return `${componentClass}${classNames}`; +}; -describe('', () => { - const componentClass = 'grid-component-row'; - const getClassNames = (classSuffixes) => { - const classNames = classSuffixHelper({ classSuffixes, componentClass }); - return `${componentClass}${classNames}`; - }; - - it('should render with defaults', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border'])); - expect(getByTestId('grid-row-wrapper')).toBeEmptyDOMElement(); - expect(getByTestId('grid-row-wrapper')).not.toHaveAttribute('data-test-selector'); - }); +it('should render with defaults', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border'])); + expect(screen.getByTestId('grid-row-wrapper')).toBeEmptyDOMElement(); + expect(screen.getByTestId('grid-row-wrapper')).not.toHaveAttribute('data-test-selector'); +}); - it('should pass through children', () => { - const children = ( -
- Party town -
- ); - const { getByTestId } = render({children}); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border'])); - expect(getByTestId('grid-row-children')).toHaveClass('test-class'); - expect(getByTestId('grid-row-children')).toHaveTextContent('Party town'); - }); +it('should pass through children', () => { + const children = ( +
+ Party town +
+ ); + render({children}); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border'])); + expect(screen.getByTestId('grid-row-children')).toHaveClass('test-class'); + expect(screen.getByTestId('grid-row-children')).toHaveTextContent('Party town'); +}); - it('should have no horizontalBorder class when horizontalBorder is false', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body'])); - }); +it('should have no horizontalBorder class when horizontalBorder is false', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body'])); +}); - it('should apply short class when short is true', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border', 'short'])); - }); +it('should apply short class when short is true', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['body', 'horizontal-border', 'short'])); +}); - it('should apply header class instead of body when type is header', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['header', 'horizontal-border'])); - }); +it('should apply header class instead of body when type is header', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['header', 'horizontal-border'])); +}); - it('should apply subfooter class instead of body when type is subfooter', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['subfooter', 'horizontal-border'])); - }); +it('should apply subfooter class instead of body when type is subfooter', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['subfooter', 'horizontal-border'])); +}); - it('should apply footer class instead of body when type is footer', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['footer', 'horizontal-border'])); - }); +it('should apply footer class instead of body when type is footer', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass(getClassNames(['footer', 'horizontal-border'])); +}); - it('should apply vertical-cell-border class when verticalCellBorder is true', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveClass( - getClassNames(['body', 'horizontal-border', 'vertical-cell-border']) - ); - }); +it('should apply vertical-cell-border class when verticalCellBorder is true', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveClass( + getClassNames(['body', 'horizontal-border', 'vertical-cell-border']) + ); +}); - it('should apply data-test-selector', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-row-wrapper')).toHaveAttribute('data-test-selector', 'this-has-data-test-selector'); - }); +it('should apply data-test-selector', () => { + render(); + expect(screen.getByTestId('grid-row-wrapper')).toHaveAttribute('data-test-selector', 'this-has-data-test-selector'); }); diff --git a/src/components/Grid/index.spec.jsx b/src/components/Grid/index.spec.jsx index 52c79ce59..ac3fb0e32 100644 --- a/src/components/Grid/index.spec.jsx +++ b/src/components/Grid/index.spec.jsx @@ -1,25 +1,21 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import Grid from '.'; -afterEach(cleanup); - -describe('', () => { - it('should have its component name as default className', () => { - const { getByTestId } = render(); - expect(getByTestId('grid-wrapper')).toHaveClass('grid-component'); - expect(getByTestId('grid-wrapper')).toBeEmptyDOMElement(); - }); +it('should have its component name as default className', () => { + render(); + expect(screen.getByTestId('grid-wrapper')).toHaveClass('grid-component'); + expect(screen.getByTestId('grid-wrapper')).toBeEmptyDOMElement(); +}); - it('should pass through children', () => { - const children = ( -
- Party town -
- ); - const { getByTestId } = render({children}); - expect(getByTestId('grid-wrapper')).toHaveClass('grid-component'); - expect(getByTestId('grid-children')).toHaveClass('test-class'); - expect(getByTestId('grid-children')).toHaveTextContent('Party town'); - }); +it('should pass through children', () => { + const children = ( +
+ Party town +
+ ); + render({children}); + expect(screen.getByTestId('grid-wrapper')).toHaveClass('grid-component'); + expect(screen.getByTestId('grid-children')).toHaveClass('test-class'); + expect(screen.getByTestId('grid-children')).toHaveTextContent('Party town'); }); diff --git a/src/components/HelpIconPopover/index.spec.jsx b/src/components/HelpIconPopover/index.spec.jsx index 384cf4027..fa35fca60 100644 --- a/src/components/HelpIconPopover/index.spec.jsx +++ b/src/components/HelpIconPopover/index.spec.jsx @@ -1,46 +1,25 @@ import React from 'react'; -import { render, cleanup, fireEvent, act } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import HelpIconPopover from '.'; -beforeEach(() => { - jest.useFakeTimers(); -}); +it('should render with defaults', async () => { + render(Have some coffee.); + expect(screen.getByTestId('help-icon-popover-wrapper')).toHaveAttribute('data-test-selector', 'tired-help'); + expect(screen.getByTestId('popover-element')).toBeInTheDocument(); + expect(screen.queryByTestId('popover-wrapper')).not.toBeInTheDocument(); -afterEach(() => { - jest.useRealTimers(); + await user.hover(screen.getByTestId('help-icon-popover-trigger')); + expect(screen.getByTestId('popover-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('popover-content')).toHaveTextContent('Have some coffee.'); }); -afterEach(cleanup); - -describe('', () => { - it('should render with defaults', () => { - console.error = jest.fn(); - const { getByTestId, queryByTestId } = render(Have some coffee.); - expect(getByTestId('help-icon-popover-wrapper')).toHaveAttribute('data-test-selector', 'tired-help'); - expect(queryByTestId('popover-element')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - - act(() => { - fireEvent.mouseEnter(getByTestId('help-icon-popover-trigger')); - jest.runAllTimers(); - }); - - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - expect(getByTestId('popover-content')).toHaveTextContent('Have some coffee.'); - }); - - it('should allow custom placement positions', () => { - console.error = jest.fn(); - const { getByTestId } = render( - - Have some coffee. - - ); - act(() => { - fireEvent.mouseEnter(getByTestId('help-icon-popover-trigger')); - jest.runAllTimers(); - }); +it('should allow custom placement positions', async () => { + render( + + Have some coffee. + + ); - expect(getByTestId('popover-wrapper')).toHaveAttribute('placement', 'bottom'); - }); + await user.hover(screen.getByTestId('help-icon-popover-trigger')); + expect(screen.getByTestId('popover-wrapper')).toHaveAttribute('placement', 'bottom'); }); diff --git a/src/components/HoverDropdownMenu/PopoverLinkItem/index.d.ts b/src/components/HoverDropdownMenu/PopoverLinkItem/index.d.ts deleted file mode 100644 index 706e15d84..000000000 --- a/src/components/HoverDropdownMenu/PopoverLinkItem/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as React from 'react'; - -export type PopoverLinkItemTarget = '_blank' | '_self' | '_modal'; - -export interface PopoverLinkItemProps { - onClick?: (...args: any[]) => any; - target?: PopoverLinkItemTarget; - title: string; - url?: string; - isEnabled?: boolean; -} - -export default class PopoverLinkItem extends React.Component { - render(): JSX.Element; -} diff --git a/src/components/HoverDropdownMenu/PopoverLinkItem/index.jsx b/src/components/HoverDropdownMenu/PopoverLinkItem/index.jsx deleted file mode 100644 index 8f08a68a9..000000000 --- a/src/components/HoverDropdownMenu/PopoverLinkItem/index.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import _ from 'lodash'; -import PropTypes from 'prop-types'; -import React from 'react'; -import Anchor from '../../Anchor'; -import Button from '../../Button'; -import './styles.css'; - -class PopoverLinkItem extends React.PureComponent { - render() { - // eslint-disable-next-line react/prop-types - const { target, title, url, isEnabled, onClick } = this.props; - - const buttonProps = { - disabled: !isEnabled, - onClick, - variant: 'link', - }; - - if (target !== '_modal') { - _.assign(buttonProps, { href: url }); - } - - if (target === '_blank') { - _.assign(buttonProps, { rel: 'noopener noreferrer' }); - } - - return ( -
  • - {buttonProps.href ? {title} : } -
  • - ); - } -} - -export const LINK_PROPS = { - target: PropTypes.oneOf(['_blank', '_self', '_modal']), - title: PropTypes.string.isRequired, - url: PropTypes.string, - isEnabled: PropTypes.bool, -}; - -PopoverLinkItem.propTypes = { onClick: PropTypes.func, ...LINK_PROPS }; - -PopoverLinkItem.defaultProps = { - target: '_self', - isEnabled: true, - onClick: _.noop, -}; - -export default PopoverLinkItem; diff --git a/src/components/HoverDropdownMenu/PopoverLinkItem/index.spec.jsx b/src/components/HoverDropdownMenu/PopoverLinkItem/index.spec.jsx deleted file mode 100644 index e4952982f..000000000 --- a/src/components/HoverDropdownMenu/PopoverLinkItem/index.spec.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import _ from 'lodash'; -import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; -import PopoverLinkItem from './'; - -afterEach(cleanup); - -describe('', () => { - let props = {}; - - beforeEach(() => { - props = { - title: 'Link 1', - url: 'www.some.url.com', - target: '_self', - isEnabled: true, - onClick: jest.fn(), - }; - }); - - it('should render with default props', () => { - const { getByText, queryByTestId } = render(); - expect(queryByTestId('popover-link-item-wrapper')).toBeInTheDocument(); - expect(getByText('Link 1').parentElement).toHaveAttribute('href', 'www.some.url.com'); - }); - - it('should trigger `props.onClick` when clicking on the component', () => { - jest.spyOn(console, 'error').mockImplementation(_.noop); - const { getByText } = render(); - fireEvent.click(getByText('Link 1')); - expect(props.onClick).toHaveBeenCalledTimes(1); - }); - - it('should not have href props on `PopoverLinkItem` when `target` is _modal', () => { - props.target = '_modal'; - const { getByText } = render(); - expect(getByText('Link 1').parentElement).not.toHaveAttribute('href'); - }); - - it('should add `rel` to anchor props when target is "_blank"', () => { - props.target = '_blank'; - const { getByText } = render(); - expect(getByText('Link 1').parentElement).toHaveAttribute('rel', 'noopener noreferrer'); - }); -}); diff --git a/src/components/HoverDropdownMenu/PopoverLinkItem/styles.css b/src/components/HoverDropdownMenu/PopoverLinkItem/styles.css deleted file mode 100644 index fc11b46ea..000000000 --- a/src/components/HoverDropdownMenu/PopoverLinkItem/styles.css +++ /dev/null @@ -1,9 +0,0 @@ -@import url('../../../styles/variable.css'); - -.popover-link-item { - padding: 4px 2px 4px 6px; -} - -.popover-link-item:hover { - background-color: $color-grey-100; -} diff --git a/src/components/HoverDropdownMenu/index.d.ts b/src/components/HoverDropdownMenu/index.d.ts deleted file mode 100644 index 951ee0997..000000000 --- a/src/components/HoverDropdownMenu/index.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; - -export type HoverDropdownMenuArrowPosition = 'left' | 'right'; - -export interface HoverDropdownMenuProps { - /** - * Determine the placement of the popover - */ - arrowPosition?: HoverDropdownMenuArrowPosition; - /** - * If set to empty string, header will not be rendered. - */ - headerText?: string; - hoverComponent: React.ReactElement; - children?: React.ReactNode; -} - -declare const HoverDropdownMenu: React.FC; - -export default HoverDropdownMenu; diff --git a/src/components/HoverDropdownMenu/index.jsx b/src/components/HoverDropdownMenu/index.jsx deleted file mode 100644 index 7bff4f1a3..000000000 --- a/src/components/HoverDropdownMenu/index.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import _ from 'lodash'; -import React from 'react'; -import PropTypes from 'prop-types'; -import Popover from '../Popover'; -import PopoverLinkItem from './PopoverLinkItem'; -import './styles.css'; - -const HoverDropdownMenu = ({ arrowPosition, headerText, hoverComponent, children }) => { - const [popperNode, setPopperNode] = React.useState(null); - const [isOpen, setIsOpen] = React.useState(false); - const [mouseInPopover, setMouseInPopover] = React.useState(false); - - const closeMenu = _.debounce(() => { - setIsOpen(false); - }, 100); - - const popoverEnterHandler = React.useCallback(() => setMouseInPopover(true), [setMouseInPopover]); - const popoverLeaveHandler = React.useCallback(() => { - setMouseInPopover(false); - closeMenu(); - }, [setMouseInPopover, closeMenu]); - - React.useEffect(() => { - if (popperNode) { - popperNode.addEventListener('mouseenter', popoverEnterHandler); - popperNode.addEventListener('mouseleave', popoverLeaveHandler); - } - }, [popperNode, popoverEnterHandler, popoverLeaveHandler]); - - const openMenu = () => { - setIsOpen(true); - setMouseInPopover(false); - }; - - const element = ( -
    - {hoverComponent} -
    - ); - - return ( -
    - {children && children.length > 0 ? ( - {children}} - popperRef={setPopperNode} - > - {element} - - ) : null} -
    - ); -}; - -HoverDropdownMenu.propTypes = { - /** - * Determine the placement of the popover - */ - arrowPosition: PropTypes.oneOf(['left', 'right']), - /** - * If set to empty string, header will not be rendered. - */ - headerText: PropTypes.string, - hoverComponent: PropTypes.element.isRequired, - children: PropTypes.node, -}; - -HoverDropdownMenu.defaultProps = { - arrowPosition: 'left', - headerText: '', -}; - -HoverDropdownMenu.Item = PopoverLinkItem; - -export default HoverDropdownMenu; diff --git a/src/components/HoverDropdownMenu/index.spec.jsx b/src/components/HoverDropdownMenu/index.spec.jsx deleted file mode 100644 index ec882f4c6..000000000 --- a/src/components/HoverDropdownMenu/index.spec.jsx +++ /dev/null @@ -1,152 +0,0 @@ -import _ from 'lodash'; -import React from 'react'; -import { render, cleanup, fireEvent, act } from '@testing-library/react'; -import Avatar from '../Avatar'; -import HoverDropdownMenu from '.'; - -beforeEach(() => { - jest.useFakeTimers(); -}); - -afterEach(() => { - jest.useRealTimers(); -}); -afterEach(cleanup); - -describe('', () => { - let links = []; - let props = {}; - - beforeEach(() => { - links = [ - { - title: 'Link 1', - url: 'www.some.url.com', - target: '_self', - isEnabled: true, - }, - { - title: 'Logout', - url: 'https://www.google.com', - target: '_self', - isEnabled: true, - }, - ]; - - props = { - headerText: 'test header', - hoverComponent: , - onLinkClick: jest.fn(), - }; - }); - - it('should render with default props', () => { - const { queryByTestId } = render( - - something - - ); - - expect(queryByTestId('avatar-wrapper')).toBeInTheDocument(); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); - - it('should render popover with list of links when `links` is not empty', async () => { - console.error = jest.fn(); - const { getByTestId, queryByTestId, queryAllByTestId } = render( - - {_.map(links, (link, idx) => ( - - ))} - - ); - - act(() => { - fireEvent.mouseEnter(getByTestId('hover-dropdown-element')); - jest.runAllTimers(); - }); - - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - expect(queryAllByTestId('popover-link-item-wrapper')).toHaveLength(2); - queryAllByTestId('popover-link-item-wrapper').forEach((item) => expect(item).toHaveClass('popover-link-item')); - expect(queryAllByTestId('popover-link-item-wrapper')[0]).toHaveTextContent('Link 1'); - expect(queryAllByTestId('popover-link-item-wrapper')[1]).toHaveTextContent('Logout'); - }); - - it('should trigger popover open or close when mouse enter or leave HoverDropdownMenu ref element', () => { - console.error = jest.fn(); - const { getByTestId, queryByTestId } = render( - - {_.map(links, (link, idx) => ( - - ))} - - ); - act(() => { - fireEvent.mouseEnter(getByTestId('hover-dropdown-element')); - jest.runAllTimers(); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - - act(() => { - fireEvent.mouseLeave(getByTestId('hover-dropdown-element')); - jest.runAllTimers(); - }); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - - act(() => { - fireEvent.mouseEnter(getByTestId('hover-dropdown-element')); - jest.runAllTimers(); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - }); - - it('should trigger popover open or close when mouse enter or leave HoverDropdownMenu items', () => { - const { getByTestId, queryByTestId, queryAllByTestId } = render( - - {_.map(links, (link, idx) => ( - - ))} - - ); - - act(() => { - fireEvent.mouseEnter(getByTestId('hover-dropdown-element')); - jest.runAllTimers(); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - - act(() => { - fireEvent.mouseLeave(getByTestId('hover-dropdown-element')); - fireEvent.mouseEnter(getByTestId('popover-wrapper')); - jest.advanceTimersByTime(50); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - - act(() => { - fireEvent.mouseLeave(getByTestId('popover-wrapper')); - fireEvent.mouseEnter(getByTestId('popover-title')); - jest.advanceTimersByTime(50); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - - act(() => { - fireEvent.mouseLeave(getByTestId('popover-title')); - fireEvent.mouseEnter(queryAllByTestId('popover-link-item-wrapper')[0]); - jest.advanceTimersByTime(49); - }); - expect(queryByTestId('popover-wrapper')).toBeInTheDocument(); - - act(() => { - fireEvent.mouseLeave(getByTestId('popover-wrapper')); - jest.runAllTimers(); - }); - - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); - - it('should not render anything if there is no children', () => { - const { queryByTestId } = render(} />); - expect(queryByTestId('popover-wrapper')).not.toBeInTheDocument(); - }); -}); diff --git a/src/components/HoverDropdownMenu/styles.css b/src/components/HoverDropdownMenu/styles.css deleted file mode 100644 index 384e3c373..000000000 --- a/src/components/HoverDropdownMenu/styles.css +++ /dev/null @@ -1,24 +0,0 @@ -@import url('../../styles/variable.css'); - -.hover-dropdown { - display: inline-block; -} - -.hover-dropdown-popover .popover-title { - font-weight: $font-weight-bold; - padding: 8px 2px 8px 6px; - background-color: $color-white; -} - -.hover-dropdown-popover .popover-content { - width: 160px; - padding: 4px 0; -} - -.hover-dropdown-popover .popover-content ul { - margin: 0; -} - -.hover-dropdown-popover .popover-content .aui--button { - padding: 0; -} diff --git a/src/components/ImageCropper/index.spec.jsx b/src/components/ImageCropper/index.spec.jsx index c949fe041..02902bb5e 100644 --- a/src/components/ImageCropper/index.spec.jsx +++ b/src/components/ImageCropper/index.spec.jsx @@ -1,87 +1,61 @@ import _ from 'lodash'; import React from 'react'; -import { act, render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import ImageCropper from '.'; -afterEach(cleanup); +it('should render with props', () => { + render( + + ); + expect(screen.getByTestId('action-panel-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('action-panel-title')).toHaveTextContent('Image Upload'); -describe('', () => { - it('should render with props', () => { - const { getByTestId, queryByTestId } = render( - - ); - expect(queryByTestId('action-panel-wrapper')).toBeInTheDocument(); - expect(getByTestId('action-panel-title')).toHaveTextContent('Image Upload'); - - expect(getByTestId('image-cropper')).toHaveStyle('width: 400px; height: 400px;'); - - expect(getByTestId('image-cropper-img')).toHaveAttribute('src', 'example.svg'); - expect(getByTestId('image-cropper-img')).toHaveAttribute('alt', 'example'); - }); - - it('should call onCrop when user upload button is clicked', () => { - const onCrop = jest.fn(); - const { queryAllByTestId } = render(); - - // console.error would be fixed after updating react/react-dom/react-test-renderer to ^16.9.0 - act(() => { - fireEvent.click(queryAllByTestId('button-wrapper')[1]); - }); + expect(screen.getByTestId('image-cropper')).toHaveStyle('width: 400px; height: 400px;'); - expect(onCrop).toHaveBeenCalledTimes(1); - }); + expect(screen.getByTestId('image-cropper-img')).toHaveAttribute('src', './test.png'); + expect(screen.getByTestId('image-cropper-img')).toHaveAttribute('alt', 'example'); +}); - it('should setAspectRatio of cropperRef', () => { - const setAspectRadio = jest.fn(); +it('should call onCrop when user upload button is clicked', async () => { + const onCrop = jest.fn(); + render(); - const TestComponent = ({ aspectRatio }) => { - const cropperRef = React.useRef(); - React.useEffect(() => { - cropperRef.current.getCropper().current.setAspectRatio = setAspectRadio; - }, []); - return ( - - ); - }; + await user.click(screen.getAllByTestId('button-wrapper')[1]); + expect(onCrop).toHaveBeenCalledTimes(1); +}); - const { rerender } = render(); - act(() => { - rerender(); - }); - expect(setAspectRadio).toHaveBeenCalledTimes(1); - expect(setAspectRadio).toHaveBeenCalledWith(3); - }); +it('should setAspectRatio of cropperRef', () => { + const setAspectRadio = jest.fn(); - it('should destroy cropperRef if component will unmount', () => { - const cropperDestroy = jest.fn(); - const TestComponent = ({ aspectRatio }) => { - const cropperRef = React.useRef(); - React.useEffect(() => { - cropperRef.current.getCropper().current.destroy = cropperDestroy; - }, []); - return ( - - ); - }; + const TestComponent = ({ aspectRatio }) => { + const cropperRef = React.useRef(); + React.useEffect(() => { + cropperRef.current.getCropper().current.setAspectRatio = setAspectRadio; + }, []); + return ( + + ); + }; - const { unmount } = render(); + const view = render(); + view.rerender(); + expect(setAspectRadio).toHaveBeenCalledTimes(1); + expect(setAspectRadio).toHaveBeenCalledWith(3); +}); - act(() => { - unmount(); - }); +it('should destroy cropperRef if component will unmount', () => { + const cropperDestroy = jest.fn(); + const TestComponent = ({ aspectRatio }) => { + const cropperRef = React.useRef(); + React.useEffect(() => { + cropperRef.current.getCropper().current.destroy = cropperDestroy; + }, []); + return ( + + ); + }; - expect(cropperDestroy).toHaveBeenCalledTimes(1); - }); + const view = render(); + view.unmount(); + expect(cropperDestroy).toHaveBeenCalledTimes(1); }); diff --git a/src/components/InformationBox/index.spec.jsx b/src/components/InformationBox/index.spec.jsx index cf5ae52c5..1a23d80c9 100644 --- a/src/components/InformationBox/index.spec.jsx +++ b/src/components/InformationBox/index.spec.jsx @@ -1,83 +1,83 @@ import React from 'react'; -import { render, cleanup } from '@testing-library/react'; +import { render, screen } from 'testing'; import InformationBox from '.'; import SvgSymbol from '../SvgSymbol'; -afterEach(cleanup); - -describe('', () => { - const icon = ; - - it('should render with props', () => { - const { getByTestId, queryByTestId } = render( - -
    I am child
    -
    - ); - - expect(getByTestId('information-box-wrapper')).toHaveClass('aui--information-box aui--information-box-light'); - - expect(getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); - expect(queryByTestId('information-box-title')).toBeInTheDocument(); - expect(getByTestId('information-box-title')).toHaveTextContent('render title here'); - - expect(queryByTestId('information-box-icon')).toBeInTheDocument(); - expect(getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); - expect(queryByTestId('information-box-node')).toBeInTheDocument(); - expect(getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); - }); - - it('should render without a title when title props is not provided', () => { - const { getByTestId, queryByTestId } = render( - -
    I am child
    -
    - ); - - expect(queryByTestId('information-box-title')).not.toBeInTheDocument(); - - expect(queryByTestId('information-box-icon')).toBeInTheDocument(); - expect(getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); - - expect(queryByTestId('information-box-node')).toBeInTheDocument(); - expect(getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); - - expect(queryByTestId('svg-symbol-wrapper')).toBeInTheDocument(); - }); - - it('should render without an icon when icon props is not provided', () => { - const { getByTestId, queryByTestId } = render( - -
    I am child
    -
    - ); - - expect(getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); - expect(queryByTestId('information-box-title')).toBeInTheDocument(); - - expect(queryByTestId('information-box-test-children')).toBeInTheDocument(); - expect(queryByTestId('information-box-icon')).not.toBeInTheDocument(); - }); - - it('should render without children nodes when children props is not provided', () => { - const { getByTestId, queryByTestId } = render(); - - expect(getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); - expect(queryByTestId('information-box-title')).toBeInTheDocument(); - expect(getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); - expect(queryByTestId('information-box-icon')).toBeInTheDocument(); - expect(queryByTestId('information-box-node')).toBeInTheDocument(); - expect(getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); - expect(getByTestId('information-box-node')).toBeEmptyDOMElement(); - }); - - it('should accept custom class names', () => { - const { getByTestId } = render(); - expect(getByTestId('information-box-wrapper')).toHaveClass('aui--information-box aui--information-box-light cx'); - }); - - it('should accept custom theme', () => { - const { getByTestId } = render(); - expect(getByTestId('information-box-wrapper')).toHaveClass('aui--information-box aui--information-box-primary'); - }); +const icon = ; + +it('should render with props', () => { + render( + +
    I am child
    +
    + ); + + expect(screen.getByTestId('information-box-wrapper')).toHaveClass('aui--information-box aui--information-box-light'); + + expect(screen.getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); + expect(screen.getByTestId('information-box-title')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-title')).toHaveTextContent('render title here'); + + expect(screen.getByTestId('information-box-icon')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); + expect(screen.getByTestId('information-box-node')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); +}); + +it('should render without a title when title props is not provided', () => { + render( + +
    I am child
    +
    + ); + + expect(screen.queryByTestId('information-box-title')).not.toBeInTheDocument(); + + expect(screen.getByTestId('information-box-icon')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); + + expect(screen.getByTestId('information-box-node')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); + + expect(screen.getByTestId('svg-symbol-wrapper')).toBeInTheDocument(); +}); + +it('should render without an icon when icon props is not provided', () => { + render( + +
    I am child
    +
    + ); + + expect(screen.getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); + expect(screen.getByTestId('information-box-title')).toBeInTheDocument(); + + expect(screen.getByTestId('information-box-test-children')).toBeInTheDocument(); + expect(screen.queryByTestId('information-box-icon')).not.toBeInTheDocument(); +}); + +it('should render without children nodes when children props is not provided', () => { + render(); + + expect(screen.getByTestId('information-box-title')).toHaveClass('aui--information-box-title'); + expect(screen.getByTestId('information-box-title')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-icon')).toHaveClass('aui--information-box-icon'); + expect(screen.getByTestId('information-box-icon')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-node')).toBeInTheDocument(); + expect(screen.getByTestId('information-box-node')).toHaveClass('aui--information-box-node'); + expect(screen.getByTestId('information-box-node')).toBeEmptyDOMElement(); +}); + +it('should accept custom class names', () => { + render(); + expect(screen.getByTestId('information-box-wrapper')).toHaveClass( + 'aui--information-box aui--information-box-light cx' + ); +}); + +it('should accept custom theme', () => { + render(); + expect(screen.getByTestId('information-box-wrapper')).toHaveClass( + 'aui--information-box aui--information-box-primary' + ); }); diff --git a/src/components/ListPicker/index.d.ts b/src/components/ListPicker/index.d.ts index 726136745..0a13e19ac 100644 --- a/src/components/ListPicker/index.d.ts +++ b/src/components/ListPicker/index.d.ts @@ -41,10 +41,10 @@ export interface ListPickerProps { itemType?: string; labelFormatter?: (...args: any[]) => any; addonFormatter?: (...args: any[]) => any; - modalApply?: (...args: any[]) => any; + modalApply: (...args: any[]) => any; modalDescription?: string; modalClassName?: string; - modalClose?: (...args: any[]) => any; + modalClose: (...args: any[]) => any; modalFootnote?: string; modalTitle?: string; show?: boolean; diff --git a/src/components/ListPicker/index.jsx b/src/components/ListPicker/index.jsx index 966f43252..188aaaa36 100644 --- a/src/components/ListPicker/index.jsx +++ b/src/components/ListPicker/index.jsx @@ -188,10 +188,10 @@ ListPicker.propTypes = { labelFormatter: PropTypes.func, addonFormatter: PropTypes.func, linkButtons: linkButtonsProps, - modalApply: PropTypes.func, + modalApply: PropTypes.func.isRequired, modalDescription: PropTypes.string, modalClassName: PropTypes.string, - modalClose: PropTypes.func, + modalClose: PropTypes.func.isRequired, modalFootnote: PropTypes.string, modalTitle: PropTypes.string, show: PropTypes.bool, @@ -204,13 +204,7 @@ ListPicker.defaultProps = { items: [], itemType: 'item', linkButtons: [], - modalApply: () => { - throw new Error('AdslotUi ListPicker needs a modalApply handler'); - }, modalClassName: 'listpicker-component', - modalClose: () => { - throw new Error('AdslotUi ListPicker needs a modalClose handler'); - }, modalTitle: 'Select Items', show: false, }; diff --git a/src/components/ListPicker/index.spec.jsx b/src/components/ListPicker/index.spec.jsx index ff3bbf0e9..15b7ba4ef 100644 --- a/src/components/ListPicker/index.spec.jsx +++ b/src/components/ListPicker/index.spec.jsx @@ -1,319 +1,296 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Radio from '../Radio'; import SvgSymbol from '../SvgSymbol'; import ListPicker from '.'; import ListPickerMocks from '../ListPicker/mocks'; -afterEach(cleanup); +const { getInitialSelection, userHeaders, users, labelFormatter, teamMember2 } = ListPickerMocks; -describe('', () => { - const { getInitialSelection, userHeaders, users, labelFormatter, teamMember2 } = ListPickerMocks; +it('should render with defaults', () => { + render( + + ); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); + expect(screen.getByText('Select Items')).toHaveClass('title'); - let divContainer = null; + const listpickerPure = screen.getByTestId('listpickerpure-wrapper'); + expect(listpickerPure).toContainElement(screen.getByTestId('empty-wrapper')); + expect(screen.getByTestId('empty-wrapper').children).toHaveLength(1); //undefined emptyIcon + expect(screen.getByTestId('empty-wrapper')).toContainElement(screen.getByTestId('empty-text')); + expect(screen.getByTestId('empty-text')).toHaveTextContent('No items to select.'); - beforeEach(() => { - divContainer = document.createElement('div'); - document.body.innerHTML = ''; - document.body.appendChild(divContainer); - }); + expect(screen.getByTestId('action-panel-header')).toHaveClass('has-actions'); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Cancel')); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Apply')); +}); - it('should render with defaults', () => { - const { getByTestId, getByText } = render(); - expect(getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); - expect(getByText('Select Items')).toHaveClass('title'); +it('should render with props', () => { + const initialSelection = getInitialSelection(); + const items = users; + const props = { + emptyMessage: 'No users.', + emptySvgSymbol: , + initialSelection, + itemHeaders: userHeaders, + itemType: 'user', + labelFormatter, + linkButtons: [{ label: 'Create User', href: '#' }], + modalDescription: 'Select users.', + modalFootnote: 'You can select multiple users.', + modalTitle: 'Select Users', + modalApply: jest.fn(), + modalClose: jest.fn(), + }; + const view = render(); + + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); + expect(screen.getByText('Select Users')).toHaveClass('title'); + + expect(screen.getByText('You can select multiple users.')).toHaveClass('listpicker-component-footnote'); + + // items + expect(screen.getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-1'); + expect(screen.getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-2'); + expect(screen.getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-3'); + + expect(screen.getAllByTestId('checkbox-input')).toHaveLength(3); + expect(screen.getAllByTestId('checkbox-input')[0]).not.toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[1]).toBeChecked(); // selectedItems + expect(screen.getAllByTestId('checkbox-input')[2]).not.toBeChecked(); + + expect(screen.getByTestId('action-panel-header')).toHaveClass('has-actions'); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Cancel')); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Create User')); + + expect(screen.getByText('Create User').parentElement).toHaveAttribute('href', '#'); + expect(screen.getByText('Create User').parentElement).toHaveClass('aui--anchor aui-default aui-inverse'); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveAttribute( + 'data-test-selector', + 'listpickerpure-component-user' + ); // itemType: 'user' + + expect(screen.getByText('Team')).toHaveClass('grid-component-cell-stretch'); // itemHeaders: userHeaders + expect(screen.getByText('Member')).toHaveClass('grid-component-cell-header-toggle'); + + expect(screen.queryByTestId('svg-symbol-wrapper')).not.toBeInTheDocument(); + + view.rerender(); + expect(screen.getByTestId('svg-symbol-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('svg-symbol-use')).toHaveAttribute('href', '/some.svg#id'); // emptySvgSymbol + expect(screen.getByTestId('empty-text')).toHaveTextContent('No users.'); //emptyMessage +}); - const listpickerPure = getByTestId('listpickerpure-wrapper'); - expect(listpickerPure).toContainElement(getByTestId('empty-wrapper')); - expect(getByTestId('empty-wrapper').children).toHaveLength(1); //undefined emptyIcon - expect(getByTestId('empty-wrapper')).toContainElement(getByTestId('empty-text')); - expect(getByTestId('empty-text')).toHaveTextContent('No items to select.'); +it('should render with props for split pane', () => { + const itemInfo = { + label: 'User Details', + properties: [ + { label: 'Name', value: 'Jill Smith' }, + { label: 'Age', value: '21' }, + ], + }; + const initialSelection = getInitialSelection(); + const emptySvgSymbol =
    ; + const props = { + emptySvgSymbol, + emptyMessage: 'No users.', + initialSelection, + items: users, + itemHeaders: userHeaders, + itemInfo, + itemType: 'user', + labelFormatter, + modalDescription: 'Select users.', + modalFootnote: 'You can select multiple users.', + modalTitle: 'Select Users', + modalApply: jest.fn(), + modalClose: jest.fn(), + }; + render(); + expect(screen.getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); + + expect(screen.getByText('Select Users')).toHaveClass('title'); + + expect(screen.getByText('Select users.').tagName).toEqual('P'); + expect(screen.getByText('Select users.').parentElement).toHaveClass('aui--action-panel-body'); + + expect(screen.getByText('You can select multiple users.')).toHaveClass('listpicker-component-footnote'); + + expect(screen.getAllByTestId('split-panel-wrapper')).toHaveLength(2); + expect(screen.getAllByTestId('split-panel-wrapper')[0]).toHaveAttribute('data-test-selector', 'user-details'); + expect(screen.getAllByTestId('split-panel-wrapper')[0]).toContainElement(screen.getByText('User Details')); + + expect(screen.getByText('Name')).toHaveClass('grid-component-cell'); + expect(screen.getByText('Jill Smith')).toHaveClass('grid-component-cell'); + expect(screen.getByText('Jill Smith')).toHaveAttribute('data-test-selector', 'name'); + + expect(screen.getByText('Age')).toHaveClass('grid-component-cell'); + expect(screen.getByText('21')).toHaveClass('grid-component-cell'); + expect(screen.getByText('21')).toHaveAttribute('data-test-selector', 'age'); + + expect(screen.getAllByTestId('split-panel-wrapper')[1]).toContainElement( + screen.getByTestId('listpickerpure-wrapper') + ); + + // items + expect(screen.getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-1'); + expect(screen.getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-2'); + expect(screen.getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-3'); + + expect(screen.getAllByTestId('checkbox-input')).toHaveLength(3); + expect(screen.getAllByTestId('checkbox-input')[0]).not.toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[1]).toBeChecked(); // selectedItems + expect(screen.getAllByTestId('checkbox-input')[2]).not.toBeChecked(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveAttribute( + 'data-test-selector', + 'listpickerpure-component-user' + ); // itemType: 'user' + + expect(screen.getByText('Team')).toHaveClass('grid-component-cell-stretch'); // itemHeaders: userHeaders + expect(screen.getByText('Member')).toHaveClass('grid-component-cell-header-toggle'); +}); - expect(getByTestId('action-panel-header')).toHaveClass('has-actions'); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Cancel')); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Apply')); - }); +it('should disable apply button for empty selection if `allowEmptySelection` is false', () => { + const props = { allowEmptySelection: false, items: users }; + render(); + expect(screen.getByTestId('action-panel-header')).toContainElement(screen.getByText('Apply')); + expect(screen.getByText('Apply').parentElement).toBeDisabled(); +}); - it('should render with props', () => { - const initialSelection = getInitialSelection(); - const items = users; - const props = { - emptyMessage: 'No users.', - emptySvgSymbol: , - initialSelection, - itemHeaders: userHeaders, - itemType: 'user', - labelFormatter, - linkButtons: [{ label: 'Create User', href: '#' }], - modalDescription: 'Select users.', - modalFootnote: 'You can select multiple users.', - modalTitle: 'Select Users', - }; - const { getByTestId, queryByTestId, queryAllByTestId, getByText, rerender } = render( - - ); +it('should change `selectedItems` state after a `selectItem` action', async () => { + const props = { initialSelection: getInitialSelection(), labelFormatter, items: users }; + render(); + + expect(screen.getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); + expect(screen.getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); + expect(screen.getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); + + expect(screen.getAllByTestId('checkbox-input')).toHaveLength(3); + expect(screen.getAllByTestId('checkbox-input')[0]).not.toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[1]).toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[2]).not.toBeChecked(); + + await user.click(screen.getAllByTestId('checkbox-input')[0]); + expect(screen.getAllByTestId('checkbox-input')[0]).toBeChecked(); +}); - expect(getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); - expect(getByText('Select Users')).toHaveClass('title'); +it('should only allow one selection if `allowMultiSelection` is false', async () => { + const props = { + allowMultiSelection: false, + initialSelection: getInitialSelection(), + labelFormatter, + items: users, + }; + render(); + + expect(screen.getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); + expect(screen.getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); + expect(screen.getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); + + expect(screen.queryByTestId('checkbox-input')).not.toBeInTheDocument(); + expect(screen.getAllByTestId('radio-input')).toHaveLength(3); + + expect(screen.getAllByTestId('radio-input')[0]).not.toBeChecked(); + expect(screen.getAllByTestId('radio-input')[1]).toBeChecked(); + expect(screen.getAllByTestId('radio-input')[2]).not.toBeChecked(); + + await user.click(screen.getAllByTestId('radio-input')[0]); + expect(screen.getAllByTestId('radio-input')[0]).toBeChecked(); + expect(screen.getAllByTestId('radio-input')[1]).not.toBeChecked(); +}); - expect(getByText('You can select multiple users.')).toHaveClass('listpicker-component-footnote'); +it('should change `selectedItems` state after a `deselectItem` action', async () => { + const props = { initialSelection: getInitialSelection(), labelFormatter, items: users }; + render(); - // items - expect(getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-1'); - expect(getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-2'); - expect(getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-3'); + expect(screen.getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); + expect(screen.getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); + expect(screen.getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); - expect(queryAllByTestId('checkbox-input')).toHaveLength(3); - expect(queryAllByTestId('checkbox-input')[0]).not.toBeChecked(); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); // selectedItems - expect(queryAllByTestId('checkbox-input')[2]).not.toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')).toHaveLength(3); + expect(screen.getAllByTestId('checkbox-input')[0]).not.toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[1]).toBeChecked(); + expect(screen.getAllByTestId('checkbox-input')[2]).not.toBeChecked(); - expect(getByTestId('action-panel-header')).toHaveClass('has-actions'); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Cancel')); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Create User')); + await user.click(screen.getAllByTestId('checkbox-input')[1]); + expect(screen.getAllByTestId('checkbox-input')[1]).not.toBeChecked(); +}); - expect(getByText('Create User').parentElement).toHaveAttribute('href', '#'); - expect(getByText('Create User').parentElement).toHaveClass('aui--anchor aui-default aui-inverse'); +it('should show modal when `show` is true', () => { + render(); + expect(screen.getByTestId('action-panel-wrapper')).toBeInTheDocument(); +}); - expect(getByTestId('listpickerpure-wrapper')).toHaveAttribute( - 'data-test-selector', - 'listpickerpure-component-user' - ); // itemType: 'user' +it('should hide modal when `show` is false', () => { + render(); + expect(screen.queryByTestId('action-panel-wrapper')).not.toBeInTheDocument(); +}); - expect(getByText('Team')).toHaveClass('grid-component-cell-stretch'); // itemHeaders: userHeaders - expect(getByText('Member')).toHaveClass('grid-component-cell-header-toggle'); +it('should only call `modalApply` when we click Apply', async () => { + const applyMock = jest.fn(); + const closeMock = jest.fn(); - expect(queryByTestId('svg-symbol-wrapper')).not.toBeInTheDocument(); + const props = { + initialSelection: getInitialSelection(), + modalApply: applyMock, + modalClose: closeMock, + }; + render(); - rerender(); - expect(queryByTestId('svg-symbol-wrapper')).toBeInTheDocument(); - expect(getByTestId('svg-symbol-use')).toHaveAttribute('href', '/some.svg#id'); // emptySvgSymbol - expect(getByTestId('empty-text')).toHaveTextContent('No users.'); //emptyMessage - }); + await user.click(screen.getByText('Apply').parentElement); + expect(applyMock).toHaveBeenCalledWith([teamMember2]); + expect(closeMock).toHaveBeenCalledTimes(0); +}); - it('should render with props for split pane', () => { - const itemInfo = { - label: 'User Details', - properties: [ - { label: 'Name', value: 'Jill Smith' }, - { label: 'Age', value: '21' }, - ], - }; - const initialSelection = getInitialSelection(); - const emptySvgSymbol =
    ; - const props = { - emptySvgSymbol, +it('should call `modalClose` when we click Cancel', async () => { + const closeMock = jest.fn(); + + render(); + await user.click(screen.getByText('Cancel').parentElement); + expect(closeMock).toHaveBeenCalledTimes(1); +}); + +describe('linkButtons', () => { + const initialSelection = getInitialSelection(); + let props = null; + + beforeEach(() => { + props = { emptyMessage: 'No users.', + emptySvgSymbol: , initialSelection, items: users, itemHeaders: userHeaders, - itemInfo, itemType: 'user', labelFormatter, + linkButtons: [{ label: 'Create User', href: '#' }], modalDescription: 'Select users.', modalFootnote: 'You can select multiple users.', modalTitle: 'Select Users', + modalApply: jest.fn(), + modalClose: jest.fn(), }; - const { getByTestId, queryAllByTestId, getByText } = render(); - expect(getByTestId('action-panel-wrapper')).toHaveClass('listpicker-component'); - - expect(getByText('Select Users')).toHaveClass('title'); - - expect(getByText('Select users.').tagName).toEqual('P'); - expect(getByText('Select users.').parentElement).toHaveClass('aui--action-panel-body'); - - expect(getByText('You can select multiple users.')).toHaveClass('listpicker-component-footnote'); - - expect(queryAllByTestId('split-panel-wrapper')).toHaveLength(2); - expect(queryAllByTestId('split-panel-wrapper')[0]).toHaveAttribute('data-test-selector', 'user-details'); - expect(queryAllByTestId('split-panel-wrapper')[0]).toContainElement(getByText('User Details')); - - expect(getByText('Name')).toHaveClass('grid-component-cell'); - expect(getByText('Jill Smith')).toHaveClass('grid-component-cell'); - expect(getByText('Jill Smith')).toHaveAttribute('data-test-selector', 'name'); - - expect(getByText('Age')).toHaveClass('grid-component-cell'); - expect(getByText('21')).toHaveClass('grid-component-cell'); - expect(getByText('21')).toHaveAttribute('data-test-selector', 'age'); - - expect(queryAllByTestId('split-panel-wrapper')[1]).toContainElement(getByTestId('listpickerpure-wrapper')); - - // items - expect(getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-1'); - expect(getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-2'); - expect(getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'user-3'); - - expect(queryAllByTestId('checkbox-input')).toHaveLength(3); - expect(queryAllByTestId('checkbox-input')[0]).not.toBeChecked(); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); // selectedItems - expect(queryAllByTestId('checkbox-input')[2]).not.toBeChecked(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveAttribute( - 'data-test-selector', - 'listpickerpure-component-user' - ); // itemType: 'user' - - expect(getByText('Team')).toHaveClass('grid-component-cell-stretch'); // itemHeaders: userHeaders - expect(getByText('Member')).toHaveClass('grid-component-cell-header-toggle'); }); - it('should disable apply button for empty selection if `allowEmptySelection` is false', () => { - const props = { allowEmptySelection: false, items: users }; - const { getByText, getByTestId } = render(); - expect(getByTestId('action-panel-header')).toContainElement(getByText('Apply')); - expect(getByText('Apply').parentElement).toBeDisabled(); + it('should render as node', () => { + props.linkButtons = []; + render(); + expect(screen.getByTestId('radio-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('radio-input').tagName).toEqual('INPUT'); + expect(screen.getByTestId('radio-input')).toHaveAttribute('type', 'radio'); }); - it('should change `selectedItems` state after a `selectItem` action', () => { - const props = { initialSelection: getInitialSelection(), labelFormatter, items: users }; - const { queryAllByTestId, getByText } = render(); - - expect(getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); - expect(getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); - expect(getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); - - expect(queryAllByTestId('checkbox-input')).toHaveLength(3); - expect(queryAllByTestId('checkbox-input')[0]).not.toBeChecked(); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); - expect(queryAllByTestId('checkbox-input')[2]).not.toBeChecked(); - - fireEvent.click(queryAllByTestId('checkbox-input')[0]); - expect(queryAllByTestId('checkbox-input')[0]).toBeChecked(); - }); - - it('should only allow one selection if `allowMultiSelection` is false', () => { - const props = { - allowMultiSelection: false, - initialSelection: getInitialSelection(), - labelFormatter, - items: users, - }; - const { queryByTestId, queryAllByTestId, getByText } = render(); - - expect(getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); - expect(getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); - expect(getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); - - expect(queryByTestId('checkbox-input')).not.toBeInTheDocument(); - expect(queryAllByTestId('radio-input')).toHaveLength(3); - - expect(queryAllByTestId('radio-input')[0]).not.toBeChecked(); - expect(queryAllByTestId('radio-input')[1]).toBeChecked(); - expect(queryAllByTestId('radio-input')[2]).not.toBeChecked(); - - fireEvent.click(queryAllByTestId('radio-input')[0]); - expect(queryAllByTestId('radio-input')[0]).toBeChecked(); - expect(queryAllByTestId('radio-input')[1]).not.toBeChecked(); - }); - - it('should change `selectedItems` state after a `deselectItem` action', () => { - const props = { initialSelection: getInitialSelection(), labelFormatter, items: users }; - const { queryAllByTestId, getByText } = render(); - - expect(getByText('John Smith').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-1'); - expect(getByText('Jane Doe').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-2'); - expect(getByText('Jack White').parentElement.parentElement).toHaveAttribute('data-test-selector', 'item-3'); - - expect(queryAllByTestId('checkbox-input')).toHaveLength(3); - expect(queryAllByTestId('checkbox-input')[0]).not.toBeChecked(); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); - expect(queryAllByTestId('checkbox-input')[2]).not.toBeChecked(); + it('should render as mixed nodes and buttons', () => { + props.linkButtons = [{ label: 'Create User', href: '#' }, ]; + render(); - fireEvent.click(queryAllByTestId('checkbox-input')[1]); - expect(queryAllByTestId('checkbox-input')[1]).not.toBeChecked(); - }); - - it('should show modal when `show` is true', () => { - const { queryByTestId } = render(); - expect(queryByTestId('action-panel-wrapper')).toBeInTheDocument(); - }); - - it('should hide modal when `show` is false', () => { - const { queryByTestId } = render(); - expect(queryByTestId('action-panel-wrapper')).not.toBeInTheDocument(); - }); - - it('should only call `modalApply` when we click Apply', () => { - const applyMock = jest.fn(); - const closeMock = jest.fn(); - - const props = { - initialSelection: getInitialSelection(), - modalApply: applyMock, - modalClose: closeMock, - }; - const { getByText } = render(); - - fireEvent.click(getByText('Apply').parentElement); - expect(applyMock).toHaveBeenCalledWith([teamMember2]); - expect(closeMock).toHaveBeenCalledTimes(0); - }); - - it('should throw when we click Apply without a handler', () => { - console.error = (err) => { - throw new Error(err); - }; - const { getByText } = render(); - - expect(() => fireEvent.click(getByText('Apply'))).toThrow('AdslotUi ListPicker needs a modalApply handler'); - }); - - it('should call `modalClose` when we click Cancel', () => { - const closeMock = jest.fn(); - - const { getByText } = render(); - fireEvent.click(getByText('Cancel').parentElement); - expect(closeMock).toHaveBeenCalledTimes(1); - }); - - it('should throw when we click Close without a handler', () => { - console.error = (err) => { - throw new Error(err); - }; - const { getByText } = render(); - expect(() => fireEvent.click(getByText('Cancel').parentElement)).toThrow( - 'AdslotUi ListPicker needs a modalClose handler' - ); - }); + expect(screen.getByTestId('radio-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('radio-input').tagName).toEqual('INPUT'); + expect(screen.getByTestId('radio-input')).toHaveAttribute('type', 'radio'); - describe('linkButtons', () => { - const initialSelection = getInitialSelection(); - let props = null; - - beforeEach(() => { - props = { - emptyMessage: 'No users.', - emptySvgSymbol: , - initialSelection, - items: users, - itemHeaders: userHeaders, - itemType: 'user', - labelFormatter, - linkButtons: [{ label: 'Create User', href: '#' }], - modalDescription: 'Select users.', - modalFootnote: 'You can select multiple users.', - modalTitle: 'Select Users', - }; - }); - - it('should render as node', () => { - props.linkButtons = []; - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('radio-wrapper')).toBeInTheDocument(); - expect(getByTestId('radio-input').tagName).toEqual('INPUT'); - expect(getByTestId('radio-input')).toHaveAttribute('type', 'radio'); - }); - - it('should render as mixed nodes and buttons', () => { - props.linkButtons = [{ label: 'Create User', href: '#' }, ]; - const { getByTestId, queryByTestId, getByText } = render(); - - expect(queryByTestId('radio-wrapper')).toBeInTheDocument(); - expect(getByTestId('radio-input').tagName).toEqual('INPUT'); - expect(getByTestId('radio-input')).toHaveAttribute('type', 'radio'); - - expect(getByText('Create User').parentElement).toHaveClass('aui-inverse'); - expect(getByText('Create User').parentElement).toHaveAttribute('href', '#'); - }); + expect(screen.getByText('Create User').parentElement).toHaveClass('aui-inverse'); + expect(screen.getByText('Create User').parentElement).toHaveAttribute('href', '#'); }); }); diff --git a/src/components/ListPickerPure/index.d.ts b/src/components/ListPickerPure/index.d.ts index 94ba04066..a81574860 100644 --- a/src/components/ListPickerPure/index.d.ts +++ b/src/components/ListPickerPure/index.d.ts @@ -16,7 +16,7 @@ export interface ListPickerPureSelectedItems { export interface ListPickerPureProps { allowMultiSelection?: boolean; - deselectItem?: (...args: any[]) => any; + deselectItem: (...args: any[]) => any; emptyMessage?: string; emptySvgSymbol?: React.ReactNode; labelFormatter?: (...args: any[]) => any; @@ -24,7 +24,7 @@ export interface ListPickerPureProps { itemHeaders?: ListPickerPureItemHeaders; items?: ListPickerPureItems[]; itemType?: string; - selectItem?: (...args: any[]) => any; + selectItem: (...args: any[]) => any; selectedItems?: ListPickerPureSelectedItems[]; } diff --git a/src/components/ListPickerPure/index.jsx b/src/components/ListPickerPure/index.jsx index d3af22190..6275cdb12 100644 --- a/src/components/ListPickerPure/index.jsx +++ b/src/components/ListPickerPure/index.jsx @@ -114,7 +114,7 @@ const itemProps = PropTypes.shape({ ListPickerPure.propTypes = { allowMultiSelection: PropTypes.bool, - deselectItem: PropTypes.func, + deselectItem: PropTypes.func.isRequired, emptyMessage: PropTypes.string, emptySvgSymbol: PropTypes.node, labelFormatter: PropTypes.func, @@ -126,22 +126,16 @@ ListPickerPure.propTypes = { }), items: PropTypes.arrayOf(itemProps), itemType: PropTypes.string, - selectItem: PropTypes.func, + selectItem: PropTypes.func.isRequired, selectedItems: PropTypes.arrayOf(itemProps), }; ListPickerPure.defaultProps = { allowMultiSelection: true, - deselectItem: () => { - throw new Error('AdslotUi ListPickerPure needs a deselectItem handler'); - }, emptyMessage: 'No items to select.', labelFormatter: (item) => item.label, items: [], itemType: 'item', - selectItem: () => { - throw new Error('AdslotUi ListPickerPure needs a selectItem handler'); - }, selectedItems: [], }; diff --git a/src/components/ListPickerPure/index.spec.jsx b/src/components/ListPickerPure/index.spec.jsx index c83c22d47..dd3e5b6e5 100644 --- a/src/components/ListPickerPure/index.spec.jsx +++ b/src/components/ListPickerPure/index.spec.jsx @@ -1,281 +1,242 @@ import _ from 'lodash'; import React from 'react'; -import { render, cleanup, fireEvent, queryByAttribute, queryAllByAttribute } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render, screen, user, within } from 'testing'; import Empty from '../Empty'; import ListPickerPure from '.'; import ListPickerMocks from '../ListPicker/mocks'; -const getByDts = queryByAttribute.bind(null, 'data-test-selector'); -const queryAllByDts = queryAllByAttribute.bind(null, 'data-test-selector'); +const { getInitialSelection, labelFormatter, teamMember4, userHeaders, nodeUserHeaders, users, usersWithUuid } = + ListPickerMocks; -afterEach(cleanup); +const selectedItems = getInitialSelection(); -describe('', () => { - const { getInitialSelection, labelFormatter, teamMember4, userHeaders, nodeUserHeaders, users, usersWithUuid } = - ListPickerMocks; +Object.freeze(selectedItems); - const selectedItems = getInitialSelection(); +it('should render with defaults', () => { + render(); - Object.freeze(selectedItems); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveAttribute( + 'data-test-selector', + 'listpickerpure-component-item' + ); + expect(screen.getByTestId('grid-wrapper')).toBeInTheDocument(); - it('should render with defaults', () => { - const { getByTestId, queryByTestId } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(getByTestId('listpickerpure-wrapper')).toHaveAttribute( - 'data-test-selector', - 'listpickerpure-component-item' - ); - expect(queryByTestId('grid-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('empty-wrapper')).toBeInTheDocument(); + expect(screen.getByTestId('empty-wrapper')).not.toBeEmptyDOMElement(); + expect(screen.getByTestId('empty-wrapper')).toHaveTextContent('No items to select.'); +}); - expect(queryByTestId('empty-wrapper')).toBeInTheDocument(); - expect(getByTestId('empty-wrapper')).not.toBeEmptyDOMElement(); - expect(getByTestId('empty-wrapper')).toHaveTextContent('No items to select.'); - }); +it('should render with props', () => { + const props = { + items: users, + itemHeaders: userHeaders, + itemType: 'user', + labelFormatter, + selectedItems, + }; + render(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveAttribute( + 'data-test-selector', + 'listpickerpure-component-user' + ); + + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Team')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Member')); + expect(screen.getByText('Team')).toHaveClass('grid-component-cell'); + expect(screen.getByText('Member')).toHaveClass('grid-component-cell'); + + screen.queryAllByTestId('grid-row-wrapper').forEach((each) => expect(each).toHaveClass('grid-component-row')); + expect(screen.queryAllByTestId('grid-row-wrapper')[1]).toContainElement(screen.getByText('John Smith')); + expect(screen.queryAllByTestId('grid-row-wrapper')[2]).toContainElement(screen.getByText('Jane Doe')); + expect(screen.queryAllByTestId('grid-row-wrapper')[3]).toContainElement(screen.getByText('Jack White')); + + expect(screen.getByText('John Smith').parentElement).toHaveAttribute('data-test-selector', 'label'); + expect(screen.getByText('John Smith').parentElement).toHaveClass('grid-component-cell-stretch'); + expect(screen.getByText('Jane Doe').parentElement).toHaveAttribute('data-test-selector', 'label'); + expect(screen.getByText('Jane Doe').parentElement).toHaveClass('grid-component-cell-stretch'); + expect(screen.getByText('Jack White').parentElement).toHaveAttribute('data-test-selector', 'label'); + expect(screen.getByText('Jack White').parentElement).toHaveClass('grid-component-cell-stretch'); + + expect(screen.getByDts('user-1')).toHaveTextContent('John Smith'); + expect(screen.getByDts('user-2')).toHaveTextContent('Jane Doe'); + expect(screen.getByDts('user-3')).toHaveTextContent('Jack White'); + + const toggles = screen.queryAllByDts('toggle'); + expect(toggles).toHaveLength(3); + expect(within(toggles[0]).getByTestId('checkbox-input')).not.toBeChecked(); + expect(within(toggles[1]).getByTestId('checkbox-input')).toBeChecked(); + expect(within(toggles[2]).getByTestId('checkbox-input')).not.toBeChecked(); +}); - it('should render with props', () => { - const props = { - items: users, - itemHeaders: userHeaders, - itemType: 'user', - labelFormatter, - selectedItems, - }; - const { container, getByTestId, queryAllByTestId, getByText } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(getByTestId('listpickerpure-wrapper')).toHaveAttribute( - 'data-test-selector', - 'listpickerpure-component-user' - ); - - expect(queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Team')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Member')); - expect(getByText('Team')).toHaveClass('grid-component-cell'); - expect(getByText('Member')).toHaveClass('grid-component-cell'); - - queryAllByTestId('grid-row-wrapper').forEach((each) => expect(each).toHaveClass('grid-component-row')); - expect(queryAllByTestId('grid-row-wrapper')[1]).toContainElement(getByText('John Smith')); - expect(queryAllByTestId('grid-row-wrapper')[2]).toContainElement(getByText('Jane Doe')); - expect(queryAllByTestId('grid-row-wrapper')[3]).toContainElement(getByText('Jack White')); - - expect(getByText('John Smith').parentElement).toHaveAttribute('data-test-selector', 'label'); - expect(getByText('John Smith').parentElement).toHaveClass('grid-component-cell-stretch'); - expect(getByText('Jane Doe').parentElement).toHaveAttribute('data-test-selector', 'label'); - expect(getByText('Jane Doe').parentElement).toHaveClass('grid-component-cell-stretch'); - expect(getByText('Jack White').parentElement).toHaveAttribute('data-test-selector', 'label'); - expect(getByText('Jack White').parentElement).toHaveClass('grid-component-cell-stretch'); - - expect(getByDts(container, 'user-1')).toHaveTextContent('John Smith'); - expect(getByDts(container, 'user-2')).toHaveTextContent('Jane Doe'); - expect(getByDts(container, 'user-3')).toHaveTextContent('Jack White'); - - expect(queryAllByDts(container, 'toggle')).toHaveLength(3); - queryAllByDts(container, 'toggle').forEach((each, index) => { - expect(each).toContainElement(queryAllByTestId('checkbox')[index]); - if (_.some(selectedItems, { id: users[index].id })) - expect(queryAllByTestId('checkbox-input')[index]).toBeChecked(); - }); - }); +it('should render with props including items and selectItems with uuids', () => { + const selectedItemsWithUuid = [teamMember4]; + const props = { + items: usersWithUuid, + itemHeaders: userHeaders, + labelFormatter, + selectedItems: selectedItemsWithUuid, + }; - it('should render with props including items and selectItems with uuids', () => { - const selectedItemsWithUuid = [teamMember4]; - const props = { - items: usersWithUuid, - itemHeaders: userHeaders, - labelFormatter, - selectedItems: selectedItemsWithUuid, - }; - - const { container, getByTestId, queryAllByTestId, getByText } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - - expect(queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Team')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Member')); - - queryAllByTestId('grid-row-wrapper').forEach((each) => expect(each).toHaveClass('grid-component-row')); - expect(queryAllByTestId('grid-row-wrapper')[1]).toContainElement(getByText('Jones Cheng')); - expect(queryAllByTestId('grid-row-wrapper')[2]).toContainElement(getByText('Joe Huang')); - - expect(getByText('Jones Cheng').parentElement).toHaveAttribute('data-test-selector', 'label'); - expect(getByText('Jones Cheng').parentElement).toHaveClass('grid-component-cell-stretch'); - expect(getByText('Joe Huang').parentElement).toHaveAttribute('data-test-selector', 'label'); - expect(getByText('Joe Huang').parentElement).toHaveClass('grid-component-cell-stretch'); - - expect(queryAllByDts(container, 'toggle')).toHaveLength(2); - queryAllByDts(container, 'toggle').forEach((each, index) => { - expect(each).toContainElement(queryAllByTestId('checkbox')[index]); - if (_.some(selectedItemsWithUuid, { id: usersWithUuid[index].id })) - expect(queryAllByTestId('checkbox-input')[index]).toBeChecked(); - }); - }); + render(); - it('should render with props including addonFormatter', () => { - const addonFormatter = () => ; - const itemHeaders = _.assign({}, ListPickerMocks.userHeaders, { - addon: 'Required', - }); - const props = { - items: users, - itemHeaders, - labelFormatter, - selectedItems, - addonFormatter, - }; - const { container, getByTestId, queryAllByTestId, getByText } = render(); - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - - expect(queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Team')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Member')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Required')); - expect(getByText('Required')).toHaveClass('grid-component-cell grid-component-cell-header-addon'); - - expect(queryAllByDts(container, 'addon')).toHaveLength(3); - queryAllByDts(container, 'addon').forEach((each) => { - expect(each).toHaveClass('grid-component-cell-addon'); - expect(each).toHaveTextContent('Nothing to show.'); - }); - }); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - it('should allow user to render node type label', () => { - const props = { - itemType: 'group-user', - items: users, - itemHeaders: nodeUserHeaders, - labelFormatter, - selectedItems, - }; - const { getByTestId, queryAllByTestId, getByText } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(getByTestId('listpickerpure-wrapper')).toHaveAttribute( - 'data-test-selector', - 'listpickerpure-component-group-user' - ); - - expect(queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Group')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Team')); - expect(queryAllByTestId('grid-row-wrapper')[0]).toContainElement(getByText('Member')); - }); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Team')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Member')); - it('should render radio buttons with `allowMultiSelection` as false', () => { - const props = { allowMultiSelection: false, items: users, selectedItems }; - const { container, getByTestId, queryAllByTestId } = render(); + screen.queryAllByTestId('grid-row-wrapper').forEach((each) => expect(each).toHaveClass('grid-component-row')); + expect(screen.queryAllByTestId('grid-row-wrapper')[1]).toContainElement(screen.getByText('Jones Cheng')); + expect(screen.queryAllByTestId('grid-row-wrapper')[2]).toContainElement(screen.getByText('Joe Huang')); - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.getByText('Jones Cheng').parentElement).toHaveAttribute('data-test-selector', 'label'); + expect(screen.getByText('Jones Cheng').parentElement).toHaveClass('grid-component-cell-stretch'); + expect(screen.getByText('Joe Huang').parentElement).toHaveAttribute('data-test-selector', 'label'); + expect(screen.getByText('Joe Huang').parentElement).toHaveClass('grid-component-cell-stretch'); - expect(getByDts(container, 'item-1')).toContainElement(queryAllByDts(container, 'toggle')[0]); - expect(getByDts(container, 'item-2')).toContainElement(queryAllByDts(container, 'toggle')[1]); - expect(getByDts(container, 'item-3')).toContainElement(queryAllByDts(container, 'toggle')[2]); + const toggles = screen.queryAllByDts('toggle'); + expect(toggles).toHaveLength(2); + expect(within(toggles[0]).getByTestId('checkbox-input')).toBeChecked(); + expect(within(toggles[1]).getByTestId('checkbox-input')).not.toBeChecked(); +}); - queryAllByDts(container, 'toggle').forEach((each, index) => { - expect(each).toContainElement(queryAllByTestId('radio-wrapper')[index]); - if (_.some(selectedItems, { id: users[index].id })) expect(queryAllByTestId('radio-input')[index]).toBeChecked(); - }); +it('should render with props including addonFormatter', () => { + const addonFormatter = () => ; + const itemHeaders = _.assign({}, ListPickerMocks.userHeaders, { + addon: 'Required', }); - - it('should throw when we select without a `selectItem` handler', () => { - console.error = (err) => { - throw new Error(err); - }; - const props = { items: users, selectedItems }; - const { getByTestId, queryAllByTestId } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - - expect(queryAllByTestId('checkbox-input')[0]).not.toBeChecked(); - - expect(() => fireEvent.click(queryAllByTestId('checkbox-input')[0])).toThrow( - 'AdslotUi ListPickerPure needs a selectItem handler' - ); + const props = { + items: users, + itemHeaders, + labelFormatter, + selectedItems, + addonFormatter, + }; + render(); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Team')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Member')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Required')); + expect(screen.getByText('Required')).toHaveClass('grid-component-cell grid-component-cell-header-addon'); + + expect(screen.queryAllByDts('addon')).toHaveLength(3); + screen.queryAllByDts('addon').forEach((each) => { + expect(each).toHaveClass('grid-component-cell-addon'); + expect(each).toHaveTextContent('Nothing to show.'); }); +}); - it('should throw when we deselect without a `deselectItem` handler', () => { - console.error = (err) => { - throw new Error(err); - }; - const props = { items: users, selectedItems }; - const { getByTestId, queryAllByTestId } = render(); +it('should allow user to render node type label', () => { + const props = { + itemType: 'group-user', + items: users, + itemHeaders: nodeUserHeaders, + labelFormatter, + selectedItems, + }; + render(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveAttribute( + 'data-test-selector', + 'listpickerpure-component-group-user' + ); + + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toHaveClass('grid-component-row-header'); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Group')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Team')); + expect(screen.queryAllByTestId('grid-row-wrapper')[0]).toContainElement(screen.getByText('Member')); +}); - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); +it('should render radio buttons with `allowMultiSelection` as false', () => { + const props = { allowMultiSelection: false, items: users, selectedItems }; + render(); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(() => fireEvent.click(queryAllByTestId('checkbox-input')[1])).toThrow( - 'AdslotUi ListPickerPure needs a deselectItem handler' - ); - }); + expect(screen.getByDts('item-1')).toContainElement(screen.queryAllByDts('toggle')[0]); + expect(screen.getByDts('item-2')).toContainElement(screen.queryAllByDts('toggle')[1]); + expect(screen.getByDts('item-3')).toContainElement(screen.queryAllByDts('toggle')[2]); - it('should call `selectItem` handler when we select', () => { - let handlerCalled = 0; - let isAllowMultiSelection; - const props = { - allowMultiSelection: false, - items: users, - selectedItems, - selectItem: (_item, allowMultiSelection) => { - handlerCalled++; - isAllowMultiSelection = allowMultiSelection; - }, - }; - const { getByTestId, queryAllByTestId } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(queryAllByTestId('radio-input')[0]).not.toBeChecked(); - - fireEvent.click(queryAllByTestId('radio-input')[0]); - expect(handlerCalled).toEqual(1); - expect(isAllowMultiSelection).toEqual(false); - }); + const toggles = screen.queryAllByDts('toggle'); + expect(toggles).toHaveLength(3); + expect(within(toggles[0]).getByTestId('radio-input')).not.toBeChecked(); + expect(within(toggles[1]).getByTestId('radio-input')).toBeChecked(); + expect(within(toggles[2]).getByTestId('radio-input')).not.toBeChecked(); +}); - it('should call `deselectItem` handler when we deselect', () => { - let handlerCalled = 0; - let isAllowMultiSelection; - const props = { - items: users, - selectedItems, - deselectItem: (_item, allowMultiSelection) => { - handlerCalled++; - isAllowMultiSelection = allowMultiSelection; - }, - }; - const { getByTestId, queryAllByTestId } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(queryAllByTestId('checkbox-input')[1]).toBeChecked(); - - fireEvent.click(queryAllByTestId('checkbox-input')[1]); - expect(handlerCalled).toEqual(1); - expect(isAllowMultiSelection).toEqual(true); - }); +it('should call `selectItem` handler when we select', async () => { + let handlerCalled = 0; + let isAllowMultiSelection; + const props = { + allowMultiSelection: false, + items: users, + selectedItems, + selectItem: (_item, allowMultiSelection) => { + handlerCalled++; + isAllowMultiSelection = allowMultiSelection; + }, + deselectItem: jest.fn(), + }; + render(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.queryAllByTestId('radio-input')[0]).not.toBeChecked(); + + await user.click(screen.queryAllByTestId('radio-input')[0]); + expect(handlerCalled).toEqual(1); + expect(isAllowMultiSelection).toEqual(false); +}); - it('should be keyboard navigable', () => { - let handlerCalled = 0; - let isAllowMultiSelection; - const props = { - allowMultiSelection: false, - items: users, - selectedItems, - selectItem: (_item, allowMultiSelection) => { - handlerCalled++; - isAllowMultiSelection = allowMultiSelection; - }, - }; - const { getAllByTestId, getByTestId, queryAllByTestId } = render(); - - expect(getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); - expect(queryAllByTestId('radio-input')[0]).not.toBeChecked(); - userEvent.tab(); - userEvent.keyboard(' '); - expect(handlerCalled).toEqual(1); - expect(isAllowMultiSelection).toEqual(false); - userEvent.keyboard('[ArrowDown][ArrowDown]'); - expect(getAllByTestId('radio-wrapper')[2]).toHaveFocus(); - }); +it('should call `deselectItem` handler when we deselect', async () => { + let handlerCalled = 0; + let isAllowMultiSelection; + const props = { + items: users, + selectedItems, + deselectItem: (_item, allowMultiSelection) => { + handlerCalled++; + isAllowMultiSelection = allowMultiSelection; + }, + selectItem: jest.fn(), + }; + render(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.queryAllByTestId('checkbox-input')[1]).toBeChecked(); + + await user.click(screen.queryAllByTestId('checkbox-input')[1]); + expect(handlerCalled).toEqual(1); + expect(isAllowMultiSelection).toEqual(true); +}); + +it('should be keyboard navigable', async () => { + let handlerCalled = 0; + let isAllowMultiSelection; + const props = { + allowMultiSelection: false, + items: users, + selectedItems, + selectItem: (_item, allowMultiSelection) => { + handlerCalled++; + isAllowMultiSelection = allowMultiSelection; + }, + deselectItem: jest.fn(), + }; + render(); + + expect(screen.getByTestId('listpickerpure-wrapper')).toHaveClass('listpickerpure-component'); + expect(screen.queryAllByTestId('radio-input')[0]).not.toBeChecked(); + await user.tab(); + await user.keyboard(' '); + expect(handlerCalled).toEqual(1); + expect(isAllowMultiSelection).toEqual(false); + await user.keyboard('[ArrowDown][ArrowDown]'); + expect(screen.getAllByTestId('radio-wrapper')[2]).toHaveFocus(); }); diff --git a/src/components/Navigation/index.spec.jsx b/src/components/Navigation/index.spec.jsx index 3c41fe41b..d0ecac606 100644 --- a/src/components/Navigation/index.spec.jsx +++ b/src/components/Navigation/index.spec.jsx @@ -1,73 +1,64 @@ import React from 'react'; -import { render, cleanup, fireEvent } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Nav, { NavItem } from '.'; -afterEach(cleanup); - describe('', () => { it('should render with default props', () => { - const { getByTestId, queryByTestId, rerender } = render(); - - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toHaveAttribute('role', 'presentation'); - expect(getByTestId('nav-item-component')).toHaveClass('aui--nav-item'); - expect(getByTestId('nav-item-component')).toHaveClass('active'); - expect(queryByTestId('nav-item-anchor')).not.toBeInTheDocument(); + const view = render(); - rerender(); - expect(getByTestId('nav-item-component')).not.toHaveClass('active'); - }); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-component')).toHaveAttribute('role', 'presentation'); + expect(screen.getByTestId('nav-item-component')).toHaveClass('aui--nav-item'); + expect(screen.getByTestId('nav-item-component')).toHaveClass('active'); + expect(screen.queryByTestId('nav-item-anchor')).not.toBeInTheDocument(); - it('should render the custom className', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toHaveClass('sample-classname'); + view.rerender(); + expect(screen.getByTestId('nav-item-component')).not.toHaveClass('active'); }); it('should render the custom className', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toHaveClass('sample-classname'); + render(); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-component')).toHaveClass('sample-classname'); }); it('should render an anchor element when given `href`', () => { - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(queryByTestId('nav-item-anchor')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toContainElement(getByTestId('nav-item-anchor')); - expect(getByTestId('nav-item-anchor')).toHaveAttribute('href', '#'); - expect(getByTestId('nav-item-anchor')).toHaveAttribute('role', 'button'); + render(); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-anchor')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-component')).toContainElement(screen.getByTestId('nav-item-anchor')); + expect(screen.getByTestId('nav-item-anchor')).toHaveAttribute('href', '#'); + expect(screen.getByTestId('nav-item-anchor')).toHaveAttribute('role', 'button'); }); - it('should trigger `setActiveKey` and `onSelect` when clicking the nav item', () => { + it('should trigger `setActiveKey` and `onSelect` when clicking the nav item', async () => { const onSelect = jest.fn(); - const { getByTestId, queryByTestId } = render(); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - fireEvent.click(getByTestId('nav-item-component')); - + render(); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + await user.click(screen.getByTestId('nav-item-component')); expect(onSelect).toHaveBeenCalledTimes(1); expect(onSelect).toHaveBeenCalledWith('event-key'); }); - it('should render disabled nav item', () => { + it('should render disabled nav item', async () => { const onSelect = jest.fn(); const setActiveKey = jest.fn(); - const { getByTestId, queryByTestId, rerender } = render( + const view = render( ); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toHaveClass('disabled'); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-component')).toHaveClass('disabled'); - fireEvent.click(getByTestId('nav-item-component')); + await user.click(screen.getByTestId('nav-item-component')); expect(setActiveKey).toHaveBeenCalledTimes(0); expect(onSelect).toHaveBeenCalledTimes(0); - rerender(); - expect(queryByTestId('nav-item-component')).toBeInTheDocument(); - expect(getByTestId('nav-item-component')).toHaveClass('disabled'); + view.rerender(); + expect(screen.getByTestId('nav-item-component')).toBeInTheDocument(); + expect(screen.getByTestId('nav-item-component')).toHaveClass('disabled'); - fireEvent.click(getByTestId('nav-item-component')); + await user.click(screen.getByTestId('nav-item-component')); expect(setActiveKey).toHaveBeenCalledTimes(0); expect(onSelect).toHaveBeenCalledTimes(0); }); @@ -84,56 +75,50 @@ describe('
    -
    -`; diff --git a/src/components/Select/index.spec.jsx b/src/components/Select/index.spec.jsx index f62c8e836..7e58f2ad8 100644 --- a/src/components/Select/index.spec.jsx +++ b/src/components/Select/index.spec.jsx @@ -1,12 +1,7 @@ import React from 'react'; -import { render, cleanup, fireEvent, queryAllByAttribute } from '@testing-library/react'; +import { render, screen, user } from 'testing'; import Select from '.'; -afterEach(cleanup); - -const queryAllByDts = queryAllByAttribute.bind(null, 'data-test-selector'); -const queryAllByClass = queryAllByAttribute.bind(null, 'class'); - const defaultOptions = [ { value: 'au', label: 'Australia' }, { value: 'ca', label: 'Canada' }, @@ -14,97 +9,83 @@ const defaultOptions = [ { value: 'uk', label: 'United Kingdom' }, ]; -describe('); - expect(queryByText('Select...')).toBeInTheDocument(); - }); - - it('should have custom option background', () => { - const { getByText, queryByText, queryAllByText } = render( - ); - fireEvent.click(getByText('Australia')); - - expect(queryByText('✕')).toBeInTheDocument(); - expect(getByText('✕')).toHaveClass('select-component__indicator select-component__clear-indicator'); - }); +it('should have base class', () => { + render( - ); +it('should have custom option background', async () => { + render(); + await user.click(screen.getByText('Australia')); - it('should have custom SelectContainer if dts is passed in', () => { - const { container, rerender, getByText, queryByText } = render(); + expect(screen.getAllByClass('select-component__multi-value__label')).toHaveLength(2); + expect(screen.getByText('Australia')).toBeInTheDocument(); + expect(screen.getByText('Australia')).toHaveClass('select-component__multi-value__label'); + expect(screen.getByText('Canada')).toBeInTheDocument(); + expect(screen.getByText('Canada')).toHaveClass('select-component__multi-value__label'); +}); - rerender(); - expect(queryByText('✕')).toBeInTheDocument(); - expect(getByText('✕')).toHaveClass('select-component__indicator select-component__clear-indicator'); - }); + expect(screen.getAllByDts('test-dts')).toHaveLength(1); + expect(screen.getAllByClass('select-component__value-container')).toHaveLength(1); + expect( + screen.getAllByClass( + 'select-component__indicator select-component__dropdown-indicator css-4m2bza-indicatorContainer' + ) + ).toHaveLength(1); - it('should render select options in body if props.isInModal is true', () => { - const { container, rerender } = render( -
    - ); + await user.click(screen.getByText('Australia')); - rerender( -
    - +
    + ); + view.rerender( +
    +