Delay snapshots
Components sometimes trigger custom interactions on render. For example, JavaScript-driven animations that cannot otherwise be disabled or third-party functionality outside of your control. The delay
configuration option enables you to define a fixed minimum time to wait before capturing a snapshot, allowing your tests to get into the intended state before Chromatic snapshots it.
Customizing snapshot delays
Chromatic’s maximum wait time before capturing a snapshot is 15 seconds, providing a balance for your tests to load resources and be ready for snapshotting. If you need to customize the wait time for Chromatic to capture a snapshot, add the delay
configuration option to your tests. For example:
// Adjust this import to match your framework (e.g., nextjs, vue3-vite)
import type { Meta, StoryObj } from "@storybook/your-framework";
/*
* Replace the @storybook/test package with the following if you are using a version of Storybook earlier than 8.0:
* import { within } from "@storybook/testing-library";
* import { expect } from "@storybook/jest";
*/
import { expect, within } from "@storybook/test";
import { Categories } from "./Categories";
const meta: Meta<typeof Categories> = {
component: Categories,
title: "Categories",
parameters: {
// Sets the delay (in milliseconds) at the component level for all stories.
chromatic: { delay: 300 },
},
};
export default meta;
type Story = StoryObj<typeof Categories>;
export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await expect(canvas.getByText("Available Categories")).toBeInTheDocument();
},
};
chromatic.delay
parameter can be set at story,
component, and project levels. This enables you to set project wide
defaults and override them for specific components and/or stories. Learn more » import { test, expect } from "@chromatic-com/playwright";
test.describe("Categories Page", () => {
// Configures the delay (in milliseconds) for this test
test.use({ delay: 300 });
test("Renders the categories page", async ({ page }) => {
await page.goto("/categories");
await expect(page.getByText("Available Categories")).toBeVisible();
});
});
delay
configuration option can be set at the
project level or the test level. This enables you to set project wide
defaults and override them for specific tests. Learn more » describe("Categories Page", () => {
// Configures the delay (in milliseconds) for this test
it("Renders the categories page", { env: { delay: 300 } }, () => {
cy.visit("/categories");
cy.get("h2").contains("Available Categories");
});
});
delay
configuration option can be set at the
project level or the test level. This enables you to set project wide
defaults and override them for specific tests. Learn more » Enabling the delay
configuration in your tests is especially useful when you have an asynchronous action or animations that end after a specific time (e.g., “animate in”) to ensure that your component is in the intended state before Chromatic captures a snapshot. However, if you’re working with a continuous animation or a third-party element you cannot deactivate, you may need to use an ignore region to prevent Chromatic from considering such parts of the UI.
Use assertions to delay snapshot capture
If you need additional control when Chromatic captures a snapshot, you can adjust your tests to rely on interaction testing via Storybook’s play
function, use custom assertions and timeouts with the E2E integration (i.e., Playwright, or Cypress), verifying that the UI is in the required state before the snapshot is taken. Chromatic waits for the assertions to pass before capturing the snapshot.
// Adjust this import to match your framework (e.g., nextjs, vue3-vite)
import type { Meta, StoryObj } from "@storybook/your-framework";
/*
* Replace the @storybook/test package with the following if you are using a version of Storybook earlier than 8.0:
* import { userEvent, waitFor, within } from "@storybook/testing-library";
* import { expect } from "@storybook/jest";
*/
import { expect, userEvent, waitFor, within } from "@storybook/test";
import { Categories } from "./Categories";
const meta: Meta<typeof Categories> = {
component: Categories,
title: "Categories",
};
export default meta;
type Story = StoryObj<typeof Categories>;
export const Default: Story = {
play: async ({ canvasElement }) => {
// Assigns canvas to the component root element
const canvas = within(canvasElement);
const LoadMoreButton = await canvas.getByRole("button", { name: "Load more" });
await userEvent.click(LoadMoreButton);
// Wait for the below assertion not throwing an error (default timeout is 1000ms)
// This is especially useful when you have an asynchronous action or component that you want to wait for before taking a snapshot
await waitFor(async () => {
const ItemList = await canvas.getByLabelText("listitems");
const numberOfItems = await within(categories).findAllByRole("link");
expect(numberOfItems).toHaveLength(0);
});
},
};
// Emulates a delayed story by setting a timeout of 10 seconds to allow the component to load the items and ensure that the list has 20 items rendered in the DOM
export const WithManualTimeout: Story = {
play: async ({ canvasElement }) => {
// Assigns canvas to the component root element
const canvas = within(canvasElement);
const LoadMoreButton = await canvas.getByTestId("button");
await userEvent.click(LoadMoreButton);
// This sets a timeout of 10 seconds and verifies that there are 20 items in the list
await new Promise((resolve) => setTimeout(resolve, 10000));
const ItemList = await canvas.getByLabelText("listitems");
const numberOfItems = await within(categories).findAllByRole("link");
expect(numberOfItems).toHaveLength(20);
},
};
ℹ️ For more information about querying elements, see the DOM Testing Library cheatsheet.
import { test, expect } from "@chromatic-com/playwright";
test.describe("Categories Page", () => {
test("Renders the categories page with additional items", async ({ page }) => {
await page.goto("/categories");
const loadMoreButton = await page.getByRole("button", { name: "Load more" });
await loadMoreButton.click();
// Verifies that there are 20 items in the list after waiting for 10 seconds
expect(await page.locator(".listItems")).toHaveCount(20, {
timeout: 10000
});
});
});
describe("Categories Page", () => {
it("Renders the categories page with additional items", () => {
cy.visit("/categories");
cy.get("button").contains("Load more").click();
// Verifies that there are 20 items in the list after waiting for 10 seconds
cy.get(".listItems", { timeout: 10000 }).should("have.length", 20);
});
});