From 03f4e415dfaa226b99534372eed1b979eef2bd17 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 17:48:13 +0800 Subject: [PATCH 1/8] E2E: Addon-actions playwright test --- code/e2e-tests/addon-actions.spec.ts | 26 ++++++++++++ code/e2e-tests/util.ts | 60 ++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 code/e2e-tests/addon-actions.spec.ts create mode 100644 code/e2e-tests/util.ts diff --git a/code/e2e-tests/addon-actions.spec.ts b/code/e2e-tests/addon-actions.spec.ts new file mode 100644 index 000000000000..efdfa76ce324 --- /dev/null +++ b/code/e2e-tests/addon-actions.spec.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-actions', () => { + test.beforeEach(async ({ page }) => { + await page.goto(storybookUrl); + }); + + test('should trigger an action', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-button', 'primary'); + const root = sbPage.previewRoot(); + const button = root.locator('button', { hasText: 'Button' }); + await button.click(); + + await sbPage.viewAddonPanel('Actions'); + const logItem = await page.locator('#storybook-panel-root #panel-tab-content', { + hasText: 'onClick', + }); + await expect(logItem).toBeVisible(); + }); +}); diff --git a/code/e2e-tests/util.ts b/code/e2e-tests/util.ts new file mode 100644 index 000000000000..2a30899a6123 --- /dev/null +++ b/code/e2e-tests/util.ts @@ -0,0 +1,60 @@ +/* eslint-disable jest/no-standalone-expect */ +import { expect, Locator, Page } from '@playwright/test'; + +export class SbPage { + readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + async navigateToStory(title: string, name: string) { + const titleId = title.replace(/ /g, '-').toLowerCase(); + const storyId = name.replace(/ /g, '-').toLowerCase(); + + const titleLink = this.page.locator(`#${titleId}`); + if ((await titleLink.getAttribute('aria-expanded')) === 'false') { + await titleLink.click(); + } + + const storyLinkId = `#${titleId}--${storyId}`; + await this.page.waitForSelector(storyLinkId); + const storyLink = this.page.locator(storyLinkId); + await storyLink.click({ force: true }); + + // assert url changes + const viewMode = name === 'docs' ? 'docs' : 'story'; + + const url = this.page.url(); + await expect(url).toContain(`path=/${viewMode}/${titleId}--${storyId}`); + + const selected = await storyLink.getAttribute('data-selected'); + await expect(selected).toBe('true'); + } + + previewIframe() { + return this.page.frameLocator('#storybook-preview-iframe'); + } + + previewRoot() { + const preview = this.previewIframe(); + return preview.locator('#root:visible, #docs-root:visible'); + } + + async viewAddonPanel(name: string) { + const tabs = await this.page.locator('[role=tablist] button[role=tab]'); + const tab = tabs.locator(`text=/^${name}/`); + await tab.click(); + } + + async selectToolbar(toolbarSelector: string, itemSelector?: string) { + await this.page.locator(toolbarSelector).click(); + if (itemSelector) { + await this.page.locator(itemSelector).click(); + } + } + + getCanvasBodyElement() { + return this.previewIframe().locator('body'); + } +} From 58fc426cfd5f2268aca242bc5e13580073d84f8a Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 17:48:35 +0800 Subject: [PATCH 2/8] E2E: Addon-backgrounds playwright test --- code/e2e-tests/addon-backgrounds.spec.ts | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 code/e2e-tests/addon-backgrounds.spec.ts diff --git a/code/e2e-tests/addon-backgrounds.spec.ts b/code/e2e-tests/addon-backgrounds.spec.ts new file mode 100644 index 000000000000..3cb70f8031a2 --- /dev/null +++ b/code/e2e-tests/addon-backgrounds.spec.ts @@ -0,0 +1,29 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-backgrounds', () => { + test.beforeEach(async ({ page }) => { + await page.goto(storybookUrl); + }); + + test('should have a dark background', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-button', 'primary'); + await sbPage.selectToolbar('[title="Change the background of the preview"]', '#dark'); + + await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-color', 'rgb(51, 51, 51)'); + }); + + test('should apply a grid', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-button', 'primary'); + await sbPage.selectToolbar('[title="Apply a grid to the preview"]'); + + await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-image', /linear-gradient/); + }); +}); From 41c1e359a434ecf3e921f80d144d301c9dd6f824 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 17:58:02 +0800 Subject: [PATCH 3/8] Fix deepscan --- code/e2e-tests/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/e2e-tests/util.ts b/code/e2e-tests/util.ts index 2a30899a6123..132f51fca0d0 100644 --- a/code/e2e-tests/util.ts +++ b/code/e2e-tests/util.ts @@ -1,5 +1,5 @@ /* eslint-disable jest/no-standalone-expect */ -import { expect, Locator, Page } from '@playwright/test'; +import { expect, Page } from '@playwright/test'; export class SbPage { readonly page: Page; From ba8561804ba10bb08144989d47719c3dc22330df Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 19:20:33 +0800 Subject: [PATCH 4/8] E2E: Addon-controls playwright test --- code/e2e-tests/addon-controls.spec.ts | 71 +++++++++++++++++++++++++++ code/e2e-tests/util.ts | 4 ++ 2 files changed, 75 insertions(+) create mode 100644 code/e2e-tests/addon-controls.spec.ts diff --git a/code/e2e-tests/addon-controls.spec.ts b/code/e2e-tests/addon-controls.spec.ts new file mode 100644 index 000000000000..a49f7cbeb489 --- /dev/null +++ b/code/e2e-tests/addon-controls.spec.ts @@ -0,0 +1,71 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-controls', () => { + test('should change component when changing controls', async ({ page }) => { + await page.goto(storybookUrl); + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-button', 'primary'); + await sbPage.viewAddonPanel('Controls'); + + // Text input: Label + await expect(sbPage.previewRoot().locator('button')).toContainText('Button'); + const label = sbPage.panelContent().locator('textarea[name=label]'); + await label.fill('Hello world'); + await expect(sbPage.previewRoot().locator('button')).toContainText('Hello world'); + + // Args in URL + await page.waitForTimeout(300); + const url = await page.url(); + await expect(url).toContain('args=label:Hello+world'); + + // Boolean toggle: Primary/secondary + await expect(sbPage.previewRoot().locator('button')).toHaveCSS( + 'background-color', + 'rgb(30, 167, 253)' + ); + const toggle = sbPage.panelContent().locator('input[name=primary]'); + await toggle.click(); + await expect(sbPage.previewRoot().locator('button')).toHaveCSS( + 'background-color', + 'rgba(0, 0, 0, 0)' + ); + + // Color picker: Background color + const color = sbPage.panelContent().locator('input[placeholder="Choose color..."]'); + await color.fill('red'); + await expect(sbPage.previewRoot().locator('button')).toHaveCSS( + 'background-color', + 'rgb(255, 0, 0)' + ); + + // TODO: enable this once the controls for size are aligned in all CLI templates. + // Radio buttons: Size + // cy.getStoryElement().find('button').should('have.css', 'font-size', '14px'); + // cy.get('label[for="size-large"]').click(); + // cy.getStoryElement().find('button').should('have.css', 'font-size', '16px'); + + // Reset controls: assert that the component is back to original state + const reset = sbPage.panelContent().locator('button[title="Reset controls"]'); + await reset.click(); + const button = sbPage.previewRoot().locator('button'); + await expect(button).toHaveCSS('font-size', '14px'); + await expect(button).toHaveCSS('background-color', 'rgb(30, 167, 253)'); + await expect(button).toContainText('Button'); + }); + + test('should apply controls automatically when passed via url', async ({ page }) => { + await page.goto(`${storybookUrl}?path=/story/example-button--primary&args=label:Hello+world`); + + const sbPage = new SbPage(page); + await expect(sbPage.previewRoot().locator('button')).toContainText('Hello world'); + + await sbPage.viewAddonPanel('Controls'); + const label = await sbPage.panelContent().locator('textarea[name=label]').inputValue(); + await expect(label).toEqual('Hello world'); + }); +}); diff --git a/code/e2e-tests/util.ts b/code/e2e-tests/util.ts index 132f51fca0d0..e9aef15095cf 100644 --- a/code/e2e-tests/util.ts +++ b/code/e2e-tests/util.ts @@ -41,6 +41,10 @@ export class SbPage { return preview.locator('#root:visible, #docs-root:visible'); } + panelContent() { + return this.page.locator('#storybook-panel-root #panel-tab-content'); + } + async viewAddonPanel(name: string) { const tabs = await this.page.locator('[role=tablist] button[role=tab]'); const tab = tabs.locator(`text=/^${name}/`); From cb20988f4ee33af6e5f63c637fcce89060678771 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 19:41:42 +0800 Subject: [PATCH 5/8] E2E: Addon-docs playwright test --- code/e2e-tests/addon-docs.spec.ts | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 code/e2e-tests/addon-docs.spec.ts diff --git a/code/e2e-tests/addon-docs.spec.ts b/code/e2e-tests/addon-docs.spec.ts new file mode 100644 index 000000000000..d4ddbaeec1a6 --- /dev/null +++ b/code/e2e-tests/addon-docs.spec.ts @@ -0,0 +1,35 @@ +/* eslint-disable no-await-in-loop */ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-docs', () => { + test.beforeEach(async ({ page }) => { + await page.goto(storybookUrl); + }); + + // FIXME: skip html/vue3 + test('should provide source snippet', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-button', 'docs'); + const root = sbPage.previewRoot(); + const toggles = root.locator('.docblock-code-toggle'); + + const toggleCount = await toggles.count(); + for (let i = 0; i < toggleCount; i += 1) { + const toggle = await toggles.nth(i); + await toggle.click({ force: true }); + } + + const codes = root.locator('pre.prismjs'); + const codeCount = await codes.count(); + for (let i = 0; i < codeCount; i += 1) { + const code = await codes.nth(i); + const text = await code.innerText(); + await expect(text).not.toMatch(/^\(args\) => /); + } + }); +}); From 23badb7d8d8811a42c68e80b678ff482517e6e5f Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 19:57:43 +0800 Subject: [PATCH 6/8] E2E: Addon-interactions playwright test --- code/e2e-tests/addon-interactions.spec.ts | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 code/e2e-tests/addon-interactions.spec.ts diff --git a/code/e2e-tests/addon-interactions.spec.ts b/code/e2e-tests/addon-interactions.spec.ts new file mode 100644 index 000000000000..52a517ce6790 --- /dev/null +++ b/code/e2e-tests/addon-interactions.spec.ts @@ -0,0 +1,33 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-interactions', () => { + test.beforeEach(async ({ page }) => { + await page.goto(storybookUrl); + }); + + // FIXME: skip xxx + test('should have interactions', async ({ page }) => { + const sbPage = new SbPage(page); + + await sbPage.navigateToStory('example-page', 'logged-in'); + await sbPage.viewAddonPanel('Interactions'); + + const welcome = await sbPage.previewRoot().locator('.welcome'); + await expect(welcome).toContainText('Welcome, Jane Doe!'); + + const interactionsTab = await page.locator('#tabbutton-interactions'); + await expect(interactionsTab).toContainText(/(1)/); + await expect(interactionsTab).toBeVisible(); + + const panel = sbPage.panelContent(); + await expect(panel).toContainText(/userEvent.click/); + await expect(panel).toBeVisible(); + + const done = await panel.locator('[data-testid=icon-done]'); + await expect(done).toBeVisible(); + }); +}); From 74f5836fa9d26afd1712efa41af6b523057d3229 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sun, 14 Aug 2022 20:02:38 +0800 Subject: [PATCH 7/8] E2E: Addon-viewport playwright test --- code/e2e-tests/addon-viewport.spec.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 code/e2e-tests/addon-viewport.spec.ts diff --git a/code/e2e-tests/addon-viewport.spec.ts b/code/e2e-tests/addon-viewport.spec.ts new file mode 100644 index 000000000000..a5935b4db2cd --- /dev/null +++ b/code/e2e-tests/addon-viewport.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('addon-viewport', () => { + test.beforeEach(async ({ page }) => { + await page.goto(storybookUrl); + }); + + test('should have viewport button in the toolbar', async ({ page }) => { + const sbPage = new SbPage(page); + + // Click on viewport button and select small mobile + await sbPage.navigateToStory('example-button', 'primary'); + await sbPage.selectToolbar('[title="Change the size of the preview"]', '#mobile1'); + + // Check that Button story is still displayed + await expect(sbPage.previewRoot()).toContainText('Button'); + }); +}); From 8e373f4b5495e83ba20515c13bc681485cbf405c Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Mon, 15 Aug 2022 08:29:52 +0800 Subject: [PATCH 8/8] E2E: Conditionally skip vue3 docs snippet tests --- code/e2e-tests/addon-docs.spec.ts | 9 +++++++-- scripts/tasks/e2e-tests.ts | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/code/e2e-tests/addon-docs.spec.ts b/code/e2e-tests/addon-docs.spec.ts index d4ddbaeec1a6..2be60673da1b 100644 --- a/code/e2e-tests/addon-docs.spec.ts +++ b/code/e2e-tests/addon-docs.spec.ts @@ -1,19 +1,24 @@ +/* eslint-disable jest/no-disabled-tests */ /* eslint-disable no-await-in-loop */ import { test, expect } from '@playwright/test'; import process from 'process'; import { SbPage } from './util'; const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; +const templateName = process.env.STORYBOOK_TEMPLATE_NAME || ''; test.describe('addon-docs', () => { test.beforeEach(async ({ page }) => { await page.goto(storybookUrl); }); - // FIXME: skip html/vue3 test('should provide source snippet', async ({ page }) => { - const sbPage = new SbPage(page); + test.skip( + /^vue3/.test(templateName), + `Skipping ${templateName}, which does not support dynamic source snippets` + ); + const sbPage = new SbPage(page); await sbPage.navigateToStory('example-button', 'docs'); const root = sbPage.previewRoot(); const toggles = root.locator('.docblock-code-toggle'); diff --git a/scripts/tasks/e2e-tests.ts b/scripts/tasks/e2e-tests.ts index 55633b6b07c9..ea72790736de 100644 --- a/scripts/tasks/e2e-tests.ts +++ b/scripts/tasks/e2e-tests.ts @@ -8,12 +8,13 @@ export const e2eTests: Task = { async ready() { return false; }, - async run(_, { builtSandboxDir, junitFilename }) { + async run(_, { builtSandboxDir, junitFilename, template }) { const storybookController = await serveSandbox(builtSandboxDir, {}); await exec('yarn playwright test --reporter=junit', { env: { STORYBOOK_URL: `http://localhost:8001`, + STORYBOOK_TEMPLATE_NAME: template.name, ...(junitFilename && { PLAYWRIGHT_JUNIT_OUTPUT_NAME: junitFilename, }),