From 21264204def77777c5c27d41d8efa0cd187d0d2f Mon Sep 17 00:00:00 2001 From: Anurag Date: Tue, 10 Nov 2020 12:53:37 +0530 Subject: [PATCH 01/15] test(accordion): refactored accordion test --- src/accordion/__tests__/Accordion.test.tsx | 144 ++++++++++++------ .../__tests__/AccordionState.test.ts | 32 +--- .../__snapshots__/Accordion.test.tsx.snap | 34 ++++- .../__snapshots__/AccordionState.test.ts.snap | 27 ++++ 4 files changed, 155 insertions(+), 82 deletions(-) create mode 100644 src/accordion/__tests__/__snapshots__/AccordionState.test.ts.snap diff --git a/src/accordion/__tests__/Accordion.test.tsx b/src/accordion/__tests__/Accordion.test.tsx index c67a03e82..f2797d3e5 100644 --- a/src/accordion/__tests__/Accordion.test.tsx +++ b/src/accordion/__tests__/Accordion.test.tsx @@ -1,32 +1,40 @@ import * as React from "react"; +import userEvent from "@testing-library/user-event"; import { axe, render, press } from "reakit-test-utils"; import { - AccordionPanel, Accordion, + AccordionPanel, AccordionTrigger, useAccordionState, + AccordionInitialState, } from "../index"; -const AccordionComponent = (props: any) => { +const AccordionComponent = (props: AccordionInitialState) => { const state = useAccordionState(props); return (

- Trigger 1 + trigger 1

- Panel 1 + panel 1

- Trigger 2 + trigger 2

- Panel 2 + panel 2 +

+ trigger 3 +

+ panel 3

- Trigger 3 + + disabled +

- Panel 3 + disabled panel
); }; @@ -42,34 +50,53 @@ describe("Accordion", () => { const { getByText: text } = render(); press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); + expect(text("trigger 1")).toHaveFocus(); + press.ArrowDown(); + expect(text("trigger 2")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 2")).toHaveFocus(); + expect(text("trigger 3")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 3")).toHaveFocus(); + expect(text("disabled")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 3")).toHaveFocus(); + expect(text("disabled")).toHaveFocus(); press.ArrowUp(); - expect(text("Trigger 2")).toHaveFocus(); + expect(text("trigger 3")).toHaveFocus(); press.ArrowUp(); - expect(text("Trigger 1")).toHaveFocus(); + expect(text("trigger 2")).toHaveFocus(); + }); + + it("Accordion should work proper with mouse", () => { + const { getByText: text } = render(); + + expect(text("panel 1")).not.toBeVisible(); + + userEvent.click(text("trigger 1")); + expect(text("panel 1")).toBeVisible(); + + userEvent.click(text("trigger 2")); + expect(text("panel 2")).toBeVisible(); + + userEvent.click(text("trigger 3")); + expect(text("panel 3")).toBeVisible(); }); it("Accordion should have proper keyboard navigation when on loop", () => { const { getByText: text } = render(); press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); + expect(text("trigger 1")).toHaveFocus(); + press.ArrowDown(); + expect(text("trigger 2")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 2")).toHaveFocus(); + expect(text("trigger 3")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 3")).toHaveFocus(); + expect(text("disabled")).toHaveFocus(); press.ArrowDown(); - expect(text("Trigger 1")).toHaveFocus(); + expect(text("trigger 1")).toHaveFocus(); press.ArrowUp(); - expect(text("Trigger 3")).toHaveFocus(); + expect(text("disabled")).toHaveFocus(); press.ArrowUp(); - expect(text("Trigger 2")).toHaveFocus(); + expect(text("trigger 3")).toHaveFocus(); }); it.each([true, false])("Accordion allowToggle: %s", toggle => { @@ -77,70 +104,77 @@ describe("Accordion", () => { , ); + const panel1 = text("panel 1"); + press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); - expect(text("Panel 1")).not.toBeVisible(); + expect(text("trigger 1")).toHaveFocus(); + expect(panel1).not.toBeVisible(); if (toggle) { // if allowToggle is true then pressing again will close it press.Enter(); - expect(text("Panel 1")).toBeVisible(); + expect(panel1).toBeVisible(); press.Enter(); - expect(text("Panel 1")).not.toBeVisible(); + expect(panel1).not.toBeVisible(); } else { // if allowToggle is false then pressing again will close it press.Enter(); - expect(text("Panel 1")).toBeVisible(); + expect(panel1).toBeVisible(); press.Enter(); - expect(text("Panel 1")).toBeVisible(); + expect(panel1).toBeVisible(); } }); it("Accordion should open/close properly", () => { const { getByText: text } = render(); + const panel1 = text("panel 1"); + const panel2 = text("panel 2"); press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); - expect(text("Panel 1")).not.toBeVisible(); - press.Enter(); - expect(text("Panel 1")).toBeVisible(); + expect(text("trigger 1")).toHaveFocus(); + expect(panel1).not.toBeVisible(); + // should work with SPACE too + press.Space(); + expect(panel1).toBeVisible(); // go to next panel press.ArrowDown(); - expect(text("Panel 2")).not.toBeVisible(); + expect(panel2).not.toBeVisible(); press.Enter(); - expect(text("Panel 2")).toBeVisible(); + expect(panel2).toBeVisible(); // panel 1 should be closed now if allowMultiple: false - expect(text("Panel 1")).not.toBeVisible(); + expect(panel1).not.toBeVisible(); }); it("Accordion should open/close properly with AllowMultiple", () => { const { getByText: text } = render(); + const panel1 = text("panel 1"); + const panel2 = text("panel 2"); press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); - expect(text("Panel 1")).not.toBeVisible(); + expect(text("trigger 1")).toHaveFocus(); + expect(panel1).not.toBeVisible(); press.Enter(); - expect(text("Panel 1")).toBeVisible(); + expect(panel1).toBeVisible(); // go to next panel press.ArrowDown(); press.Enter(); - expect(text("Panel 2")).toBeVisible(); + expect(panel2).toBeVisible(); // panel 1 should be visible since allowmultiple is true - expect(text("Panel 1")).toBeVisible(); + expect(panel1).toBeVisible(); }); it("Accordion should have none selected by default", () => { const { getByText: text } = render(); press.Tab(); - expect(text("Panel 1")).not.toBeVisible(); - expect(text("Panel 2")).not.toBeVisible(); - expect(text("Panel 3")).not.toBeVisible(); + expect(text("panel 1")).not.toBeVisible(); + expect(text("panel 2")).not.toBeVisible(); + expect(text("panel 3")).not.toBeVisible(); }); it("Accordion with selectedId given to be selected properly", () => { @@ -149,26 +183,38 @@ describe("Accordion", () => { ); press.Tab(); - expect(text("Panel 1")).not.toBeVisible(); - expect(text("Panel 2")).toBeVisible(); + expect(text("panel 1")).not.toBeVisible(); + expect(text("panel 2")).toBeVisible(); }); it("Accordion manual: false", () => { const { getByText: text } = render(); press.Tab(); - expect(text("Trigger 1")).toHaveFocus(); - expect(text("Panel 1")).toBeVisible(); + expect(text("trigger 1")).toHaveFocus(); + expect(text("panel 1")).toBeVisible(); // go to next panel press.ArrowDown(); - expect(text("Trigger 2")).toHaveFocus(); - expect(text("Panel 2")).toBeVisible(); + expect(text("trigger 2")).toHaveFocus(); + expect(text("panel 2")).toBeVisible(); // go to next panel press.ArrowDown(); - expect(text("Trigger 3")).toHaveFocus(); - expect(text("Panel 3")).toBeVisible(); + expect(text("trigger 3")).toHaveFocus(); + expect(text("panel 3")).toBeVisible(); + }); + + it("Accordion disabled item", () => { + const { getByText: text } = render(); + + press.Tab(); + expect(text("trigger 1")).toHaveFocus(); + press.Enter(); + expect(text("panel 1")).toBeVisible(); + + userEvent.click(text("disabled")); + expect(text("disabled panel")).not.toBeVisible(); }); test("Accordion renders with no a11y violations", async () => { diff --git a/src/accordion/__tests__/AccordionState.test.ts b/src/accordion/__tests__/AccordionState.test.ts index 9af8a5e2c..e4281bdf7 100644 --- a/src/accordion/__tests__/AccordionState.test.ts +++ b/src/accordion/__tests__/AccordionState.test.ts @@ -13,32 +13,10 @@ function render({ .result; } -test("Accordion: initial state", () => { - const result = render(); +describe("useAccordionState", () => { + test("initial state", () => { + const result = render(); - expect(result.current).toMatchInlineSnapshot(` - Object { - "allowMultiple": false, - "allowToggle": false, - "baseId": "base", - "currentId": undefined, - "groups": Array [], - "items": Array [], - "loop": false, - "manual": true, - "orientation": "vertical", - "panels": Array [], - "rtl": false, - "selectedId": null, - "selectedIds": Array [], - "unstable_angular": false, - "unstable_hasActiveWidget": false, - "unstable_idCountRef": Object { - "current": 0, - }, - "unstable_moves": 0, - "unstable_virtual": false, - "wrap": false, - } - `); + expect(result.current).toMatchSnapshot(); + }); }); diff --git a/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap b/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap index 1d1b39604..ded535791 100644 --- a/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +++ b/src/accordion/__tests__/__snapshots__/Accordion.test.tsx.snap @@ -13,7 +13,7 @@ exports[`Accordion should render correctly 1`] = ` tabindex="0" type="button" > - Trigger 1 + trigger 1
- Panel 1 + panel 1

- Panel 2 + panel 2

- Panel 3 + panel 3 +
+

+ +

+ diff --git a/src/accordion/__tests__/__snapshots__/AccordionState.test.ts.snap b/src/accordion/__tests__/__snapshots__/AccordionState.test.ts.snap new file mode 100644 index 000000000..0ebb9c64c --- /dev/null +++ b/src/accordion/__tests__/__snapshots__/AccordionState.test.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`useAccordionState initial state 1`] = ` +Object { + "allowMultiple": false, + "allowToggle": false, + "baseId": "base", + "currentId": undefined, + "groups": Array [], + "items": Array [], + "loop": false, + "manual": true, + "orientation": "vertical", + "panels": Array [], + "rtl": false, + "selectedId": null, + "selectedIds": Array [], + "unstable_angular": false, + "unstable_hasActiveWidget": false, + "unstable_idCountRef": Object { + "current": 0, + }, + "unstable_moves": 0, + "unstable_virtual": false, + "wrap": false, +} +`; From 2e388bb2802030e8338dc88bfaaae78f4573df33 Mon Sep 17 00:00:00 2001 From: Anurag Date: Tue, 10 Nov 2020 13:23:25 +0530 Subject: [PATCH 02/15] test(toast): improved toast test & fixed COUNT --- src/toast/ToastState.ts | 7 +- src/toast/__tests__/Toast.test.tsx | 35 ++--- src/toast/__tests__/ToastState.test.ts | 106 +++++++------- .../__snapshots__/ToastState.test.ts.snap | 131 ++++++++++++++++++ 4 files changed, 203 insertions(+), 76 deletions(-) create mode 100644 src/toast/__tests__/__snapshots__/ToastState.test.ts.snap diff --git a/src/toast/ToastState.ts b/src/toast/ToastState.ts index 717b0079d..9f484e3f9 100644 --- a/src/toast/ToastState.ts +++ b/src/toast/ToastState.ts @@ -45,12 +45,11 @@ interface ToastStateProps { animationTimeout?: number; } -let COUNTER = 0; - export const useToastState = ({ defaultPlacement = "bottom-center", animationTimeout = 0, }: ToastStateProps) => { + const COUNTER = React.useRef(0); const [toasts, setToasts] = React.useState({}); const sortedToasts = getPlacementSortedToasts(toasts); @@ -78,8 +77,8 @@ export const useToastState = ({ autoDismiss, placement = defaultPlacement, }: Partial>) => { - COUNTER = COUNTER + 1; - const id = idProps || `toast-${COUNTER}`; + COUNTER.current = COUNTER.current + 1; + const id = idProps || `toast-${COUNTER.current}`; /* wait until the next frame so we can animate diff --git a/src/toast/__tests__/Toast.test.tsx b/src/toast/__tests__/Toast.test.tsx index c2d5fa01f..ffd494914 100644 --- a/src/toast/__tests__/Toast.test.tsx +++ b/src/toast/__tests__/Toast.test.tsx @@ -29,21 +29,21 @@ const Demo = () => { }); }} > - Error + Error button ); @@ -70,7 +70,7 @@ const ToastComp: React.FC = () => { error: ({ hideToast, content, id }) => { return (
@@ -111,16 +111,16 @@ describe("Toast", () => {
@@ -131,13 +131,15 @@ describe("Toast", () => { it("toast should popup to the screen after click", () => { const { getByText: text, getByTestId: id } = render(); - expect(text("Error")).toBeInTheDocument(); + const errorBtn = text("Error button"); + + expect(errorBtn).toBeInTheDocument(); act(() => { - click(text("Error")); + click(errorBtn); }); - expect(id("error")).toHaveTextContent("This is error"); + expect(id("error-toast")).toHaveTextContent("This is error"); }); it("should be hideToastd after clicking close button", () => { @@ -146,22 +148,23 @@ describe("Toast", () => { getByTestId: getId, queryByTestId: queryId, } = render(); + const errorBtn = text("Error button"); - expect(text("Error")).toBeInTheDocument(); + expect(errorBtn).toBeInTheDocument(); // add first act(() => { - click(text("Error")); + click(errorBtn); }); - expect(getId("error")).toHaveTextContent("This is error"); + expect(getId("error-toast")).toHaveTextContent("This is error"); // let hideToast now act(() => { click(getId("error-close")); }); - expect(queryId("error")).not.toBeInTheDocument(); + expect(queryId("error-toast")).not.toBeInTheDocument(); }); test("Toast renders with no a11y violations", async () => { diff --git a/src/toast/__tests__/ToastState.test.ts b/src/toast/__tests__/ToastState.test.ts index 0911c0de6..1adffde66 100644 --- a/src/toast/__tests__/ToastState.test.ts +++ b/src/toast/__tests__/ToastState.test.ts @@ -2,6 +2,7 @@ import { wait } from "reakit-test-utils"; import { renderHook, act } from "@testing-library/react-hooks"; import { useToastState } from ".."; +import { cleanup } from "@testing-library/react-hooks"; beforeEach(() => { jest.useFakeTimers(); @@ -11,6 +12,7 @@ beforeEach(() => { }); afterEach(() => { + cleanup(); (window.requestAnimationFrame as any).mockRestore(); }); @@ -18,17 +20,17 @@ describe("ToastState", () => { it("should render correctly", () => { const state = renderHook(() => useToastState({})).result; - expect(state.current).toMatchInlineSnapshot(` - Object { - "hideToast": [Function], - "isToastVisible": [Function], - "removeToast": [Function], - "showToast": [Function], - "sortedToasts": Object {}, - "toasts": Object {}, - "toggleToast": [Function], - } - `); + state.current.showToast({ content: "hello world" }); + state.current.showToast({ content: "hello world 2" }); + state.current.showToast({ + content: "hello world 3", + autoDismiss: true, + timeout: 5000, + type: "warning", + placement: "top-right", + }); + + expect(state.current).toMatchSnapshot(); }); it("should add a new toast", () => { @@ -39,55 +41,57 @@ describe("ToastState", () => { act(() => { result.current.showToast({ type: "primary", content: "Hello world" }); }); - expect(Object.values(result.current.toasts)).toMatchObject([ - { - autoDismiss: undefined, - content: "Hello world", - isVisible: true, - placement: "bottom-center", - timeout: undefined, - type: "primary", - }, - ]); + + expect(result.current.toasts).toMatchInlineSnapshot(` + Object { + "toast-1": Object { + "autoDismiss": undefined, + "content": "Hello world", + "id": "toast-1", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "primary", + }, + } + `); }); it("should toggle toast", () => { const { result } = renderHook(() => useToastState({})); - + const toastId = "toast-1"; expect(result.current.toasts).toStrictEqual({}); act(() => { result.current.showToast({ type: "primary", content: "Hello world" }); }); - const id = Object.values(result.current.toasts)[0].id; - act(() => { - result.current.toggleToast({ id, isVisible: false }); + result.current.toggleToast({ id: toastId, isVisible: false }); + }); + + expect(result.current.toasts[toastId]).toMatchObject({ + isVisible: false, }); - expect(result.current.toasts[id]).toMatchObject({ isVisible: false }); }); it("should remove toast", () => { const { result } = renderHook(() => useToastState({})); - expect(result.current.toasts).toStrictEqual({}); act(() => { result.current.showToast({ type: "primary", content: "Hello world" }); }); expect(Object.values(result.current.toasts)).toHaveLength(1); - const id = Object.values(result.current.toasts)[0].id; act(() => { - result.current.removeToast(id); + result.current.removeToast("toast-1"); }); expect(result.current.toasts).toStrictEqual({}); }); it("should hide toast", () => { const { result } = renderHook(() => useToastState({ animationTimeout: 5 })); - let id = ""; expect(result.current.toasts).toStrictEqual({}); @@ -95,21 +99,24 @@ describe("ToastState", () => { result.current.showToast({ type: "primary", content: "Hello world" }); }); expect(Object.values(result.current.toasts)).toHaveLength(1); - id = Object.values(result.current.toasts)[0].id; act(() => { - result.current.hideToast(id); + result.current.hideToast("toast-1"); }); - expect(Object.values(result.current.toasts)).toMatchObject([ - { - autoDismiss: undefined, - content: "Hello world", - isVisible: false, - placement: "bottom-center", - timeout: undefined, - type: "primary", - }, - ]); + + expect(result.current.toasts).toMatchInlineSnapshot(` + Object { + "toast-1": Object { + "autoDismiss": undefined, + "content": "Hello world", + "id": "toast-1", + "isVisible": false, + "placement": "bottom-center", + "timeout": undefined, + "type": "primary", + }, + } + `); // Wait for animation timeout and after that toast should be removed wait( @@ -153,19 +160,6 @@ describe("ToastState", () => { }); }); - const sortedToasts = result.current.sortedToasts; - expect(sortedToasts["top-center"]).toHaveLength(1); - expect(sortedToasts["bottom-center"]).toHaveLength(1); - expect(sortedToasts["bottom-left"]).toHaveLength(2); - expect(sortedToasts["top-right"]).toHaveLength(1); - - expect(sortedToasts["bottom-left"][0]).toMatchObject({ - content: "Hello world 3", - placement: "bottom-left", - }); - expect(sortedToasts["bottom-left"][1]).toMatchObject({ - content: "Hello world 4", - placement: "bottom-left", - }); + expect(result.current.sortedToasts).toMatchSnapshot(); }); }); diff --git a/src/toast/__tests__/__snapshots__/ToastState.test.ts.snap b/src/toast/__tests__/__snapshots__/ToastState.test.ts.snap new file mode 100644 index 000000000..0b5a0f438 --- /dev/null +++ b/src/toast/__tests__/__snapshots__/ToastState.test.ts.snap @@ -0,0 +1,131 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ToastState should render correctly 1`] = ` +Object { + "hideToast": [Function], + "isToastVisible": [Function], + "removeToast": [Function], + "showToast": [Function], + "sortedToasts": Object { + "bottom-center": Array [ + Object { + "autoDismiss": undefined, + "content": "hello world", + "id": "toast-1", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "", + }, + Object { + "autoDismiss": undefined, + "content": "hello world 2", + "id": "toast-2", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "", + }, + ], + "top-right": Array [ + Object { + "autoDismiss": true, + "content": "hello world 3", + "id": "toast-3", + "isVisible": true, + "placement": "top-right", + "timeout": 5000, + "type": "warning", + }, + ], + }, + "toasts": Object { + "toast-1": Object { + "autoDismiss": undefined, + "content": "hello world", + "id": "toast-1", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "", + }, + "toast-2": Object { + "autoDismiss": undefined, + "content": "hello world 2", + "id": "toast-2", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "", + }, + "toast-3": Object { + "autoDismiss": true, + "content": "hello world 3", + "id": "toast-3", + "isVisible": true, + "placement": "top-right", + "timeout": 5000, + "type": "warning", + }, + }, + "toggleToast": [Function], +} +`; + +exports[`ToastState should test getToastToRender 1`] = ` +Object { + "bottom-center": Array [ + Object { + "autoDismiss": undefined, + "content": "Hello world 2", + "id": "toast-2", + "isVisible": true, + "placement": "bottom-center", + "timeout": undefined, + "type": "primary", + }, + ], + "bottom-left": Array [ + Object { + "autoDismiss": undefined, + "content": "Hello world 3", + "id": "toast-3", + "isVisible": true, + "placement": "bottom-left", + "timeout": undefined, + "type": "primary", + }, + Object { + "autoDismiss": undefined, + "content": "Hello world 4", + "id": "toast-4", + "isVisible": true, + "placement": "bottom-left", + "timeout": undefined, + "type": "primary", + }, + ], + "top-center": Array [ + Object { + "autoDismiss": undefined, + "content": "Hello world 1", + "id": "toast-1", + "isVisible": true, + "placement": "top-center", + "timeout": undefined, + "type": "primary", + }, + ], + "top-right": Array [ + Object { + "autoDismiss": undefined, + "content": "Hello world 5", + "id": "toast-5", + "isVisible": true, + "placement": "top-right", + "timeout": undefined, + "type": "primary", + }, + ], +} +`; From c60175e8e011b3d3c3be944ba5c1830056c66084 Mon Sep 17 00:00:00 2001 From: Anurag Date: Tue, 10 Nov 2020 13:32:16 +0530 Subject: [PATCH 03/15] test(live-announcer): refactored live announcer tests --- src/utils/LiveAnnouncer.test.tsx | 48 ++++--------------- .../__snapshots__/LiveAnnouncer.test.tsx.snap | 38 +++++++++++++++ src/utils/utils.test.tsx | 8 ++-- 3 files changed, 50 insertions(+), 44 deletions(-) create mode 100644 src/utils/__snapshots__/LiveAnnouncer.test.tsx.snap diff --git a/src/utils/LiveAnnouncer.test.tsx b/src/utils/LiveAnnouncer.test.tsx index e2e6b6fb3..9e8538ac4 100644 --- a/src/utils/LiveAnnouncer.test.tsx +++ b/src/utils/LiveAnnouncer.test.tsx @@ -16,42 +16,7 @@ describe("LiveAnnouncer", () => { it("should render correctly", () => { announce("Hello world", "assertive", 0); - expect(document.body).toMatchInlineSnapshot(` - -
- - - Hello world - - - -
- - `); + expect(document.body).toMatchSnapshot(); destroyAnnouncer(); @@ -59,6 +24,9 @@ describe("LiveAnnouncer", () => { }); test("LiveRegionAnnouncer", () => { + const assertiveMessage = "Hello Assertive"; + const politeMessage = "Hello Polite"; + const Announcer = () => { const ref = React.useRef(); @@ -67,14 +35,14 @@ describe("LiveAnnouncer", () => { +
+ +