From 6b7c5bd2072908ba4a9707827d49e1826e2cce22 Mon Sep 17 00:00:00 2001 From: Sven van de Scheur Date: Mon, 15 Jan 2024 17:49:15 +0100 Subject: [PATCH] :white_check_mark: #4 - test: reduce flakyness of tests --- .storybook/test-runner.ts | 27 ++++++++++++++++++++ src/components/dropdown/dropdown.stories.tsx | 20 +++++++-------- src/components/navbar/navbar.stories.tsx | 10 ++++---- src/components/navbar/navbar.tsx | 3 +-- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 .storybook/test-runner.ts diff --git a/.storybook/test-runner.ts b/.storybook/test-runner.ts new file mode 100644 index 00000000..4871b22d --- /dev/null +++ b/.storybook/test-runner.ts @@ -0,0 +1,27 @@ +const { getStoryContext } = require("@storybook/test-runner"); +const { MINIMAL_VIEWPORTS } = require("@storybook/addon-viewport"); + +const DEFAULT_VP_SIZE = { width: 1280, height: 720 }; + +module.exports = { + /** + * This makes sure the test runner respects the viewport. + * @see {@link https://github.com/storybookjs/test-runner/issues/85#issuecomment-1576465128|[Bug] Tests always run in the default viewport} + * @param page + * @param story + */ + async preRender(page, story) { + const context = await getStoryContext(page, story); + const vpName = + context.parameters?.viewport?.defaultViewport ?? "responsive"; + const vpParams = MINIMAL_VIEWPORTS[vpName]; + + if (vpParams) { + const width = parseInt(vpParams.styles.width); + const height = parseInt(vpParams.styles.height); + page.setViewportSize({ width, height }); + } else { + page.setViewportSize(DEFAULT_VP_SIZE); + } + }, +}; diff --git a/src/components/dropdown/dropdown.stories.tsx b/src/components/dropdown/dropdown.stories.tsx index 46868542..51d9be05 100644 --- a/src/components/dropdown/dropdown.stories.tsx +++ b/src/components/dropdown/dropdown.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { expect, userEvent, within } from "@storybook/test"; +import { expect, userEvent, waitFor, within } from "@storybook/test"; import React from "react"; import { Button, ButtonLink } from "../button"; @@ -19,11 +19,11 @@ const meta = { // Click opens, escape closes. await userEvent.click(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); userEvent.keyboard("{Escape}"); - expect(await canvas.findByRole("dialog")).not.toBeVisible(); + await waitFor(() => expect(canvas.queryByRole("dialog")).toBeNull()); await userEvent.click(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); // Tab focuses items. await userEvent.tab({ delay: 10 }); @@ -102,11 +102,11 @@ export const ActivateOnHover: Story = { // Click opens, escape closes. await userEvent.hover(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); userEvent.keyboard("{Escape}"); - expect(await canvas.findByRole("dialog")).not.toBeVisible(); + await waitFor(() => expect(canvas.queryByRole("dialog")).toBeNull()); await userEvent.hover(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); // Tab focuses items. await userEvent.tab({ delay: 10 }); @@ -125,12 +125,12 @@ export const ActivateOnFocus: Story = { // Click opens, escape closes. await userEvent.tab({ delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); userEvent.keyboard("{Escape}"); - expect(await canvas.findByRole("dialog")).not.toBeVisible(); + await waitFor(() => expect(canvas.queryByRole("dialog")).toBeNull()); await userEvent.tab({ shift: true, delay: 10 }); await userEvent.tab({ delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); // Tab focuses items. await userEvent.tab({ delay: 10 }); diff --git a/src/components/navbar/navbar.stories.tsx b/src/components/navbar/navbar.stories.tsx index b616c1af..a81bb26b 100644 --- a/src/components/navbar/navbar.stories.tsx +++ b/src/components/navbar/navbar.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; -import { expect, userEvent, within } from "@storybook/test"; +import { expect, userEvent, waitFor, within } from "@storybook/test"; import React from "react"; import { Button, ButtonLink } from "../button"; @@ -57,11 +57,11 @@ export const NavbarOnMobile: Story = { // Click opens, escape closes. await userEvent.click(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); - userEvent.keyboard("{Escape}"); - expect(await canvas.findByRole("dialog")).not.toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); + userEvent.keyboard("{Escape}", { delay: 10 }); + await waitFor(() => expect(canvas.queryByRole("dialog")).toBeNull()); await userEvent.click(button, { delay: 10 }); - expect(await canvas.findByRole("dialog")).toBeVisible(); + await expect(canvas.getByRole("dialog")).toBeVisible(); // Tab focuses items. await userEvent.tab({ delay: 10 }); diff --git a/src/components/navbar/navbar.tsx b/src/components/navbar/navbar.tsx index db92e079..82ec8582 100644 --- a/src/components/navbar/navbar.tsx +++ b/src/components/navbar/navbar.tsx @@ -15,9 +15,8 @@ export type NavbarProps = ToolbarProps; */ export const Navbar: React.FC = ({ children, ...props }) => { const [isMobile, setIsMobile] = useState( - window?.matchMedia("(max-width: 767px)").matches, + window?.matchMedia("(max-width: 767px)").matches ?? true, ); - /** * Updates `isMobile` on resize. */