Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert cypress e2e tests to playwright #18932

Merged
merged 8 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions code/e2e-tests/addon-actions.spec.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
29 changes: 29 additions & 0 deletions code/e2e-tests/addon-backgrounds.spec.ts
Original file line number Diff line number Diff line change
@@ -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/);
});
});
71 changes: 71 additions & 0 deletions code/e2e-tests/addon-controls.spec.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
40 changes: 40 additions & 0 deletions code/e2e-tests/addon-docs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* 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);
});

test('should provide source snippet', async ({ 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');

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\) => /);
}
});
});
33 changes: 33 additions & 0 deletions code/e2e-tests/addon-interactions.spec.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
22 changes: 22 additions & 0 deletions code/e2e-tests/addon-viewport.spec.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
64 changes: 64 additions & 0 deletions code/e2e-tests/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable jest/no-standalone-expect */
import { expect, 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');
}

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}/`);
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');
}
}
3 changes: 2 additions & 1 deletion scripts/tasks/e2e-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}),
Expand Down