Storybook Vue 3 renderer for developing, documenting, and testing UI components in isolation
—
Integration with Playwright for component testing, providing utilities to create test functions for Vue components within the Storybook environment. This enables automated browser-based testing of individual components and stories.
Creates a Playwright test function specifically designed for component testing with Storybook Vue 3 components.
/**
* Creates Playwright test function for component testing.
* Provides a test runner that can render and interact with Vue components
* in a browser environment using Playwright.
*
* @param options - Configuration options for the test runner
*/
function createTest(options?: any): any;Usage Example:
import { createTest } from "@storybook/vue3/experimental-playwright";
import { test, expect } from "@playwright/experimental-ct-vue";
const storybookTest = createTest();
storybookTest("Button renders correctly", async ({ mount }) => {
const component = await mount(MyButton, {
props: {
label: "Click me",
primary: true,
},
});
await expect(component).toContainText("Click me");
await expect(component).toHaveClass(/btn-primary/);
});import { createTest } from "@storybook/vue3/experimental-playwright";
import { composeStory } from "@storybook/vue3";
import Meta, { Primary } from "./Button.stories";
const test = createTest();
const PrimaryStory = composeStory(Primary, Meta);
test("Primary story renders correctly", async ({ mount }) => {
const component = await mount(PrimaryStory);
await expect(component).toBeVisible();
await expect(component.getByRole("button")).toHaveText("Button");
});import { createTest } from "@storybook/vue3/experimental-playwright";
const test = createTest();
test("Button interaction", async ({ mount }) => {
let clicked = false;
const component = await mount(MyButton, {
props: {
label: "Click me",
onClick: () => { clicked = true; },
},
});
await component.getByRole("button").click();
expect(clicked).toBe(true);
});import { createTest } from "@storybook/vue3/experimental-playwright";
const test = createTest();
test("Form submission", async ({ mount }) => {
const component = await mount(ContactForm, {
props: {
onSubmit: (data) => console.log("Form submitted:", data),
},
});
await component.getByLabel("Name").fill("John Doe");
await component.getByLabel("Email").fill("john@example.com");
await component.getByRole("button", { name: "Submit" }).click();
await expect(component.getByText("Form submitted successfully")).toBeVisible();
});// playwright-ct.config.ts
import { defineConfig, devices } from "@playwright/experimental-ct-vue";
import { resolve } from "path";
export default defineConfig({
testDir: "./src/components",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: "html",
use: {
trace: "on-first-retry",
ctViteConfig: {
resolve: {
alias: {
"@": resolve(__dirname, "./src"),
},
},
},
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
],
});// test-setup.ts
import { beforeMount } from "@playwright/experimental-ct-vue";
import { setup } from "@storybook/vue3";
import { createPinia } from "pinia";
// Setup global plugins for component tests
setup(() => createPinia());
beforeMount(async ({ app }) => {
// Additional test-specific setup
app.config.globalProperties.$testMode = true;
});import { createTest } from "@storybook/vue3/experimental-playwright";
const test = createTest();
test.describe("Button Component", () => {
test("renders with default props", async ({ mount }) => {
const component = await mount(MyButton);
await expect(component).toBeVisible();
});
test("applies custom styling", async ({ mount }) => {
const component = await mount(MyButton, {
props: { variant: "danger", size: "large" },
});
await expect(component).toHaveClass(/btn-danger/);
await expect(component).toHaveClass(/btn-lg/);
});
});import { createTest } from "@storybook/vue3/experimental-playwright";
import AxeBuilder from "@axe-core/playwright";
const test = createTest();
test("Button is accessible", async ({ mount, page }) => {
await mount(MyButton, {
props: { label: "Accessible Button" },
});
const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});import { createTest } from "@storybook/vue3/experimental-playwright";
const test = createTest();
test("Button visual regression", async ({ mount }) => {
const component = await mount(MyButton, {
props: {
label: "Visual Test Button",
primary: true,
},
});
await expect(component).toHaveScreenshot("primary-button.png");
});# .github/workflows/component-tests.yml
name: Component Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm install
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run component tests
run: npx playwright test -c playwright-ct.config.ts
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/Install with Tessl CLI
npx tessl i tessl/npm-storybook--vue3