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

E2E: Fix flaky e2e tests #23630

Merged
merged 9 commits into from
Aug 1, 2023
Merged
24 changes: 12 additions & 12 deletions code/addons/interactions/template/stories/basics.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,21 @@ export default {
},
};

export const Validation = {
play: async (context) => {
const { args, canvasElement, step } = context;
const canvas = within(canvasElement);

await step('Submit', async () => fireEvent.click(canvas.getByRole('button')));

await expect(args.onSuccess).not.toHaveBeenCalled();
},
};

export const Type = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.type(canvas.getByTestId('value'), 'test');
await userEvent.type(canvas.getByTestId('value'), 'foobar');
},
};

Expand Down Expand Up @@ -85,17 +96,6 @@ export const WithLoaders = {
},
};

export const Validation = {
play: async (context) => {
const { args, canvasElement, step } = context;
const canvas = within(canvasElement);

await step('Submit', async () => fireEvent.click(canvas.getByRole('button')));

await expect(args.onSuccess).not.toHaveBeenCalled();
},
};

export const UserEventSetup = {
play: async (context) => {
const { args, canvasElement, step } = context;
Expand Down
5 changes: 0 additions & 5 deletions code/e2e-tests/addon-actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import { SbPage } from './util';
const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';

test.describe('addon-actions', () => {
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test.beforeEach(async ({ page }) => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
Expand Down
7 changes: 1 addition & 6 deletions code/e2e-tests/addon-backgrounds.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@ import process from 'process';
import { SbPage } from './util';

const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';
const templateName = process.env.STORYBOOK_TEMPLATE_NAME;
const templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';

test.describe('addon-backgrounds', () => {
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test.beforeEach(async ({ page }) => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
Expand Down
5 changes: 0 additions & 5 deletions code/e2e-tests/addon-controls.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import { SbPage } from './util';
const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';

test.describe('addon-controls', () => {
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('should change component when changing controls', async ({ page }) => {
await page.goto(storybookUrl);
const sbPage = new SbPage(page);
Expand Down
6 changes: 1 addition & 5 deletions code/e2e-tests/addon-docs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ test.describe('addon-docs', () => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('should show descriptions for stories', async ({ page }) => {
const skipped = [
Expand Down Expand Up @@ -87,7 +83,7 @@ test.describe('addon-docs', () => {
});

test('should provide source snippet', async ({ page }) => {
// templateName is e.g. 'Vue-CLI (Default JS)'
// templateName is e.g. 'vue-cli/default-js'
test.skip(
/^(vue3|vue-cli|preact)/i.test(`${templateName}`),
`Skipping ${templateName}, which does not support dynamic source snippets`
Expand Down
23 changes: 3 additions & 20 deletions code/e2e-tests/addon-interactions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,9 @@ test.describe('addon-interactions', () => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

// FIXME: skip xxx
test('should have interactions', async ({ page }) => {
// templateName is e.g. 'Vue-CLI (Default JS)'
// templateName is e.g. 'vue-cli/default-js'
test.skip(
// eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
Expand Down Expand Up @@ -47,7 +42,7 @@ test.describe('addon-interactions', () => {
});

test('should step through interactions', async ({ page }) => {
// templateName is e.g. 'Vue-CLI (Default JS)'
// templateName is e.g. 'vue-cli/default-js'
test.skip(
// eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
Expand All @@ -56,7 +51,7 @@ test.describe('addon-interactions', () => {

const sbPage = new SbPage(page);

await sbPage.navigateToStory('addons/interactions/basics', 'type-and-clear');
await sbPage.deepLinkToStory(storybookUrl, 'addons/interactions/basics', 'type-and-clear');
await sbPage.viewAddonPanel('Interactions');

// Test initial state - Interactions have run, count is correct and values are as expected
Expand Down Expand Up @@ -109,18 +104,6 @@ test.describe('addon-interactions', () => {
await expect(interactionsTab).toBeVisible();
await expect(interactionsTab.getByText('3')).toBeVisible();

// After debugging I found that sometimes the toolbar gets hidden, maybe some keypress or session storage issue?
// if the toolbar is hidden, this will toggle the toolbar
if (await page.locator('[offset="40"]').isHidden()) {
await page.locator('html').press('t');
}

// After debugging I found that sometimes the toolbar gets hidden, maybe some keypress or session storage issue?
// if the toolbar is hidden, this will toggle the toolbar
if (await page.locator('[offset="40"]').isHidden()) {
await page.locator('html').press('t');
}

// Test remount state (from toolbar) - Interactions have rerun, count is correct and values are as expected
const remountComponentButton = await page.locator('[title="Remount component"]');
await remountComponentButton.click();
Expand Down
4 changes: 0 additions & 4 deletions code/e2e-tests/addon-viewport.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ test.describe('addon-viewport', () => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('should have viewport button in the toolbar', async ({ page }) => {
const sbPage = new SbPage(page);
Expand Down
4 changes: 0 additions & 4 deletions code/e2e-tests/framework-nextjs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ test.describe('Next.js', () => {
await page.goto(storybookUrl);
await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test.describe('next/image', () => {
let sbPage: SbPage;
Expand Down
6 changes: 1 addition & 5 deletions code/e2e-tests/json-files.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ import { test, expect } from '@playwright/test';
import process from 'process';

const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';
const templateName = process.env.STORYBOOK_TEMPLATE_NAME;
const templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';

test.describe('JSON files', () => {
test.beforeEach(async ({ page }) => {
await page.goto(storybookUrl);
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('should have index.json', async ({ page }) => {
test.skip(
Expand Down
4 changes: 0 additions & 4 deletions code/e2e-tests/manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ test.describe('manager', () => {

await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('shortcuts sidebar', async ({ page }) => {
const sbPage = new SbPage(page);
Expand Down
43 changes: 27 additions & 16 deletions code/e2e-tests/preview-web.spec.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
/* eslint-disable jest/no-disabled-tests */
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('preview-web', () => {
test.beforeEach(async ({ page }) => {
await page.goto(storybookUrl);

await new SbPage(page).waitUntilLoaded();
});
test.afterEach(async ({ page }) => {
await page.evaluate(() => window.localStorage.clear());
await page.evaluate(() => window.sessionStorage.clear());
});

test('should pass over shortcuts, but not from play functions, story', async ({ page }) => {
const sbPage = new SbPage(page);
await sbPage.navigateToStory('lib/preview-api/shortcuts', 'keydown-during-play');
test.skip(
// eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
`Skipping ${templateName}, which does not support addon-interactions`
);

const sbPage = new SbPage(page);
await sbPage.deepLinkToStory(storybookUrl, 'lib/preview-api/shortcuts', 'keydown-during-play');
await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();

await sbPage.previewRoot().locator('button').press('s');
// wait for the play function to complete
await sbPage.viewAddonPanel('Interactions');
const interactionsTab = await page.locator('#tabbutton-storybook-interactions-panel');
await expect(interactionsTab).toBeVisible();
const panel = sbPage.panelContent();
const runStatusBadge = await panel.locator('[aria-label="Status of the test run"]');
await expect(runStatusBadge).toContainText(/Pass/);

// click outside, to remove focus from the input of the story, then press S to toggle sidebar
await sbPage.previewRoot().click();
await sbPage.previewRoot().press('s');
await expect(sbPage.page.locator('.sidebar-container')).not.toBeVisible();

// restore the sidebar back to visible, because it is persisted in localStorage
await page.locator('html').press('s');
await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();
});

test('should pass over shortcuts, but not from play functions, docs', async ({ page }) => {
test.skip(
// eslint-disable-next-line jest/valid-title
/^(lit)/i.test(`${templateName}`),
`Skipping ${templateName}, which does not support addon-interactions`
);

const sbPage = new SbPage(page);
await sbPage.navigateToStory('lib/preview-api/shortcuts', 'docs');
await sbPage.deepLinkToStory(storybookUrl, 'lib/preview-api/shortcuts', 'docs');

await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();

await sbPage.previewRoot().getByRole('button').getByText('Submit').first().press('s');
await expect(sbPage.page.locator('.sidebar-container')).not.toBeVisible();

// restore the sidebar back to visible, because it is persisted in localStorage
await page.locator('html').press('s');
await expect(sbPage.page.locator('.sidebar-container')).toBeVisible();
});
});
25 changes: 25 additions & 0 deletions code/e2e-tests/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ export class SbPage {
}
}

/**
* Visit a story via the URL instead of selecting from the sidebar.
*/
async deepLinkToStory(baseURL: string, title: string, name: 'docs' | string) {
const titleId = toId(title);
const storyId = toId(name);
const storyLinkId = `${titleId}--${storyId}`;
const viewMode = name === 'docs' ? 'docs' : 'story';
await this.page.goto(`${baseURL}/?path=/${viewMode}/${storyLinkId}`);
}

/**
* Visit a story by selecting it from the sidebar.
*/
async navigateToStory(title: string, name: string) {
await this.openComponent(title);

Expand All @@ -46,6 +60,17 @@ export class SbPage {
}

async waitUntilLoaded() {
// make sure we start every test with clean state – to avoid possible flakyness
await this.page.context().addInitScript(() => {
const storeState = {
layout: {
showToolbar: true,
showNav: true,
showPanel: true,
},
};
window.sessionStorage.setItem('@storybook/manager/store', JSON.stringify(storeState));
}, {});
const root = this.previewRoot();
const docsLoadingPage = root.locator('.sb-preparing-docs');
const storyLoadingPage = root.locator('.sb-preparing-story');
Expand Down
2 changes: 1 addition & 1 deletion code/lib/preview-api/template/stories/shortcuts.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export const KeydownDuringPlay = {
const button = await within(canvasElement).findByText('Submit');
await userEvent.type(button, 's');

expect(previewKeydown).not.toBeCalled();
await expect(previewKeydown).not.toBeCalled();
},
};
9 changes: 3 additions & 6 deletions code/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
import { defineConfig, devices } from '@playwright/test';

/**
* Read environment variables from file.
Expand All @@ -10,7 +9,7 @@ import { devices } from '@playwright/test';
/**
* See https://playwright.dev/docs/test-configuration.
*/
const config: PlaywrightTestConfig = {
export default defineConfig({
testDir: './e2e-tests',
/* Maximum time one test can run for. */
timeout: 30 * 1000,
Expand Down Expand Up @@ -112,6 +111,4 @@ const config: PlaywrightTestConfig = {
// command: 'npm run start',
// port: 3000,
// },
};

export default config;
});
Loading