new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Playwright · API reference · all subjects

component testing

17 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

mount fixture returns Locator for gallery root

The mount(storyId, props?) fixture from @playwright/test drives the gallery's window.mount and returns a Locator for the gallery root (#root). Queries should be scoped from this returned locator, for example: component.getByRole('button').click() rather than component.click().

mount fixture passes serializable props to story

The mount(storyId, props?) fixture passes plain serializable props as the second argument. These props are handed by the gallery to the story as its props. Callbacks belong inside the story, not in props.

mount fixture signature and type checking

The mount fixture is generic over the story type: pass the story type as a template argument to type-check the props. Example: const component = await mount<typeof WithTitle>('components/Button/WithTitle', { title: 'Hello' }). This works for React and Vue stories.

component.update() re-renders story with new props without remounting

Call component.update(newProps) to test how a component reacts to a prop change without remounting. This re-renders the same story with new props on the existing root, preserving state. This requires the gallery to reuse its root/instance.

Story files location and naming convention

Stories live next to the component in *.story.tsx (or .ts/.jsx/.js/.vue) files; each named export is one story. Story id is the path under src/ without the .story.* extension, plus the export name. Example: src/components/Button.story.tsx export Primary → components/Button/Primary. A .story.vue single-file component is one story addressable by its path alone (its default export).

Gallery implementation requirements

The gallery is a single page that exposes window.mount(params) and window.unmount() to render a story into #root. It resolves stories from story files (e.g. with import.meta.glob) and is framework-specific and owned by the user — there is no template to copy. The mount fixture navigates to baseURL to access the gallery.

Playwright config for component testing with Vite app

For Vite apps, add a project to playwright.config.ts with: name: 'components', testDir: './tests/components', use: { ...devices['Desktop Chrome'], baseURL: 'http://localhost:5173/playwright/gallery/index.html', serviceWorkers: 'block', reuseContext: true }. Add webServer with command: 'npm run dev', url: 'http://localhost:5173/playwright/gallery/index.html', reuseExistingServer: !process.env.CI. The gallery is served at /playwright/gallery/index.html by the existing dev server.

Playwright config for component testing with non-Vite apps

For non-Vite apps (Next.js, webpack, no dev server), run a small standalone dev server (e.g. Vite) to serve the gallery page and point baseURL at it. This requires vite and the framework plugin as devDependencies. The webServer command might be: npx vite --config playwright/vite.config.ts with url pointing to the standalone server (e.g. http://localhost:3100/playwright/gallery/index.html).

serviceWorkers: 'block' configuration purpose

Setting serviceWorkers: 'block' in the Playwright config keeps the app's own service worker from serving cached responses that would shadow page.route() mocks used in tests.

reuseContext: true configuration purpose

Setting reuseContext: true in the Playwright config reuses the browser context across tests in a worker, providing a large speedup for component suites similar to the old component-testing runtime.

Recording component state for test assertion

Where a component takes callbacks, the story creates the state, provides the callbacks, and records the state into a hidden form for the test to assert on. Record each observed value in its own data-testid input using String(...) or JSON.stringify(...) for payloads, then assert with toHaveValue() — a web-first assertion that retries until the state lands.

Test callbacks and events example

Example story recording expanded state: export const Stateful = () => { const [expanded, setExpanded] = useState(false); return <><Expandable expanded={expanded} setExpanded={setExpanded} title="Title">Details</Expandable><form hidden><input data-testid="expanded" readOnly value={String(expanded)} /></form></>; }. Example test: const component = await mount('components/Expandable/Stateful'); await component.locator('.codicon-chevron-right').click(); await expect(component.getByTestId('expanded')).toHaveValue('true');

Per-test props example

Example story with props: export const WithTitle = ({ title = 'Default' }: { title?: string }) => <Button title={title} />. Example test: const component = await mount('components/Button/WithTitle', { title: 'Hello' });

Prop transitions with update() example

Example testing prop changes without remounting: const component = await mount('components/Counter/Default', { value: 1 }); await expect(component.getByTestId('value')).toHaveText('1'); await component.update({ value: 2 }); await expect(component.getByTestId('value')).toHaveText('2');

Multiple stories in one test example

Each mount() navigates fresh for full isolation; mounting several stories in one test is cheap. Example: await expect(await mount('Button/Primary')).toHaveScreenshot('primary.png'); await expect(await mount('Button/Disabled')).toHaveScreenshot('disabled.png');

Network mocking in component tests

Use page.route() as usual for network mocking — register routes before mount(), since mounting navigates. serviceWorkers: 'block' (set in config) keeps the app's own service worker from serving cached responses that shadow the routes.

Debugging stories from browser devtools

Open the gallery URL (baseURL) in a browser and call await window.mount({ story: 'components/Button/Primary' }) from the devtools console — this is exactly what the mount fixture does. An unknown story rejects window.mount, which surfaces as the test's mount() throwing with a real stack.

Give your agent this brain