From 873c07774e8ca28cb5665c16dc9e9ea98761a10d Mon Sep 17 00:00:00 2001 From: Damien Robson Date: Thu, 12 Dec 2024 08:05:07 +0000 Subject: [PATCH 1/6] perf(pipeline): update Playwright image to latest --- .github/workflows/playwright.yml | 2 +- playwright-ct.config.ts | 3 +- .../split-button/split-button.pw.tsx | 47 ++- src/components/tabs/tabs.pw.tsx | 115 ------- src/components/tabs/tabs.test.tsx | 130 ++++++++ src/components/text-editor/text-editor.pw.tsx | 296 ++++++++++++------ .../vertical-menu/vertical-menu.pw.tsx | 73 +---- .../vertical-menu/vertical-menu.test.tsx | 109 ++++++- 8 files changed, 481 insertions(+), 294 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 697547f63b..1f7b2d987a 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -12,7 +12,7 @@ jobs: timeout-minutes: 30 runs-on: ubuntu-latest container: - image: mcr.microsoft.com/playwright:v1.47.0-jammy + image: mcr.microsoft.com/playwright:v1.49.1-noble strategy: fail-fast: false matrix: diff --git a/playwright-ct.config.ts b/playwright-ct.config.ts index 0db9bb329f..e1399f06a6 100644 --- a/playwright-ct.config.ts +++ b/playwright-ct.config.ts @@ -1,4 +1,5 @@ import { defineConfig, devices } from "@playwright/experimental-ct-react17"; + import { resolve } from "path"; const playwrightDir = resolve(__dirname, "./playwright"); @@ -30,7 +31,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + trace: "retain-on-failure", /* Port to use for Playwright component endpoint. */ ctPort: 3100, /* Custom config for internal bundler Playwright uses for component tests. See https://playwright.dev/docs/test-components#under-the-hood */ diff --git a/src/components/split-button/split-button.pw.tsx b/src/components/split-button/split-button.pw.tsx index a75285d828..d28fe2814e 100644 --- a/src/components/split-button/split-button.pw.tsx +++ b/src/components/split-button/split-button.pw.tsx @@ -580,6 +580,8 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); await expect(additionalButton(page, 0)).toBeVisible(); await expect(additionalButton(page, 1)).toBeVisible(); await expect(additionalButton(page, 2)).toBeVisible(); @@ -592,14 +594,20 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); - await expect(additionalButton(page, 0)).toBeFocused(); - await page.keyboard.press("Tab"); - await expect(additionalButton(page, 1)).toBeFocused(); - await page.keyboard.press("Tab"); - await expect(additionalButton(page, 2)).toBeFocused(); - await page.keyboard.press("Tab"); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); - await expect(additionalButton(page, 0)).not.toBeVisible(); + const firstButton = buttonList.getByRole("button").first(); + const secondButton = buttonList.getByRole("button").nth(1); + const thirdButton = buttonList.getByRole("button").last(); + + await expect(firstButton).toBeFocused(); + await firstButton.press("Tab"); + await expect(secondButton).toBeFocused(); + await secondButton.press("Tab"); + await expect(thirdButton).toBeFocused(); + await thirdButton.press("Tab"); + await expect(buttonList).toBeHidden(); await expect(mainButton(page).nth(1)).toBeFocused(); }); @@ -610,7 +618,9 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); - await page.waitForTimeout(1000); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); + await page.keyboard.press("ArrowDown"); await page.keyboard.press("ArrowDown"); await page.keyboard.press("ArrowDown"); @@ -625,10 +635,13 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); + await additionalButton(page, 1).focus(); - await page.keyboard.press("Shift+Tab"); + await page.keyboard.press("Shift+Tab", { delay: 1000 }); await expect(additionalButton(page, 0)).toBeFocused(); - await page.keyboard.press("Shift+Tab"); + await page.keyboard.press("Shift+Tab", { delay: 1000 }); await expect(additionalButton(page, 0)).not.toBeVisible(); await expect(splitToggleButton(page).nth(0)).toBeFocused(); @@ -641,12 +654,14 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); await additionalButton(page, 2).focus(); - await page.waitForTimeout(1000); + await page.keyboard.press("ArrowUp"); await page.keyboard.press("ArrowUp"); await page.keyboard.press("ArrowUp"); - await page.waitForTimeout(1000); + await expect(additionalButton(page, 0)).toBeFocused(); }); @@ -657,6 +672,8 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); await additionalButton(page, 2).focus(); await page.keyboard.down("Meta"); await page.keyboard.press("ArrowUp"); @@ -670,6 +687,8 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); await additionalButton(page, 2).focus(); await page.keyboard.down("Control"); await page.keyboard.press("ArrowUp"); @@ -695,6 +714,7 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + await page.keyboard.down("Meta"); await page.keyboard.press("ArrowDown"); await expect(additionalButton(page, 2)).toBeFocused(); @@ -730,6 +750,7 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + await additionalButton(page, 0).click(); await expect(additionalButtonsContainer(page)).toHaveCount(0); }); @@ -741,6 +762,8 @@ test.describe("Functional tests in a custom component", () => { await mount(); await splitToggleButton(page).nth(0).click(); + const buttonList = page.getByRole("list"); + await buttonList.waitFor(); await additionalButton(page, 1).focus(); await page.keyboard.press("Escape"); await expect(additionalButtonsContainer(page)).toHaveCount(0); diff --git a/src/components/tabs/tabs.pw.tsx b/src/components/tabs/tabs.pw.tsx index be51cc58c5..38023343c2 100644 --- a/src/components/tabs/tabs.pw.tsx +++ b/src/components/tabs/tabs.pw.tsx @@ -454,121 +454,6 @@ test.describe("Tabs component", () => { }); }); - test.describe("check events for Tabs component", () => { - test.describe("when position is top", () => { - // TODO: Skipped due to flaky focus behaviour. To review in FE-6428 - test.skip("should call onTabChange callback when click event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).click(); - expect(callbackCount).toBe(1); - }); - - test("should call onTabChange callback when enter key event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).press("Enter"); - expect(callbackCount).toBe(1); - }); - }); - - test.describe("when position is left", () => { - // TODO: Skipped due to flaky focus behaviour. To review in FE-6428 - test.skip("should call onTabChange callback when click event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).click(); - expect(callbackCount).toBe(1); - }); - - test("should call onTabChange callback when enter key event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).press("Enter"); - expect(callbackCount).toBe(1); - }); - }); - - test.describe("when in Sidebar", () => { - // TODO: Skipped due to flaky focus behaviour. To review in FE-6428 - test.skip("should call onTabChange callback when click event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).click(); - expect(callbackCount).toBe(1); - }); - - test("should call onTabChange callback when enter key event is triggered", async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await tabById(page, 2).press("Enter"); - expect(callbackCount).toBe(1); - }); - }); - }); - test.describe("Accessibility tests for Tabs component", () => { test("should pass accessibility tests for Tabs component", async ({ mount, diff --git a/src/components/tabs/tabs.test.tsx b/src/components/tabs/tabs.test.tsx index 4d8e5811cf..c3b0f0e1a1 100644 --- a/src/components/tabs/tabs.test.tsx +++ b/src/components/tabs/tabs.test.tsx @@ -1666,3 +1666,133 @@ test("renders the tabs with the correct size when the `size` prop is set to larg ); expect(screen.getByTestId("tab-container")).toHaveStyle("height: 50px"); }); + +// ported from Playwright +describe("check events for Tabs component", () => { + describe("when position is top", () => { + test("should call onTabChange callback when a click event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + , + ); + + await user.click(screen.getByRole("tab", { name: "Test 2" })); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + + test("should call onTabChange callback when a keyboard Enter press event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + , + ); + const tab2 = screen.getByRole("tab", { name: "Test 2" }); + tab2.focus(); + await user.keyboard("{Enter}"); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + }); + + describe("when position is left", () => { + test("should call onTabChange callback when a click event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + , + ); + await user.click(screen.getByRole("tab", { name: "Test 2" })); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + + test("should call onTabChange callback when a keyboard Enter press event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + , + ); + const tab2 = screen.getByRole("tab", { name: "Test 2" }); + tab2.focus(); + await user.keyboard("{Enter}"); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + }); + + describe("when in a sidebar", () => { + test("should call onTabChange callback when a click event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + + } + > + drawer content + , + ); + await user.click(screen.getByRole("tab", { name: "Test 2" })); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + + test("should call onTabChange callback when a keyboard Enter press event is triggered", async () => { + const onTabChange = jest.fn(); + const user = userEvent.setup(); + render( + + + Content + + + Content + + + } + > + drawer content + , + ); + const tab2 = screen.getByRole("tab", { name: "Test 2" }); + tab2.focus(); + await user.keyboard("{Enter}"); + expect(onTabChange).toHaveBeenCalledWith("2"); + }); + }); +}); diff --git a/src/components/text-editor/text-editor.pw.tsx b/src/components/text-editor/text-editor.pw.tsx index 0cb682136c..3d1cd95bdb 100644 --- a/src/components/text-editor/text-editor.pw.tsx +++ b/src/components/text-editor/text-editor.pw.tsx @@ -72,115 +72,225 @@ test.describe("Functionality tests", () => { }); }); - buttonNames.slice(2, 4).forEach((buttonType) => { - test(`should render text in ${buttonType} style`, async ({ - mount, - page, - }) => { - await mount(); + test(`should render text in bullet-list style`, async ({ mount, page }) => { + await mount(); - const textInput = textEditorInput(page); - const toolbar = textEditorToolbar(page, buttonType); - await toolbar.click(); - await textInput.clear(); - await textInput.type("Testing"); - await page.keyboard.press("Enter"); - await textInput.type("is"); - await page.keyboard.press("Enter"); - await textInput.type("awesome"); + const textInput = textEditorInput(page); + const toolbar = textEditorToolbar(page, "bullet-list"); + await toolbar.click(); + await textInput.clear(); + await textInput.pressSequentially("Testing", { delay: 100 }); + await page.keyboard.press("Enter"); + await textInput.pressSequentially("is", { delay: 100 }); + await page.keyboard.press("Enter"); + await textInput.pressSequentially("awesome", { delay: 100 }); - if (buttonType === "bullet-list") { - await expect(innerTextList(page, "ul", 1)).toHaveText("Testing"); - await expect(innerTextList(page, "ul", 2)).toHaveText("is"); - await expect(innerTextList(page, "ul", 3)).toHaveText("awesome"); - } - if (buttonType === "number-list") { - await expect(innerTextList(page, "ol", 1)).toHaveText("Testing"); - await expect(innerTextList(page, "ol", 2)).toHaveText("is"); - await expect(innerTextList(page, "ol", 3)).toHaveText("awesome"); - } - await expect(toolbar).toHaveCSS("background-color", "rgb(0, 50, 76)"); - }); + await expect(innerTextList(page, "ul", 1)).toHaveText("Testing"); + await expect(innerTextList(page, "ul", 2)).toHaveText("is"); + await expect(innerTextList(page, "ul", 3)).toHaveText("awesome"); + + await expect(toolbar).toHaveCSS("background-color", "rgb(0, 50, 76)"); }); - buttonNames.forEach((buttonType, times) => { - test(`should focus ${buttonType} button using RightArrow keyboard key`, async ({ - mount, - page, - }) => { - await mount(); + test(`should render text in number-list style`, async ({ mount, page }) => { + await mount(); - const textInput = textEditorInput(page); - await textInput.focus(); - await page.keyboard.press("Tab"); - for (let i = 0; i < times; i++) { - await page.keyboard.press("ArrowRight"); - } + const textInput = textEditorInput(page); + const toolbar = textEditorToolbar(page, "number-list"); + await toolbar.click(); + await textInput.clear(); + await textInput.pressSequentially("Testing", { delay: 100 }); + await page.keyboard.press("Enter"); + await textInput.pressSequentially("is", { delay: 100 }); + await page.keyboard.press("Enter"); + await textInput.pressSequentially("awesome", { delay: 100 }); - await expect(textEditorToolbar(page, buttonType)).toBeFocused(); - }); + await expect(innerTextList(page, "ol", 1)).toHaveText("Testing"); + await expect(innerTextList(page, "ol", 2)).toHaveText("is"); + await expect(innerTextList(page, "ol", 3)).toHaveText("awesome"); + + await expect(toolbar).toHaveCSS("background-color", "rgb(0, 50, 76)"); }); - buttonNames.forEach((buttonType, times) => { - test(`should focus ${buttonType} button using ArrowLeft keyboard key`, async ({ - mount, - page, - }) => { - await mount(); + test(`should focus all editor toolbar buttons using ArrowRight keyboard key`, async ({ + mount, + page, + }) => { + await mount(); - const textInput = textEditorInput(page); - await textInput.focus(); - await page.keyboard.press("Tab"); - for (let i = 0; i < buttonNames.length - times; i++) { - await page.keyboard.press("ArrowLeft"); - } + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + // Expect bold to be focused + await expect(textEditorToolbar(page, "bold")).toBeFocused(); + // Expect italic to be focused + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await expect(textEditorToolbar(page, "italic")).toBeFocused(); + // Expect bullet-list to be focused + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await expect(textEditorToolbar(page, "bullet-list")).toBeFocused(); + // Expect number-list to be focused + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await expect(textEditorToolbar(page, "number-list")).toBeFocused(); + }); - await expect(textEditorToolbar(page, buttonType)).toBeFocused(); - }); + test(`should focus all editor toolbar buttons using ArrowLeft keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + // Expect bold to be focused + await expect(textEditorToolbar(page, "bold")).toBeFocused(); + // Expect italic to be focused + await page.keyboard.press("ArrowLeft", { delay: 1000 }); + await expect(textEditorToolbar(page, "number-list")).toBeFocused(); + // Expect bullet-list to be focused + await page.keyboard.press("ArrowLeft", { delay: 1000 }); + await expect(textEditorToolbar(page, "bullet-list")).toBeFocused(); + // Expect number-list to be focused + await page.keyboard.press("ArrowLeft", { delay: 1000 }); + await expect(textEditorToolbar(page, "italic")).toBeFocused(); }); - buttonNames.forEach((buttonType, times) => { - test(`should activate ${buttonType} button using Enter keyboard key`, async ({ - mount, - page, - }) => { - await mount(); + test(`should activate bold button using Enter keyboard key`, async ({ + mount, + page, + }) => { + await mount(); - const textInput = textEditorInput(page); - await textInput.focus(); - await page.keyboard.press("Tab"); - for (let i = 0; i < times; i++) { - await page.keyboard.press("ArrowRight"); - } - await page.keyboard.press("Enter"); + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + await expect(textEditorToolbar(page, "bold")).toBeFocused(); + await page.keyboard.press("Enter", { delay: 1000 }); + await expect(textEditorToolbar(page, "bold")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); - await expect(textEditorToolbar(page, buttonType)).toHaveCSS( - "background-color", - "rgb(0, 50, 76)", - ); - }); + test(`should activate italic button using Enter keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); + + await expect(textEditorToolbar(page, "italic")).toBeFocused(); + await page.keyboard.press("Enter", { delay: 1000 }); + await expect(textEditorToolbar(page, "italic")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); }); - buttonNames.forEach((buttonType, times) => { - test(`should activate ${buttonType} button using Space keyboard key`, async ({ - mount, - page, - }) => { - await mount(); + test(`should activate bullet-list button using Enter keyboard key`, async ({ + mount, + page, + }) => { + await mount(); - const textInput = textEditorInput(page); - await textInput.focus(); - await page.keyboard.press("Tab"); - for (let i = 0; i < times; i++) { - await page.keyboard.press("ArrowRight"); - } - await page.keyboard.press("Space"); + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); - await expect(textEditorToolbar(page, buttonType)).toHaveCSS( - "background-color", - "rgb(0, 50, 76)", - ); - }); + await expect(textEditorToolbar(page, "bullet-list")).toBeFocused(); + await page.keyboard.press("Enter", { delay: 1000 }); + await expect(textEditorToolbar(page, "bullet-list")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); + + test(`should activate number-list button using Enter keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const textInput = textEditorInput(page); + await textInput.click(); + await page.keyboard.press("Tab", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); + await page.keyboard.press("ArrowRight", { delay: 1000 }); + + await expect(textEditorToolbar(page, "number-list")).toBeFocused(); + await page.keyboard.press("Enter", { delay: 1000 }); + await expect(textEditorToolbar(page, "number-list")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); + + test(`should activate bold button using Space keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const boldButton = page.getByRole("button", { name: "bold" }); + await boldButton.press("Space"); + + await expect(textEditorToolbar(page, "bold")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); + + test(`should activate italic button using Space keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const italicButton = page.getByRole("button", { name: "italic" }); + await italicButton.press("Space"); + + await expect(textEditorToolbar(page, "italic")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); + + test(`should activate bullet-list button using Space keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const bulletListButton = page.getByRole("button", { name: "bullet-list" }); + await bulletListButton.press("Space"); + + await expect(textEditorToolbar(page, "bullet-list")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); + }); + + test(`should activate number-list button using Space keyboard key`, async ({ + mount, + page, + }) => { + await mount(); + + const numberListButton = page.getByRole("button", { name: "number-list" }); + await numberListButton.press("Space"); + + await expect(textEditorToolbar(page, "number-list")).toHaveCSS( + "background-color", + "rgb(0, 50, 76)", + ); }); buttonNames.forEach((buttonType, times) => { @@ -256,7 +366,7 @@ test.describe("Functionality tests", () => { const textInput = textEditorInput(page); await textInput.clear(); - await textInput.type(linkText); + await textInput.pressSequentially(linkText, { delay: 100 }); await expect(innerText(page)).toHaveText(linkText); }); @@ -269,7 +379,7 @@ test.describe("Functionality tests", () => { const textInput = textEditorInput(page); await textInput.clear(); - await textInput.type(longText); + await textInput.pressSequentially(longText, { delay: 100 }); await expect(textEditorCounter(page)).toHaveText("0 characters left"); await expect(innerText(page)).toHaveText(longTextAssert); diff --git a/src/components/vertical-menu/vertical-menu.pw.tsx b/src/components/vertical-menu/vertical-menu.pw.tsx index a8a9e1a982..0fcfe3ae58 100644 --- a/src/components/vertical-menu/vertical-menu.pw.tsx +++ b/src/components/vertical-menu/vertical-menu.pw.tsx @@ -284,11 +284,11 @@ test.describe("with beforeEach for VerticalMenuFullScreen", () => { mount, page, }) => { - let callbackCount = 0; + let closeCallbackInvoked = false; await mount( { - callbackCount += 1; + closeCallbackInvoked = true; }} />, ); @@ -296,7 +296,7 @@ test.describe("with beforeEach for VerticalMenuFullScreen", () => { await verticalMenuTrigger(page).click(); await page.keyboard.press("Escape"); - await expect(callbackCount).toBe(1); + await expect(closeCallbackInvoked).toBe(true); }); test(`should render Vertical Menu Full Screen without isOpen prop`, async ({ @@ -599,47 +599,6 @@ test.describe("VerticalMenuFullScreen test background scroll when tabbing", () = }); test.describe("Events test", () => { - test(`should call onClick callback when a click event is triggered`, async ({ - mount, - page, - }) => { - let callbackCount = 0; - await mount( - { - callbackCount += 1; - }} - />, - ); - - await verticalMenuTrigger(page).click(); - - await expect(callbackCount).toBe(1); - }); - - test(`should call onClose callback when a click event is triggered for VerticalMenuFullScreen`, async ({ - mount, - page, - }) => { - let callbackCount = 0; - await page.setViewportSize({ - width: 320, - height: 599, - }); - await mount( - { - callbackCount += 1; - }} - />, - ); - - await verticalMenuTrigger(page).click(); - await closeIconButton(page).click(); - - await expect(callbackCount).toBe(1); - }); - test(`should be available when a Dialog is opened in the background`, async ({ mount, page, @@ -666,32 +625,6 @@ test.describe("Events test", () => { const dialogText = page.getByText("Do you want to leave before saving?"); await expect(dialogText).toBeInViewport(); }); - - [...keysToTrigger].forEach((key) => { - test(`should call onClose callback when a ${key} key event is triggered`, async ({ - mount, - page, - }) => { - let callbackCount = 0; - await page.setViewportSize({ - width: 320, - height: 599, - }); - await mount( - { - callbackCount += 1; - }} - />, - ); - - await verticalMenuTrigger(page).click(); - await closeIconButton(page).focus(); - await page.keyboard.press(key); - - await expect(callbackCount).toBe(1); - }); - }); }); test.describe("should check the accessibility tests", () => { diff --git a/src/components/vertical-menu/vertical-menu.test.tsx b/src/components/vertical-menu/vertical-menu.test.tsx index b573cbf4e2..c74c40d945 100644 --- a/src/components/vertical-menu/vertical-menu.test.tsx +++ b/src/components/vertical-menu/vertical-menu.test.tsx @@ -1,7 +1,13 @@ import React from "react"; import { render, screen } from "@testing-library/react"; - -import { VerticalMenu, VerticalMenuItem } from "."; +import userEvent from "@testing-library/user-event"; + +import { + VerticalMenu, + VerticalMenuFullScreen, + VerticalMenuItem, + VerticalMenuTrigger, +} from "."; import Logger from "../../__internal__/utils/logger"; // mock Logger.deprecate so that no console warnings occur while running the tests @@ -107,4 +113,103 @@ describe("VerticalMenu", () => { expect(menu).toHaveAttribute("data-element", "foo"); expect(menu).toHaveAttribute("data-role", "bar"); }); + + describe("callbacks", () => { + it(`should close the Vertical Menu Full Screen when escape key is pressed`, async () => { + const user = userEvent.setup(); + + const setMockState = jest.fn(); + const useStateMock: any = (useState: any) => [useState, setMockState]; + jest.spyOn(React, "useState").mockImplementation(useStateMock); + + render( + <> + + + + , + , + ); + await user.keyboard("{esc}"); + expect(setMockState).toHaveBeenCalledWith(false); + }); + + it(`should call onClick callback when a click event is triggered and using VerticalMenuTrigger`, async () => { + const user = userEvent.setup(); + + const setMockState = jest.fn(); + const useStateMock: any = (useState: any) => [useState, setMockState]; + jest.spyOn(React, "useState").mockImplementation(useStateMock); + + render( + + Menu + , + ); + await user.click(screen.getByText("Menu")); + expect(setMockState).toHaveBeenCalledWith(false); + }); + + it(`should call onClose callback when a click event is triggered`, async () => { + const user = userEvent.setup(); + + const setMockState = jest.fn(); + const useStateMock: any = (useState: any) => [useState, setMockState]; + jest.spyOn(React, "useState").mockImplementation(useStateMock); + + render( + <> + + + + , + , + ); + const closeBtn = screen.getByRole("button"); + await user.click(closeBtn); + expect(setMockState).toHaveBeenCalledWith(false); + }); + + it(`should call onClose callback when a Space key event is triggered`, async () => { + const user = userEvent.setup(); + + const setMockState = jest.fn(); + const useStateMock: any = (useState: any) => [useState, setMockState]; + jest.spyOn(React, "useState").mockImplementation(useStateMock); + + render( + <> + + + + , + , + ); + const closeBtn = screen.getByRole("button"); + closeBtn.focus(); + await user.keyboard("{Space}"); + expect(setMockState).toHaveBeenCalledWith(false); + }); + + it(`should call onClose callback when a Enter key event is triggered`, async () => { + const user = userEvent.setup(); + + const setMockState = jest.fn(); + const useStateMock: any = (useState: any) => [useState, setMockState]; + jest.spyOn(React, "useState").mockImplementation(useStateMock); + + render( + <> + + + + , + , + ); + const closeBtn = screen.getByRole("button"); + closeBtn.focus(); + await user.keyboard("{enter}"); + expect(setMockState).toHaveBeenCalledWith(false); + }); + }); }); From 18a401200d4f209c5cfca97249056014c33401b2 Mon Sep 17 00:00:00 2001 From: James Parslow Date: Mon, 9 Dec 2024 17:47:33 +0000 Subject: [PATCH 2/6] test: wrap interactions that update state with act wrapper in preparation for consuming latest version of React Testing Library and its sibling packages --- .../checkable-input/checkable-input.test.tsx | 10 +- src/__internal__/fieldset/fieldset.test.tsx | 13 +- .../focus-trap/focus-trap.test.tsx | 157 +++++++++++++----- .../input-icon-toggle.test.tsx | 17 +- .../validations/validation-icon.test.tsx | 18 +- src/components/accordion/accordion.test.tsx | 3 +- .../action-popover/action-popover.test.tsx | 3 +- .../advanced-color-picker.test.tsx | 31 +++- src/components/badge/badge.test.tsx | 10 +- .../batch-selection/batch-selection.test.tsx | 2 + src/components/date/date.test.tsx | 4 +- src/components/decimal/decimal.test.tsx | 102 +++++++++--- .../dialog-full-screen.test.tsx | 29 ++-- src/components/dialog/dialog.test.tsx | 9 +- .../duelling-picklist.test.tsx | 10 +- .../picklist-group/picklist-group.test.tsx | 22 ++- .../flat-table-checkbox.test.tsx | 17 +- src/components/flat-table/flat-table.test.tsx | 26 ++- src/components/help/help.test.tsx | 14 +- src/components/link/link.test.tsx | 14 +- .../menu/menu-item/menu-item.test.tsx | 81 ++++++--- src/components/menu/menu.test.tsx | 26 ++- src/components/modal/modal.test.tsx | 26 ++- .../numeral-date/numeral-date.test.tsx | 12 +- src/components/pages/pages.test.tsx | 39 +++-- src/components/pod/pod.test.tsx | 90 ++++++---- .../popover-container.test.tsx | 17 +- src/components/portrait/portrait.test.tsx | 12 +- src/components/profile/profile.test.tsx | 2 +- src/components/search/search.test.tsx | 30 ++-- .../select-list/select-list.test.tsx | 8 +- .../select-textbox/select-textbox.test.tsx | 16 +- .../filterable-select.test.tsx | 97 ++++++++--- .../select/multi-select/multi-select.test.tsx | 14 +- src/components/sidebar/sidebar.test.tsx | 23 ++- .../simple-color-picker.test.tsx | 47 +++--- .../__internal__/tab-title/tab-title.test.tsx | 39 +++-- src/components/tabs/tabs.test.tsx | 74 ++++++--- .../__internal__/toolbar/toolbar.test.tsx | 45 +++-- .../text-editor/text-editor.test.tsx | 32 +++- src/components/textarea/textarea.test.tsx | 23 ++- src/components/textbox/textbox.test.tsx | 23 ++- .../__internal__/accordion/accordion.test.tsx | 3 +- src/components/time/time.test.tsx | 23 ++- src/components/toast/toast.test.tsx | 46 +++-- .../useScrollBlock/useScrollBlock.test.tsx | 3 +- 46 files changed, 955 insertions(+), 407 deletions(-) diff --git a/src/__internal__/checkable-input/checkable-input.test.tsx b/src/__internal__/checkable-input/checkable-input.test.tsx index 39729cc2d6..a78c58ad8f 100644 --- a/src/__internal__/checkable-input/checkable-input.test.tsx +++ b/src/__internal__/checkable-input/checkable-input.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import CheckableInput from "."; test("renders `label` with expected id when `id` prop is passed", () => { @@ -40,7 +40,9 @@ test("renders input with 'aria-describedby' as the id of the validation tooltip expect(input).not.toHaveAttribute("aria-describedby"); - input.focus(); + act(() => { + input.focus(); + }); expect(input).toHaveAttribute("aria-describedby", "foo-validation"); }); @@ -59,7 +61,9 @@ test("appends the id of the validation tooltip to the input's 'aria-describedby' expect(input).toHaveAttribute("aria-describedby", "foo-field-help"); - input.focus(); + act(() => { + input.focus(); + }); expect(input).toHaveAttribute( "aria-describedby", diff --git a/src/__internal__/fieldset/fieldset.test.tsx b/src/__internal__/fieldset/fieldset.test.tsx index 7184bcb9c1..a9c5f2cb53 100644 --- a/src/__internal__/fieldset/fieldset.test.tsx +++ b/src/__internal__/fieldset/fieldset.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen, within } from "@testing-library/react"; +import { act, render, screen, within } from "@testing-library/react"; import Fieldset from "."; import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils"; @@ -96,11 +96,16 @@ test("sets `aria-describedby` on help icon as tooltip content when focused and r , ); - const help = screen.getByRole("button", { name: "help" }); - help.focus(); + + act(() => { + help.focus(); + }); expect(help).toHaveAccessibleDescription("label help"); - help.blur(); + + act(() => { + help.blur(); + }); expect(help).not.toHaveAttribute("aria-describedby"); }); diff --git a/src/__internal__/focus-trap/focus-trap.test.tsx b/src/__internal__/focus-trap/focus-trap.test.tsx index 10b2e1fac7..a9ea26a40b 100644 --- a/src/__internal__/focus-trap/focus-trap.test.tsx +++ b/src/__internal__/focus-trap/focus-trap.test.tsx @@ -5,11 +5,10 @@ import { fireEvent, createEvent, waitFor, + act, } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { act } from "react-dom/test-utils"; - import FocusTrap, { FocusTrapProps } from "./focus-trap.component"; import { RadioButton, RadioButtonGroup } from "../../components/radio-button"; import ModalContext from "../../components/modal/__internal__/modal.context"; @@ -156,8 +155,10 @@ test("refocuses the last element that had focus within the trap when `triggerRef }), ); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); - buttonTwo.blur(); + act(() => { + buttonTwo.focus(); + buttonTwo.blur(); + }); rerender( mockComponentToRender({ autoFocus: false, triggerRefocusFlag: true }), @@ -209,7 +210,9 @@ test("when `triggerRefocusFlag` is set, the container is refocused if last eleme , ); - screen.getByRole("button", { name: "Two" }).focus(); + act(() => { + screen.getByRole("button", { name: "Two" }).focus(); + }); rerender( @@ -313,7 +316,9 @@ describe("when FocusTrap wraps an element and element has focusable items inside render(mockComponentToRender()); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.keyboard("{ArrowDown}"); expect(buttonTwo).toHaveFocus(); @@ -324,7 +329,9 @@ describe("when FocusTrap wraps an element and element has focusable items inside render(mockComponentToRender()); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab({ shift: true }); const buttonTwo = screen.getByRole("button", { name: "Two" }); @@ -336,7 +343,9 @@ describe("when FocusTrap wraps an element and element has focusable items inside render(mockComponentToRender()); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); const buttonOne = screen.getByRole("button", { name: "One" }); @@ -348,7 +357,9 @@ describe("when FocusTrap wraps an element and element has focusable items inside render(mockComponentToRender()); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); const buttonTwo = screen.getByRole("button", { name: "Two" }); @@ -360,7 +371,9 @@ describe("when FocusTrap wraps an element and element has focusable items inside render(mockComponentToRender()); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab(); const buttonOne = screen.getByRole("button", { name: "One" }); @@ -406,7 +419,9 @@ it("only allows non-disabled elements to be focused", async () => { ); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); const buttonTwo = screen.getByRole("button", { name: "Two" }); @@ -432,7 +447,9 @@ describe("when first focusable elements are radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Red").focus(); + act(() => { + screen.getByLabelText("Red").focus(); + }); await user.tab({ shift: true }); expect(screen.getByRole("button", { name: "Two" })).toHaveFocus(); @@ -442,7 +459,9 @@ describe("when first focusable elements are radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Green").focus(); + act(() => { + screen.getByLabelText("Green").focus(); + }); await user.tab({ shift: true }); expect(screen.getByRole("button", { name: "Two" })).toHaveFocus(); @@ -469,7 +488,9 @@ describe("with 2 different radio groups", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Apple").focus(); + act(() => { + screen.getByLabelText("Apple").focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -479,7 +500,9 @@ describe("with 2 different radio groups", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Melon").focus(); + act(() => { + screen.getByLabelText("Melon").focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -506,7 +529,9 @@ describe("with 2 different focusable radio groups and a custom selector", () => const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Apple").focus(); + act(() => { + screen.getByLabelText("Apple").focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -516,7 +541,9 @@ describe("with 2 different focusable radio groups and a custom selector", () => const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Melon").focus(); + act(() => { + screen.getByLabelText("Melon").focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -539,7 +566,9 @@ describe("when last focusable elements are radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Red").focus(); + act(() => { + screen.getByLabelText("Red").focus(); + }); await user.tab(); expect(screen.getByRole("button", { name: "One" })).toHaveFocus(); @@ -549,7 +578,9 @@ describe("when last focusable elements are radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Green").focus(); + act(() => { + screen.getByLabelText("Green").focus(); + }); await user.tab(); expect(screen.getByRole("button", { name: "One" })).toHaveFocus(); @@ -572,7 +603,9 @@ describe("when trap contains radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Red").focus(); + act(() => { + screen.getByLabelText("Red").focus(); + }); await user.tab({ shift: true }); expect(screen.getByRole("button", { name: "One" })).toHaveFocus(); @@ -582,7 +615,9 @@ describe("when trap contains radio buttons", () => { const user = userEvent.setup({ delay: null }); render(); - screen.getByLabelText("Green").focus(); + act(() => { + screen.getByLabelText("Green").focus(); + }); await user.tab({ shift: true }); expect(screen.getByRole("button", { name: "One" })).toHaveFocus(); @@ -593,7 +628,9 @@ describe("when trap contains radio buttons", () => { render(); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(screen.getByLabelText("Red")).toHaveFocus(); @@ -606,7 +643,9 @@ describe("when trap contains radio buttons", () => { const greenRadio = screen.getByLabelText("Green"); await user.click(greenRadio); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(greenRadio).toHaveFocus(); @@ -617,7 +656,9 @@ describe("when trap contains radio buttons", () => { render(); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -630,7 +671,9 @@ describe("when trap contains radio buttons", () => { const greenRadio = screen.getByLabelText("Green"); await user.click(greenRadio); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); expect(greenRadio).toHaveFocus(); @@ -654,7 +697,9 @@ describe("when trap contains radio buttons when using a custom selector", () => render(); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(screen.getByLabelText("Red")).toHaveFocus(); @@ -667,7 +712,9 @@ describe("when trap contains radio buttons when using a custom selector", () => const greenRadio = screen.getByLabelText("Green"); await user.click(greenRadio); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(greenRadio).toHaveFocus(); @@ -678,7 +725,9 @@ describe("when trap contains radio buttons when using a custom selector", () => render(); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); expect(screen.getByLabelText("Green")).toHaveFocus(); @@ -691,7 +740,9 @@ describe("when trap contains radio buttons when using a custom selector", () => const greenRadio = screen.getByLabelText("Green"); await user.click(greenRadio); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); expect(greenRadio).toHaveFocus(); @@ -741,7 +792,9 @@ describe("when trap contains only one focusable element according to a custom se render(); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab(); expect(screen.getByRole("button", { name: "Two" })).toHaveFocus(); @@ -752,7 +805,9 @@ describe("when trap contains only one focusable element according to a custom se render(); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonTwo.focus(); + act(() => { + buttonTwo.focus(); + }); await user.tab({ shift: true }); expect(screen.getByRole("button", { name: "Two" })).toHaveFocus(); @@ -851,7 +906,9 @@ test("when `additionalWrapperRefs` are specified, tab should cycle through focus const user = userEvent.setup({ delay: null }); render(); - screen.getByRole("button", { name: BUTTON_IN_WRAPPER }).focus(); + act(() => { + screen.getByRole("button", { name: BUTTON_IN_WRAPPER }).focus(); + }); await user.tab(); expect( @@ -871,7 +928,9 @@ test("when `additionalWrapperRefs` are specified, shift-tab should cycle through const user = userEvent.setup({ delay: null }); render(); - screen.getByRole("button", { name: BUTTON_IN_WRAPPER }).focus(); + act(() => { + screen.getByRole("button", { name: BUTTON_IN_WRAPPER }).focus(); + }); await user.tab({ shift: true }); expect( @@ -1087,7 +1146,9 @@ test("only focuses elements which meet the custom selector, when tabbing both fo const buttonOne = screen.getByRole("button", { name: "One" }); const buttonThree = screen.getByRole("button", { name: "Three" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(buttonThree).toHaveFocus(); @@ -1115,7 +1176,9 @@ test("when multiple focus traps are open at once, focus moves correctly between ); const buttonOne = screen.getByRole("button", { name: "One" }); const buttonTwo = screen.getByRole("button", { name: "Two" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(buttonTwo).toHaveFocus(); @@ -1125,7 +1188,9 @@ test("when multiple focus traps are open at once, focus moves correctly between const buttonThree = screen.getByRole("button", { name: "Three" }); const buttonFour = screen.getByRole("button", { name: "Four" }); - buttonThree.focus(); + act(() => { + buttonThree.focus(); + }); await user.tab(); expect(buttonFour).toHaveFocus(); @@ -1155,7 +1220,9 @@ test("when multiple focus traps are open at once, focus moves correctly between , ); const buttonOne = screen.getByRole("button", { name: "One" }); - buttonOne.focus(); + act(() => { + buttonOne.focus(); + }); await user.tab(); expect(screen.getByRole("button", { name: "Two" })).toHaveFocus(); @@ -1167,7 +1234,9 @@ test("when multiple focus traps are open at once, focus moves correctly between expect(buttonOne).toHaveFocus(); const buttonFour = screen.getByRole("button", { name: "Four" }); - buttonFour.focus(); + act(() => { + buttonFour.focus(); + }); await user.tab(); expect(screen.getByRole("button", { name: "Six" })).toHaveFocus(); @@ -1222,7 +1291,9 @@ test("should focus the first focusable element when the the focus is on a non fo , ); - screen.getByRole("button", { name: "Three" }).focus(); + act(() => { + screen.getByRole("button", { name: "Three" }).focus(); + }); await user.tab(); @@ -1240,7 +1311,9 @@ test("should focus the last focusable element when the the focus is on a non foc , ); - screen.getByRole("button", { name: "One" }).focus(); + act(() => { + screen.getByRole("button", { name: "One" }).focus(); + }); await user.tab({ shift: true }); @@ -1378,7 +1451,7 @@ test("should focus the first input that has the `autoFocus` prop set on it", () - + {}} /> , ); @@ -1392,7 +1465,7 @@ test("should loop to the last element when there is elements with tabIndex of -1 - + {}} /> , ); diff --git a/src/__internal__/input-icon-toggle/input-icon-toggle.test.tsx b/src/__internal__/input-icon-toggle/input-icon-toggle.test.tsx index 0f25a273fa..2af12bd893 100644 --- a/src/__internal__/input-icon-toggle/input-icon-toggle.test.tsx +++ b/src/__internal__/input-icon-toggle/input-icon-toggle.test.tsx @@ -1,5 +1,11 @@ import React from "react"; -import { render, screen, createEvent, fireEvent } from "@testing-library/react"; +import { + render, + screen, + createEvent, + fireEvent, + act, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import * as floatingUi from "@floating-ui/react-dom"; import InputIconToggle, { InputIconToggleProps } from "."; @@ -310,7 +316,9 @@ test("calls `onFocus` handler when the validation icon is focused", async () => ); const validationIcon = screen.getByTestId("icon-error"); - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); expect(mockOnFocus).toHaveBeenCalled(); }); @@ -323,8 +331,9 @@ test("calls `onBlur` handler when the validation icon loses focus", async () => const validationIcon = screen.getByTestId("icon-error"); const user = userEvent.setup(); - - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); await user.tab(); expect(mockOnBlur).toHaveBeenCalled(); diff --git a/src/__internal__/validations/validation-icon.test.tsx b/src/__internal__/validations/validation-icon.test.tsx index f8ace50efa..2eac0bfcc2 100644 --- a/src/__internal__/validations/validation-icon.test.tsx +++ b/src/__internal__/validations/validation-icon.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { render, screen, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import ValidationIcon from "./validation-icon.component"; @@ -122,7 +122,9 @@ test("renders a tooltip when the validation icon is focused", () => { render(); const validationIcon = screen.getByTestId("icon-error"); - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); const tooltip = screen.getByRole("tooltip"); expect(tooltip).toBeVisible(); @@ -134,7 +136,9 @@ test("renders a tooltip when validation icon is focused, then is not rendered on const user = userEvent.setup(); const validationIcon = screen.getByTestId("icon-error"); - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); const tooltip = screen.getByRole("tooltip"); expect(tooltip).toBeVisible(); @@ -146,7 +150,9 @@ test("sets the 'id' attribute on the tooltip via the `tooltipId` prop on the val render(); const validationIcon = screen.getByTestId("icon-error"); - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); const tooltip = screen.getByRole("tooltip"); expect(tooltip).toHaveAttribute("id", "foo"); @@ -157,7 +163,9 @@ test("triggers a passed function via the `onFocus` prop when the validation icon render(); const validationIcon = screen.getByTestId("icon-error"); - validationIcon.focus(); + act(() => { + validationIcon.focus(); + }); expect(mockOnFocus).toHaveBeenCalled(); }); diff --git a/src/components/accordion/accordion.test.tsx b/src/components/accordion/accordion.test.tsx index 45d8d2f08d..fee70774c1 100644 --- a/src/components/accordion/accordion.test.tsx +++ b/src/components/accordion/accordion.test.tsx @@ -1,6 +1,5 @@ import React from "react"; -import { act } from "react-dom/test-utils"; -import { render, screen } from "@testing-library/react"; +import { render, screen, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { StyledAccordionHeadingsContainer } from "./accordion.style"; diff --git a/src/components/action-popover/action-popover.test.tsx b/src/components/action-popover/action-popover.test.tsx index 49dc114f81..4725f19198 100644 --- a/src/components/action-popover/action-popover.test.tsx +++ b/src/components/action-popover/action-popover.test.tsx @@ -1,8 +1,7 @@ import React from "react"; -import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; import * as floatingUi from "@floating-ui/dom"; -import { render, screen } from "@testing-library/react"; +import { render, screen, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils"; import sageTheme from "../../style/themes/sage"; diff --git a/src/components/advanced-color-picker/advanced-color-picker.test.tsx b/src/components/advanced-color-picker/advanced-color-picker.test.tsx index 0dfccd2bc9..b668db9b32 100644 --- a/src/components/advanced-color-picker/advanced-color-picker.test.tsx +++ b/src/components/advanced-color-picker/advanced-color-picker.test.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import userEvent from "@testing-library/user-event"; -import { render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen, waitFor } from "@testing-library/react"; import AdvancedColorPicker, { AdvancedColorPickerProps, } from "./advanced-color-picker.component"; @@ -236,7 +236,9 @@ test.each([ await user.click(screen.getByRole("button", { name: "Change colour" })); expect(await screen.findByRole("dialog")).toBeVisible(); - screen.getByRole("radio", { name: "pink" }).focus(); + act(() => { + screen.getByRole("radio", { name: "pink" }).focus(); + }); await user.keyboard(keyCode); await waitFor(() => { @@ -255,9 +257,13 @@ test.each(["a", "b", "q", "t", "x", "4", "0"])( await user.click(screen.getByRole("button", { name: "Change colour" })); expect(await screen.findByRole("dialog")).toBeVisible(); - screen.getByRole("radio", { name: "pink" }).focus(); + act(() => { + screen.getByRole("radio", { name: "pink" }).focus(); + }); await user.keyboard(key); - jest.runAllTimers(); + act(() => { + jest.runAllTimers(); + }); expect(screen.getByRole("dialog")).toBeVisible(); }, @@ -269,8 +275,11 @@ test("tabbing from the close button should focus the selected color input", asyn render(); await user.click(screen.getByRole("button", { name: "Change colour" })); - screen.getByRole("button", { name: "Close" }).focus(); + act(() => { + screen.getByRole("button", { name: "Close" }).focus(); + }); await user.keyboard("{Tab}"); + expect(screen.getByRole("radio", { name: "orchid" })).toHaveFocus(); }); @@ -294,7 +303,9 @@ test("shift-tabbing from the close button should focus the selected color input" render(); await user.click(screen.getByRole("button", { name: "Change colour" })); - screen.getByRole("button", { name: "Close" }).focus(); + act(() => { + screen.getByRole("button", { name: "Close" }).focus(); + }); await user.keyboard("{Shift>}{Tab}"); expect(screen.getByRole("radio", { name: "orchid" })).toHaveFocus(); }); @@ -343,7 +354,9 @@ test("when the user closes the component, it does trigger the onBlur callback", expect(await screen.findByRole("radio", { name: "white" })).toHaveFocus(); await user.click(screen.getByRole("button", { name: "Close" })); - jest.runAllTimers(); + act(() => { + jest.runAllTimers(); + }); expect(onBlur).toHaveBeenCalledTimes(1); expect(onBlur.mock.calls[0][0].target).toHaveAccessibleName("white"); @@ -363,7 +376,9 @@ test("when another color input is clicked, it does not trigger the onBlur callba expect(await screen.findByRole("radio", { name: "white" })).toHaveFocus(); await user.click(screen.getByRole("radio", { name: "pink" })); - jest.runAllTimers(); + act(() => { + jest.runAllTimers(); + }); expect(onBlur).toHaveBeenCalledTimes(0); }); diff --git a/src/components/badge/badge.test.tsx b/src/components/badge/badge.test.tsx index c0d4f0da44..4b907af20f 100644 --- a/src/components/badge/badge.test.tsx +++ b/src/components/badge/badge.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Badge from "./badge.component"; @@ -43,11 +43,15 @@ describe("Badge", () => { const badgeButton = screen.getByRole("button"); const badgeText = screen.getByText("9"); - badgeButton.focus(); + act(() => { + badgeButton.focus(); + }); expect(badgeText).not.toBeVisible(); - badgeButton.blur(); + act(() => { + badgeButton.blur(); + }); expect(badgeText).toBeVisible(); }); diff --git a/src/components/batch-selection/batch-selection.test.tsx b/src/components/batch-selection/batch-selection.test.tsx index cba29f6a1a..b4e8965769 100644 --- a/src/components/batch-selection/batch-selection.test.tsx +++ b/src/components/batch-selection/batch-selection.test.tsx @@ -78,6 +78,7 @@ test("`ButtonMinor` children should be automatically disabled via context", () = test("`Link` children should be automatically disabled via context", () => { render( + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} Link as an anchor , ); @@ -94,6 +95,7 @@ test("`Link` children should be automatically disabled via context", () => { test("`Link` children rendered as a button should be automatically disabled via context", () => { render( + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} {}}>Link as a button , ); diff --git a/src/components/date/date.test.tsx b/src/components/date/date.test.tsx index dbb9592072..72d4dad0aa 100644 --- a/src/components/date/date.test.tsx +++ b/src/components/date/date.test.tsx @@ -1668,6 +1668,6 @@ test("should select the correct date when the locale is overridden and a date is await user.type(input, "05/04"); jest.advanceTimersByTime(10); - const grid = screen.getByRole("status").textContent; - expect(grid).toEqual("April 2019"); + const caption = screen.getByRole("status"); + expect(caption).toHaveTextContent("April 2019"); }); diff --git a/src/components/decimal/decimal.test.tsx b/src/components/decimal/decimal.test.tsx index 6daf960931..06bde1d166 100644 --- a/src/components/decimal/decimal.test.tsx +++ b/src/components/decimal/decimal.test.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Decimal from "./decimal.component"; @@ -426,7 +426,9 @@ describe("when the component is uncontrolled", () => { const user = userEvent.setup(); render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); (screen.getByRole("textbox") as HTMLInputElement).select(); await user.paste(pastedText); @@ -473,7 +475,9 @@ describe("when the component is uncontrolled", () => { const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowLeft}"); await user.keyboard("-"); @@ -487,7 +491,9 @@ describe("when the component is uncontrolled", () => { const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowRight}"); await user.keyboard("-"); @@ -546,7 +552,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox") as HTMLInputElement; - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); decimalInput.setSelectionRange(selectionStart, selectionEnd); await user.keyboard("{Backspace}"); @@ -561,7 +569,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowLeft}"); await user.keyboard("{Backspace}"); @@ -574,7 +584,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowRight}"); await user.keyboard("{Backspace}"); @@ -633,7 +645,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox") as HTMLInputElement; - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); decimalInput.setSelectionRange(selectionStart, selectionEnd); await user.keyboard("{Delete}"); @@ -648,7 +662,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowLeft}"); await user.keyboard("{Delete}"); @@ -661,7 +677,9 @@ describe("when the component is uncontrolled", () => { render(); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{ArrowRight}"); await user.keyboard("{Delete}"); @@ -689,7 +707,9 @@ describe("when the component is uncontrolled", () => { const onKeyDown = jest.fn(); render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{ArrowRight}"); await user.keyboard("1"); @@ -724,7 +744,9 @@ describe("when the component is uncontrolled", () => { const onChange = jest.fn(); render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(onChange).not.toHaveBeenCalled(); @@ -821,7 +843,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -840,7 +864,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -952,7 +978,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -971,7 +999,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -1011,7 +1041,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -1030,7 +1062,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -1103,7 +1137,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -1122,7 +1158,9 @@ describe("when the component is uncontrolled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.keyboard("{Delete}"); await user.tab(); @@ -1148,7 +1186,9 @@ describe("when the component is controlled", () => { const onChange = jest.fn(); render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(onChange).not.toHaveBeenCalled(); @@ -1176,7 +1216,9 @@ describe("when the component is controlled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(screen.getByRole("textbox")).toHaveValue("0"); @@ -1193,7 +1235,9 @@ describe("when the component is controlled", () => { />, ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(screen.getByRole("textbox")).toHaveValue("0.0"); @@ -1280,7 +1324,9 @@ describe("when the component is controlled", () => { ); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{Backspace}"); await user.tab(); @@ -1304,7 +1350,9 @@ describe("when the component is controlled", () => { render(); const decimalInput = screen.getByRole("textbox"); - decimalInput.focus(); + act(() => { + decimalInput.focus(); + }); await user.keyboard("{Backspace}"); await user.tab(); @@ -1370,7 +1418,9 @@ test("when wrapped in an I18nProvider, the appropriate locale is used, and the f , ); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(screen.getByRole("textbox")).toHaveValue("0.00"); }); diff --git a/src/components/dialog-full-screen/dialog-full-screen.test.tsx b/src/components/dialog-full-screen/dialog-full-screen.test.tsx index 600d93893d..1383b17f23 100644 --- a/src/components/dialog-full-screen/dialog-full-screen.test.tsx +++ b/src/components/dialog-full-screen/dialog-full-screen.test.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import { + act, render, screen, waitFor, @@ -85,10 +86,12 @@ test("the dialog container should not be focused when the dialog opens if the di , ); - // need to use fake timers here rather than waitFor to ensure that the test fails if the disableAutoFocus functionality - // gets broken - using waitFor would always pass as the dialog is always initially unfocused. To be sure focus doesn't - // happen we need to let all timers run. - jest.runAllTimers(); + act(() => { + // need to use fake timers here rather than waitFor to ensure that the test fails if the disableAutoFocus functionality + // gets broken - using waitFor would always pass as the dialog is always initially unfocused. To be sure focus doesn't + // happen we need to let all timers run. + jest.runAllTimers(); + }); expect(screen.getByRole("dialog")).not.toHaveFocus(); @@ -389,7 +392,9 @@ test("the onCancel callback should be called when the enter key is pressed", asy const onCancel = jest.fn(); render(); - screen.getByRole("button", { name: "Close" }).focus(); + act(() => { + screen.getByRole("button", { name: "Close" }).focus(); + }); await user.keyboard("{Enter}"); await waitForElementToBeRemoved(() => screen.queryByRole("dialog")); @@ -402,13 +407,17 @@ test("the onCancel callback should not be called when a non-Enter key is pressed const onCancel = jest.fn(); render(); - screen.getByRole("button", { name: "Close" }).focus(); + act(() => { + screen.getByRole("button", { name: "Close" }).focus(); + }); await user.keyboard("a"); - // need to use fake timers here rather than waitFor to ensure that the test fails if this feature ever - // gets broken - using waitFor would always pass as the dialog is already visible (and onCancel not called) - // at this point - jest.runAllTimers(); + act(() => { + // need to use fake timers here rather than waitFor to ensure that the test fails if this feature ever + // gets broken - using waitFor would always pass as the dialog is already visible (and onCancel not called) + // at this point + jest.runAllTimers(); + }); expect(screen.getByRole("dialog")).toBeVisible(); expect(onCancel).not.toHaveBeenCalled(); diff --git a/src/components/dialog/dialog.test.tsx b/src/components/dialog/dialog.test.tsx index e508b6218f..fb26366100 100644 --- a/src/components/dialog/dialog.test.tsx +++ b/src/components/dialog/dialog.test.tsx @@ -4,6 +4,7 @@ import { screen, within, waitForElementToBeRemoved, + act, } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; @@ -185,7 +186,7 @@ describe("closing behaviour", () => { ); const closeButton = screen.getByRole("button", { name: /Close/i }); - closeButton.focus(); + act(() => closeButton.focus()); await user.keyboard("{Enter}"); await waitForElementToBeRemoved(() => screen.queryByRole("dialog")); @@ -202,7 +203,7 @@ describe("closing behaviour", () => { ); const closeButton = screen.getByRole("button", { name: /Close/i }); - closeButton.focus(); + act(() => closeButton.focus()); await user.keyboard("{ }"); await waitForElementToBeRemoved(() => screen.queryByRole("dialog")); @@ -220,7 +221,7 @@ describe("closing behaviour", () => { ); const closeButton = screen.getByRole("button", { name: /Close/i }); - closeButton.focus(); + act(() => closeButton.focus()); await user.keyboard("{a}"); expect(onCancel).not.toHaveBeenCalled(); @@ -246,8 +247,6 @@ test("root container is refocused when the focus method of the component's ref h ); const button = screen.getByRole("button", { name: /Refocus dialog/i }); - button.focus(); - await user.click(button); expect(screen.getByRole("dialog")).toHaveFocus(); diff --git a/src/components/duelling-picklist/duelling-picklist.test.tsx b/src/components/duelling-picklist/duelling-picklist.test.tsx index a359a09d00..8341967127 100644 --- a/src/components/duelling-picklist/duelling-picklist.test.tsx +++ b/src/components/duelling-picklist/duelling-picklist.test.tsx @@ -1,5 +1,5 @@ import React, { useReducer } from "react"; -import { render, screen, within } from "@testing-library/react"; +import { act, render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { @@ -582,7 +582,9 @@ test.each([ const allSourceGroupButtons = within( screen.getAllByTestId("picklist")[0], ).getAllByTestId("picklist-group-button"); - allSourceGroupButtons[allSourceGroupButtons.length - 1].focus(); + act(() => { + allSourceGroupButtons[allSourceGroupButtons.length - 1].focus(); + }); await user.keyboard(key); expect( @@ -605,7 +607,9 @@ test.each([ const allSourceGroupButtons = within( screen.getAllByTestId("picklist")[1], ).getAllByTestId("picklist-group-button"); - allSourceGroupButtons[allSourceGroupButtons.length - 1].focus(); + act(() => { + allSourceGroupButtons[allSourceGroupButtons.length - 1].focus(); + }); await user.keyboard(key); expect( diff --git a/src/components/duelling-picklist/picklist-group/picklist-group.test.tsx b/src/components/duelling-picklist/picklist-group/picklist-group.test.tsx index 5671491799..aa9ed48a3d 100644 --- a/src/components/duelling-picklist/picklist-group/picklist-group.test.tsx +++ b/src/components/duelling-picklist/picklist-group/picklist-group.test.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { render, screen } from "@testing-library/react"; +import { render, screen, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import PicklistGroup from "./picklist-group.component"; @@ -92,7 +92,9 @@ test("when the enter key is pressed with the group button focused, the onChange , ); - screen.getByTestId("picklist-group-button").focus(); + act(() => { + screen.getByTestId("picklist-group-button").focus(); + }); await user.keyboard("{Enter}"); expect(onChange).toHaveBeenCalledTimes(1); @@ -119,7 +121,9 @@ test("when the space key is pressed with the group button focused, the onChange , ); - screen.getByTestId("picklist-group-button").focus(); + act(() => { + screen.getByTestId("picklist-group-button").focus(); + }); await user.keyboard(" "); expect(onChange).toHaveBeenCalledTimes(1); @@ -146,7 +150,9 @@ test("when a key other than space or enter is pressed with the group button focu , ); - screen.getByTestId("picklist-group-button").focus(); + act(() => { + screen.getByTestId("picklist-group-button").focus(); + }); await user.keyboard("a"); expect(onChange).not.toHaveBeenCalled(); @@ -217,7 +223,9 @@ test("when an 'add' button is focused, it should change the background colour of , ); - screen.getByTestId("picklist-group-button").focus(); + act(() => { + screen.getByTestId("picklist-group-button").focus(); + }); expect(screen.getAllByRole("listitem")[0]).toHaveStyleRule( "background", @@ -244,7 +252,9 @@ test("when a 'remove' button is focused, it should change the background colour , ); - screen.getByTestId("picklist-group-button").focus(); + act(() => { + screen.getByTestId("picklist-group-button").focus(); + }); expect(screen.getAllByRole("listitem")[0]).toHaveStyleRule( "background", diff --git a/src/components/flat-table/flat-table-checkbox/flat-table-checkbox.test.tsx b/src/components/flat-table/flat-table-checkbox/flat-table-checkbox.test.tsx index 73c2f9010b..4ea088f1df 100644 --- a/src/components/flat-table/flat-table-checkbox/flat-table-checkbox.test.tsx +++ b/src/components/flat-table/flat-table-checkbox/flat-table-checkbox.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import FlatTableCheckbox from "./flat-table-checkbox.component"; @@ -42,8 +42,9 @@ test("should stop propagation when the user presses a key that is not up or down , ); - - screen.getByRole("checkbox").focus(); + act(() => { + screen.getByRole("checkbox").focus(); + }); await user.keyboard("{a}"); expect(parentOnKeyDown).not.toHaveBeenCalled(); @@ -61,8 +62,9 @@ test("should not stop propagation when the user presses down arrow key", async ( , ); - - screen.getByRole("checkbox").focus(); + act(() => { + screen.getByRole("checkbox").focus(); + }); await user.keyboard("{ArrowDown}"); expect(parentOnKeyDown).toHaveBeenCalled(); @@ -80,8 +82,9 @@ test("should not stop propagation when the user presses up arrow key", async () , ); - - screen.getByRole("checkbox").focus(); + act(() => { + screen.getByRole("checkbox").focus(); + }); await user.keyboard("{ArrowUp}"); expect(parentOnKeyDown).toHaveBeenCalled(); diff --git a/src/components/flat-table/flat-table.test.tsx b/src/components/flat-table/flat-table.test.tsx index cc8a0ff5c7..f58ab4b6c4 100644 --- a/src/components/flat-table/flat-table.test.tsx +++ b/src/components/flat-table/flat-table.test.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import FlatTable from "./flat-table.component"; @@ -62,7 +62,9 @@ describe("when rows are interactive", () => { ); const tableWrapper = screen.getByRole("region"); const focusableTableContainer = screen.getByTestId("flat-table-container"); - focusableTableContainer.focus(); + act(() => { + focusableTableContainer.focus(); + }); expect(focusableTableContainer).toHaveFocus(); expect(tableWrapper).toHaveStyleRule("outline", "transparent 3px solid"); @@ -91,7 +93,9 @@ describe("when rows are interactive", () => { ); const tableWrapper = screen.getByRole("region"); const focusableTableContainer = screen.getByTestId("flat-table-container"); - focusableTableContainer.focus(); + act(() => { + focusableTableContainer.focus(); + }); expect(focusableTableContainer).toHaveFocus(); expect(tableWrapper).toHaveStyleRule( @@ -117,7 +121,9 @@ describe("when rows are interactive", () => { , ); const focusableTableContainer = screen.getByTestId("flat-table-container"); - focusableTableContainer.focus(); + act(() => { + focusableTableContainer.focus(); + }); expect(focusableTableContainer).toHaveFocus(); @@ -187,7 +193,9 @@ describe("when rows are interactive", () => { const secondRow = screen.getByRole("row", { name: "three four" }); const thirdRow = screen.getByRole("row", { name: "five six" }); const fourthRow = screen.getByRole("row", { name: "seven eight" }); - focusableTableContainer?.focus(); + act(() => { + focusableTableContainer?.focus(); + }); await user.keyboard("{Tab}"); expect(firstRow).toHaveFocus(); @@ -374,7 +382,9 @@ describe("when rows are interactive", () => { ); const secondRow = screen.getByRole("row", { name: "three four" }); const checkbox = screen.getByRole("checkbox"); - checkbox.focus(); + act(() => { + checkbox.focus(); + }); expect(checkbox).toHaveFocus(); await user.keyboard("{ArrowDown}"); @@ -399,7 +409,9 @@ describe("when rows are interactive", () => { ); const firstRow = screen.getByRole("row", { name: "one two" }); const checkbox = screen.getByRole("checkbox"); - checkbox.focus(); + act(() => { + checkbox.focus(); + }); expect(checkbox).toHaveFocus(); await user.keyboard("{ArrowUp}"); diff --git a/src/components/help/help.test.tsx b/src/components/help/help.test.tsx index 836fa2f974..63cd792075 100644 --- a/src/components/help/help.test.tsx +++ b/src/components/help/help.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Help from "."; import Icon from "../icon"; @@ -35,9 +35,11 @@ test("removes tooltip when Escape key is pressed", async () => { const user = userEvent.setup(); render(foo); - screen.getByRole("button", { name: "help" }).focus(); + act(() => { + screen.getByRole("button", { name: "help" }).focus(); + }); - expect(screen.getByRole("tooltip", { name: "foo" })).toBeVisible(); + expect(await screen.findByRole("tooltip", { name: "foo" })).toBeVisible(); await user.keyboard("{Escape}"); @@ -48,9 +50,11 @@ test("does not remove tooltip when Enter key is pressed", async () => { const user = userEvent.setup(); render(foo); - screen.getByRole("button", { name: "help" }).focus(); + act(() => { + screen.getByRole("button", { name: "help" }).focus(); + }); - const tooltip = screen.getByRole("tooltip", { name: "foo" }); + const tooltip = await screen.findByRole("tooltip", { name: "foo" }); expect(tooltip).toBeVisible(); diff --git a/src/components/link/link.test.tsx b/src/components/link/link.test.tsx index 93f7a6c6b8..013c043522 100644 --- a/src/components/link/link.test.tsx +++ b/src/components/link/link.test.tsx @@ -1,7 +1,7 @@ /* TODO: FE-6579 To re-enable once button-related props are removed from Link */ /* eslint-disable jsx-a11y/anchor-is-valid */ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Link from "./link.component"; @@ -158,7 +158,9 @@ describe("when the `onKeyDown` event is triggered", () => { render(); const linkElement = screen.getByTestId("link-anchor"); - linkElement.focus(); + act(() => { + linkElement.focus(); + }); await user.keyboard("{Enter}"); expect(onKeyDownFn).toHaveBeenCalled(); @@ -170,7 +172,9 @@ describe("when the `onKeyDown` event is triggered", () => { render(); const linkElement = screen.getByTestId("link-anchor"); - linkElement.focus(); + act(() => { + linkElement.focus(); + }); await user.keyboard("{Enter}"); expect(onKeyDownFn).toHaveBeenCalled(); @@ -183,7 +187,9 @@ describe("when the `onKeyDown` event is triggered", () => { render(); const linkElement = screen.getByTestId("link-anchor"); - linkElement.focus(); + act(() => { + linkElement.focus(); + }); await user.keyboard("{Enter}"); expect(onKeyDownFn).toHaveBeenCalled(); diff --git a/src/components/menu/menu-item/menu-item.test.tsx b/src/components/menu/menu-item/menu-item.test.tsx index 58b798ec48..57ffce9ccb 100644 --- a/src/components/menu/menu-item/menu-item.test.tsx +++ b/src/components/menu/menu-item/menu-item.test.tsx @@ -1,5 +1,12 @@ import React from "react"; -import { fireEvent, render, screen, within } from "@testing-library/react"; +import { + act, + fireEvent, + render, + screen, + waitFor, + within, +} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { MenuItem, MenuSegmentTitle } from ".."; @@ -478,7 +485,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -505,7 +514,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -530,7 +541,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowup}"); const submenuItems = screen.getAllByRole("link"); @@ -557,7 +570,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -580,7 +595,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -605,7 +622,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); await user.keyboard("{End}"); @@ -639,7 +658,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -664,7 +685,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); await user.keyboard("{End}"); @@ -690,7 +713,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("link"); @@ -715,7 +740,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("link", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); await user.tab(); @@ -736,7 +763,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("link", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); await user.keyboard("{a}"); @@ -897,7 +926,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowleft}"); expect(screen.queryByRole("list")).not.toBeInTheDocument(); @@ -917,7 +948,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); await user.keyboard("{Escape}"); @@ -941,7 +974,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); await user.keyboard("{arrowdown}"); await user.keyboard("{Enter}"); @@ -968,14 +1003,20 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("button", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); await user.keyboard("{Enter}"); - expect(screen.queryByRole("list")).not.toBeInTheDocument(); + act(() => { + jest.runOnlyPendingTimers(); + }); - jest.runOnlyPendingTimers(); + await waitFor(() => { + expect(screen.queryByRole("list")).not.toBeInTheDocument(); + }); jest.useRealTimers(); }); @@ -1004,7 +1045,9 @@ describe("when MenuItem has a submenu", () => { , ); const submenuParentItem = screen.getByRole("link", { name: "Item One" }); - submenuParentItem.focus(); + act(() => { + submenuParentItem.focus(); + }); await user.keyboard("{arrowdown}"); const submenuItems = screen.getAllByRole("button"); await user.click(submenuItems[2]); diff --git a/src/components/menu/menu.test.tsx b/src/components/menu/menu.test.tsx index d3b3b8ed63..a6fe3ad556 100644 --- a/src/components/menu/menu.test.tsx +++ b/src/components/menu/menu.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { screen, render } from "@testing-library/react"; +import { screen, render, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Menu, MenuItem } from "."; @@ -28,7 +28,9 @@ test("should focus the last item when 'End' key is pressed by user", async () => , ); const firstMenuItem = screen.getByRole("link", { name: "test one" }); - firstMenuItem.focus(); + act(() => { + firstMenuItem.focus(); + }); const lastMenuItem = screen.getByRole("link", { name: "test four" }); await user.keyboard("{End}"); @@ -46,7 +48,9 @@ test("should focus the first item when 'Home' key is pressed by user", async () , ); const lastMenuItem = screen.getByRole("link", { name: "test four" }); - lastMenuItem.focus(); + act(() => { + lastMenuItem.focus(); + }); const firstMenuItem = screen.getByRole("link", { name: "test one" }); await user.keyboard("{Home}"); @@ -64,7 +68,9 @@ test("should focus the next item in sequence, and remove focus from menu on last , ); const items = screen.getAllByRole("link"); - items[0].focus(); + act(() => { + items[0].focus(); + }); await user.tab(); expect(items[1]).toHaveFocus(); @@ -87,7 +93,9 @@ test("should focus the previous item in sequence, and remove focus from menu on , ); const items = screen.getAllByRole("link"); - items[3].focus(); + act(() => { + items[3].focus(); + }); await user.tab({ shift: true }); expect(items[2]).toHaveFocus(); @@ -110,7 +118,9 @@ test("should not focus the next item in sequence when 'arrowright' key is presse , ); const items = screen.getAllByRole("link"); - items[0].focus(); + act(() => { + items[0].focus(); + }); await user.keyboard("{arrowright}"); expect(items[0]).toHaveFocus(); @@ -131,7 +141,9 @@ test("should not focus the previous item in sequence when 'arrowleft' key is pre , ); const items = screen.getAllByRole("link"); - items[3].focus(); + act(() => { + items[3].focus(); + }); await user.keyboard("{arrowleft}"); expect(items[3]).toHaveFocus(); diff --git a/src/components/modal/modal.test.tsx b/src/components/modal/modal.test.tsx index 2b5d3f4ed0..a35947a2ab 100644 --- a/src/components/modal/modal.test.tsx +++ b/src/components/modal/modal.test.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Modal from "./modal.component"; @@ -100,7 +100,9 @@ test("closes top modal when the `escape` key is pressed", async () => { expect(onCancelFnTwo).toHaveBeenCalled(); expect(onCancelFn).not.toHaveBeenCalled(); - jest.runOnlyPendingTimers(); + act(() => { + jest.runOnlyPendingTimers(); + }); jest.useRealTimers(); }); @@ -123,7 +125,9 @@ test("does not fire `onCancel` if the `escape` key is pressed and no modals are expect(onCancelFnTwo).not.toHaveBeenCalled(); expect(onCancelFn).not.toHaveBeenCalled(); - jest.runOnlyPendingTimers(); + act(() => { + jest.runOnlyPendingTimers(); + }); jest.useRealTimers(); }); @@ -134,16 +138,16 @@ test("does not fire `onCancel` if the `escape` key is pressed and `disableClose` const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); render( - <> - - , + , ); await user.keyboard("{Escape}"); expect(onCancelFn).not.toHaveBeenCalled(); - jest.runOnlyPendingTimers(); + act(() => { + jest.runOnlyPendingTimers(); + }); jest.useRealTimers(); }); @@ -160,7 +164,9 @@ test("should call the `onCancel` method when the modal is open and the `escape` expect(onCancelFn).toHaveBeenCalled(); - jest.runOnlyPendingTimers(); + act(() => { + jest.runOnlyPendingTimers(); + }); jest.useRealTimers(); }); @@ -177,7 +183,9 @@ test("onCancel method should not have been called with disableEscKey prop set to expect(onCancelFn).not.toHaveBeenCalled(); - jest.runOnlyPendingTimers(); + act(() => { + jest.runOnlyPendingTimers(); + }); jest.useRealTimers(); }); diff --git a/src/components/numeral-date/numeral-date.test.tsx b/src/components/numeral-date/numeral-date.test.tsx index a9b3ac0260..edd3e3f4e5 100644 --- a/src/components/numeral-date/numeral-date.test.tsx +++ b/src/components/numeral-date/numeral-date.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen, within } from "@testing-library/react"; +import { render, screen, within, act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { testStyledSystemMargin, @@ -1839,7 +1839,10 @@ test("should call `onBlur` callback if prop is passed and user clicks outside of const dayInput = screen.getByRole("textbox", { name: "Day" }); await user.click(dayInput); await user.click(document.body); - jest.runAllTimers(); + + act(() => { + jest.runOnlyPendingTimers(); + }); expect(onBlur).toHaveBeenCalled(); }); @@ -1860,7 +1863,10 @@ test("should not call `onBlur` callback if prop is passed and user clicks from o const monthInput = screen.getByRole("textbox", { name: "Month" }); await user.click(dayInput); await user.click(monthInput); - jest.runAllTimers(); + + act(() => { + jest.runOnlyPendingTimers(); + }); expect(onBlur).not.toHaveBeenCalled(); }); diff --git a/src/components/pages/pages.test.tsx b/src/components/pages/pages.test.tsx index ac4756a17c..14c13ab942 100644 --- a/src/components/pages/pages.test.tsx +++ b/src/components/pages/pages.test.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Pages, { Page, PagesProps } from "./pages.component"; @@ -72,7 +72,9 @@ test.each([ render(); await user.click(screen.getByRole("button", { name: "Go to second page" })); - jest.runAllTimers(); + act(() => { + jest.runAllTimers(); + }); expect(screen.getByTestId("visible-page")).toHaveClass( `${expected}-enter-done`, @@ -105,8 +107,9 @@ test("when the `pageIndex` prop is changed to `undefined`, the currently-rendere expect(screen.getByRole("heading")).toHaveTextContent("Page 2"); rerender(); - jest.runAllTimers(); - + act(() => { + jest.runAllTimers(); + }); expect(screen.getByRole("heading")).toHaveTextContent("Page 2"); }); @@ -115,9 +118,10 @@ test("navigating to the next page should render the expected content", async () render(); await user.click(screen.getByRole("button", { name: "Go to second page" })); - jest.runAllTimers(); - - expect(screen.getByRole("heading")).toHaveTextContent("My Second Page"); + act(() => { + jest.runAllTimers(); + }); + expect(screen.getByRole("heading", { name: "My Second Page" })).toBeVisible(); }); test("navigating to the previous page should render the expected content", async () => { @@ -126,9 +130,10 @@ test("navigating to the previous page should render the expected content", async expect(screen.getByRole("heading")).toHaveTextContent("My Second Page"); await user.click(screen.getByRole("button", { name: "Back" })); - jest.runAllTimers(); - - expect(screen.getByRole("heading")).toHaveTextContent("My First Page"); + act(() => { + jest.runAllTimers(); + }); + expect(screen.getByRole("heading", { name: "My First Page" })).toBeVisible(); }); test("navigating to the previous page should render the last page when currently on the first page", async () => { @@ -136,9 +141,10 @@ test("navigating to the previous page should render the last page when currently render(); await user.click(screen.getByRole("button", { name: "Back" })); - jest.runAllTimers(); - - expect(screen.getByRole("heading")).toHaveTextContent("My Third Page"); + act(() => { + jest.runAllTimers(); + }); + expect(screen.getByRole("heading", { name: "My Third Page" })).toBeVisible(); }); test("navigating to the next page should render the first page when currently on the last page", async () => { @@ -147,9 +153,10 @@ test("navigating to the next page should render the first page when currently on expect(screen.getByRole("heading")).toHaveTextContent("My Third Page"); await user.click(screen.getByRole("button", { name: "Go to next page" })); - jest.runAllTimers(); - - expect(screen.getByRole("heading")).toHaveTextContent("My First Page"); + act(() => { + jest.runAllTimers(); + }); + expect(screen.getByRole("heading", { name: "My First Page" })).toBeVisible(); }); test("when attempting to navigate pages and there is only one page, it should not change the rendered content", async () => { diff --git a/src/components/pod/pod.test.tsx b/src/components/pod/pod.test.tsx index 0651370883..c0445204da 100644 --- a/src/components/pod/pod.test.tsx +++ b/src/components/pod/pod.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Pod from "."; import Typography from "../typography"; @@ -94,8 +94,9 @@ test("calls `onEdit` when Enter key is pressed on the edit button", async () => render(); const editButton = screen.getByRole("button", { name: "Edit" }); - editButton.focus(); - + act(() => { + editButton.focus(); + }); await user.keyboard("{enter}"); expect(onEdit).toHaveBeenCalled(); @@ -107,9 +108,11 @@ test("does not call `onEdit` when non-Enter key is pressed on the edit button", render(); const editButton = screen.getByRole("button", { name: "Edit" }); - editButton.focus(); - + act(() => { + editButton.focus(); + }); await user.keyboard("a"); + expect(onEdit).not.toHaveBeenCalled(); }); @@ -129,9 +132,11 @@ test("calls `onEdit` when `triggerEditOnContent` is true and Enter key is presse render(); const content = screen.getByTestId("pod-block"); - content.focus(); - + act(() => { + content.focus(); + }); await user.keyboard("{enter}"); + expect(onEdit).toHaveBeenCalled(); }); @@ -141,9 +146,11 @@ test("does not call `onEdit` when `triggerEditOnContent` is true and non-Enter k render(); const content = screen.getByTestId("pod-block"); - content.focus(); - + act(() => { + content.focus(); + }); await user.keyboard("a"); + expect(onEdit).not.toHaveBeenCalled(); }); @@ -169,9 +176,11 @@ test("calls `onDelete` when Enter key is pressed on the delete button", async () render(); const deleteButton = screen.getByRole("button", { name: "Delete" }); - deleteButton.focus(); - + act(() => { + deleteButton.focus(); + }); await user.keyboard("{enter}"); + expect(onDelete).toHaveBeenCalled(); }); @@ -181,9 +190,11 @@ test("does not call `onDelete` when non-Enter key is pressed on the delete butto render(); const deleteButton = screen.getByRole("button", { name: "Delete" }); - deleteButton.focus(); - + act(() => { + deleteButton.focus(); + }); await user.keyboard("a"); + expect(onDelete).not.toHaveBeenCalled(); }); @@ -209,9 +220,11 @@ test("calls `onUndo` when Enter key is pressed on the undo button", async () => render(); const undoButton = screen.getByRole("button", { name: "Undo" }); - undoButton.focus(); - + act(() => { + undoButton.focus(); + }); await user.keyboard("{enter}"); + expect(onUndo).toHaveBeenCalled(); }); @@ -221,9 +234,11 @@ test("does not call `onUndo` when non-Enter key is pressed on the undo button", render(); const undoButton = screen.getByRole("button", { name: "Undo" }); - undoButton.focus(); - + act(() => { + undoButton.focus(); + }); await user.keyboard("a"); + expect(onUndo).not.toHaveBeenCalled(); }); @@ -232,14 +247,19 @@ test("renders content with focus border when edit button is focused and removes render( {}} />); const editButton = screen.getByRole("button", { name: "Edit" }); - editButton.focus(); - + act(() => { + editButton.focus(); + }); const content = screen.getByTestId("pod-block"); + expect(content).toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); - editButton.blur(); + act(() => { + editButton.blur(); + }); + expect(content).not.toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); @@ -250,14 +270,19 @@ test("renders content with focus border when delete button is focused and remove render( {}} />); const deleteButton = screen.getByRole("button", { name: "Delete" }); - deleteButton.focus(); - + act(() => { + deleteButton.focus(); + }); const content = screen.getByTestId("pod-block"); + expect(content).toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); - deleteButton.blur(); + act(() => { + deleteButton.blur(); + }); + expect(content).not.toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); @@ -268,14 +293,19 @@ test("renders content with focus border when undo button is focused and removes render( {}} />); const undoButton = screen.getByRole("button", { name: "Undo" }); - undoButton.focus(); - + act(() => { + undoButton.focus(); + }); const content = screen.getByTestId("pod-block"); + expect(content).toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); - undoButton.blur(); + act(() => { + undoButton.blur(); + }); + expect(content).not.toHaveStyleRule( "border: 3px solid var(--colorsSemanticFocus500)", ); @@ -459,7 +489,9 @@ test("renders block with correct colour when `variant` is 'tile', `internalEditB ); const editButton = screen.getByRole("button", { name: "Edit" }); - editButton.focus(); + act(() => { + editButton.focus(); + }); const block = screen.getByTestId("pod-block"); expect(block).toHaveStyleRule( @@ -472,7 +504,9 @@ test("renders block with correct padding when `border` is false and a button is render( {}} border={false} />); const editButton = screen.getByRole("button", { name: "Edit" }); - editButton.focus(); + act(() => { + editButton.focus(); + }); const block = screen.getByTestId("pod-block"); expect(block).toHaveStyle({ padding: "0" }); diff --git a/src/components/popover-container/popover-container.test.tsx b/src/components/popover-container/popover-container.test.tsx index 60b8eff0db..8cdf71c7a5 100644 --- a/src/components/popover-container/popover-container.test.tsx +++ b/src/components/popover-container/popover-container.test.tsx @@ -295,10 +295,14 @@ test.each([ await user.click(screen.getByRole("button")); - expect(await screen.findByRole("dialog")).toHaveAttribute( - "data-floating-placement", - placement, - ); + act(() => { + jest.runOnlyPendingTimers(); + }); + const dialog = await screen.findByRole("dialog"); + + await waitFor(() => { + expect(dialog).toHaveAttribute("data-floating-placement", placement); + }); }, ); @@ -402,8 +406,9 @@ describe("closing the popup", () => { await user.click(screen.getByRole("button")); const closeButton = await screen.findByRole("button", { name: "close" }); - closeButton.focus(); - + act(() => { + closeButton.focus(); + }); await user.keyboard("{Enter}"); await waitFor(() => { diff --git a/src/components/portrait/portrait.test.tsx b/src/components/portrait/portrait.test.tsx index 0fe3a59ec7..57c0d3c49f 100644 --- a/src/components/portrait/portrait.test.tsx +++ b/src/components/portrait/portrait.test.tsx @@ -39,7 +39,7 @@ test("renders with a gravatar image, if a valid email is passed via the `gravata const hash = MD5(email); const src = `https://www.gravatar.com/avatar/${hash}?s=40&d=404`; - render(); + render(); const img = screen.getByRole("img"); expect(img).toBeVisible(); @@ -53,8 +53,8 @@ test("logs a deprecation warning once when the `gravatar` prop is passed, and a render( <> - - + + , ); @@ -75,7 +75,7 @@ test("if a valid gravatar email is not found and an onError event is triggered, const email = "invalid.email@1973"; const hash = MD5(email); const src = `https://www.gravatar.com/avatar/${hash}?s=40&d=404`; - render(); + render(); const img = screen.getByRole("img"); expect(img).toBeVisible(); @@ -91,7 +91,7 @@ test("if a valid gravatar email is not found and an onError event is triggered, test("renders with a custom image, if a valid src is passed via the `src` prop", () => { const src = "https://upload.wikimedia.org/wikipedia/en/6/6c/Heatposter.jpg"; - render(); + render(); const img = screen.getByRole("img"); expect(img).toBeVisible(); @@ -100,7 +100,7 @@ test("renders with a custom image, if a valid src is passed via the `src` prop", test("if a valid src is not found and an onError event is triggered, the default individual icon is rendered", async () => { const src = "not-a-url"; - render(); + render(); const img = screen.getByRole("img"); expect(img).toBeVisible(); diff --git a/src/components/profile/profile.test.tsx b/src/components/profile/profile.test.tsx index c2cf76ee3f..755bed332b 100644 --- a/src/components/profile/profile.test.tsx +++ b/src/components/profile/profile.test.tsx @@ -162,7 +162,7 @@ test("renders avatar with custom initials when `initials` prop is passed", () => test("renders avatar with custom image when `src` prop is passed", () => { const src = "https://upload.wikimedia.org/wikipedia/en/6/6c/Heatposter.jpg"; - render(); + render(); const avatar = screen.getByRole("img"); expect(avatar).toBeVisible(); diff --git a/src/components/search/search.test.tsx b/src/components/search/search.test.tsx index 7f65b1980e..4bd5cedbf3 100644 --- a/src/components/search/search.test.tsx +++ b/src/components/search/search.test.tsx @@ -1,5 +1,5 @@ import React, { useRef } from "react"; -import { render, screen, within } from "@testing-library/react"; +import { act, render, screen, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import Search, { SearchHandle } from "./search.component"; @@ -137,7 +137,9 @@ test("when the input is blurred, the `onBlur` callback prop is called", async () const onBlur = jest.fn(); render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); expect(onBlur).toHaveBeenCalledTimes(1); }); @@ -284,24 +286,28 @@ test("the component's wrapper element has the appropriate `data-component` tag", ); }); -test("the textbox cross icon can be tabbed to when present", async () => { - const user = userEvent.setup(); - render(); +test("do not render remove button when the input is empty", () => { + render(); - await user.type(screen.getByRole("textbox"), "Bar"); - await user.tab(); + expect(screen.queryByTestId("input-icon-toggle")).not.toBeInTheDocument(); +}); - expect(screen.getByTestId("input-icon-toggle")).toHaveFocus(); +test("render remove button when the input is not empty", () => { + render(); + + expect(screen.getByTestId("input-icon-toggle")).toBeVisible(); }); -test("the textbox close icon can not be tabbed to when the input is empty", async () => { +test("remove button can be reached via keyboard when present", async () => { const user = userEvent.setup(); - render(); + render(); - screen.getByRole("textbox").focus(); + act(() => { + screen.getByRole("textbox").focus(); + }); await user.tab(); - expect(document.body).toHaveFocus(); + expect(screen.getByTestId("input-icon-toggle")).toHaveFocus(); }); test("when a character key is pressed, propagation of the event to parent elements is prevented", async () => { diff --git a/src/components/select/__internal__/select-list/select-list.test.tsx b/src/components/select/__internal__/select-list/select-list.test.tsx index 9187d9ec0c..3fbf528474 100644 --- a/src/components/select/__internal__/select-list/select-list.test.tsx +++ b/src/components/select/__internal__/select-list/select-list.test.tsx @@ -122,11 +122,11 @@ describe("rendered content", () => {