From c63a9bd2f8059b12ee61e0720f2c7bbb8e1830ef Mon Sep 17 00:00:00 2001 From: carocao-msft <96077406+carocao-msft@users.noreply.github.com> Date: Mon, 10 Mar 2025 20:42:47 +0000 Subject: [PATCH] test --- common/config/rush/pnpm-lock.yaml | 6 ++- packages/storybook8/package.json | 9 +++- packages/storybook8/test/playwright.config.ts | 47 +++++++++++++++++++ .../storybook8/test/tests/storybook.spec.ts | 37 +++++++++++++++ packages/storybook8/test/utils.ts | 37 +++++++++++++++ packages/storybook8/tsconfig.json | 11 ++++- 6 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 packages/storybook8/test/playwright.config.ts create mode 100644 packages/storybook8/test/tests/storybook.spec.ts create mode 100644 packages/storybook8/test/utils.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 81ab15898b5..ef584bbd560 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -19904,7 +19904,7 @@ packages: dev: false file:projects/storybook8.tgz: - resolution: {integrity: sha512-bWsxxyeBNIRzRrQzU9HWhQp3uoED7TcGs+OM0YcU4uw58c0NrHcxfRyUDYOr99D4uXxZcMd6V0qNX7RGnYZOyA==, tarball: file:projects/storybook8.tgz} + resolution: {integrity: sha512-GkK0UK/9cmwIaBp5g8mqscPZttK3GYgOR6HEg93yKFCLmAdkM4AEhcNkACD4J9FtG0/MLLMhoCktbxcdzcFYBA==, tarball: file:projects/storybook8.tgz} name: '@rush-temp/storybook8' version: 0.0.0 dependencies: @@ -19924,6 +19924,7 @@ packages: '@mdx-js/react': 1.6.22(react@18.3.1) '@microsoft/applicationinsights-react-js': 3.4.3(react@18.3.1)(tslib@2.8.1) '@microsoft/applicationinsights-web': 2.8.18(tslib@2.8.1) + '@playwright/test': 1.50.1 '@storybook/addon-actions': 8.2.6(storybook@8.2.6) '@storybook/addon-controls': 8.2.6(storybook@8.2.6) '@storybook/addon-docs': 8.2.6(storybook@8.2.6) @@ -19960,6 +19961,7 @@ packages: copyfiles: 2.4.1 core-js: 3.40.0 cross-env: 7.0.3 + dotenv: 10.0.0 eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) eslint-plugin-header: 3.1.1(eslint@8.57.1) @@ -19969,6 +19971,7 @@ packages: eslint-plugin-prettier: 5.2.3(eslint-config-prettier@9.1.0)(eslint@8.57.1)(prettier@3.3.2) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) + express: 5.0.1 husky: 8.0.3 jest: 29.7.0(@types/node@22.10.10)(ts-node@10.9.2) jest-fetch-mock: 3.0.3 @@ -19976,6 +19979,7 @@ packages: json-stringify-safe: 5.0.1 nan: 2.22.0 node-forge: 1.3.1 + path: 0.12.7 preact: 10.25.4 prettier: 3.3.2 pretty-quick: 4.0.0(prettier@3.3.2) diff --git a/packages/storybook8/package.json b/packages/storybook8/package.json index 5ed2ac3cea5..7fdc86ae4d5 100644 --- a/packages/storybook8/package.json +++ b/packages/storybook8/package.json @@ -17,7 +17,8 @@ "prettier:check": "prettier --no-error-on-unmatched-pattern --check --config ../../.prettierrc --ignore-path=../../.prettierignore \"**/*.js\" \"**/*.jsx\" \"**/*.ts\" \"**/*.tsx\"", "lint": "node ./scripts/lint.mjs", "lint:fix": "rushx lint --fix --", - "lint:quiet": "rushx lint -- --quiet" + "lint:quiet": "rushx lint -- --quiet", + "test:stories": "npx playwright test -c test/playwright.config.ts" }, "license": "MIT", "dependencies": { @@ -116,6 +117,10 @@ "ts-loader": "^8.0.12", "ts-node": "^10.9.2", "typescript": "5.4.5", - "webpack": "5.95.0" + "webpack": "5.95.0", + "@playwright/test": "~1.50.1", + "dotenv": "^10.0.0", + "express": "^5.0.1", + "path": "0.12.7" } } diff --git a/packages/storybook8/test/playwright.config.ts b/packages/storybook8/test/playwright.config.ts new file mode 100644 index 00000000000..2b14cd0f6f3 --- /dev/null +++ b/packages/storybook8/test/playwright.config.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + // Look for test files in the "tests" directory, relative to this configuration file. + testDir: './tests', + + // Run all tests in parallel. + fullyParallel: true, + + // Fail the build on CI if you accidentally left test.only in the source code. + forbidOnly: !!process.env.CI, + + // Retry on CI only. + retries: process.env.CI ? 2 : 0, + + // Opt out of parallel tests on CI. + workers: process.env.CI ? 1 : undefined, + + // Reporter to use + reporter: 'html', + + timeout: 300000, // Increase global timeout to 5 minutes (300,000ms) + + use: { + // Base URL to use in actions like `await page.goto('/')`. + baseURL: 'http://127.0.0.1:6006', + + // Collect trace when retrying the failed test. + trace: 'on-first-retry', + }, + // Configure projects for major browsers. + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + ], + // Run your local dev server before starting the tests. + // webServer: { + // command: 'npm run start', + // url: 'http://127.0.0.1:6006', + // reuseExistingServer: !process.env.CI + // } +}); diff --git a/packages/storybook8/test/tests/storybook.spec.ts b/packages/storybook8/test/tests/storybook.spec.ts new file mode 100644 index 00000000000..ac0d7e68b66 --- /dev/null +++ b/packages/storybook8/test/tests/storybook.spec.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { expect, Locator, test } from '@playwright/test'; +import { loadStory, getStoryIds } from '../utils.js'; + +test('Take screenshots of all stories', async ({ page }) => { + const storyIds = await getStoryIds(page); + + for (const storyId of storyIds) { + await loadStory(page, `docs/${storyId}`); + await page.waitForSelector('#root'); + await page.getByRole('button', { name: 'Go full screen [⌥ F]' }).click(); + await expect(page).toHaveScreenshot(`${storyId}.png`); + // const hrefs = await page.locator("//div[contains(@class, 'sbdocs')").getAttribute('href'); + // get all the elements that have a href attribute and id not in storyids + // const elements = await page.locator("//a[starts-with(@class, 'sbdocs')]"); + const elements = await page.locator('a'); + console.log(elements); + const linkCount = await elements.count(); + console.log(linkCount); + if (linkCount === 0) { + console.log('No links found'); + } else { + for (let i = 0; i < linkCount; i++) { + // //get the text of the quote + // const link = await elements.nth(i).getAttribute('href'); + // //log it to the console + // console.log(`Quote: ${link}`); + // await page.goto(link, { waitUntil: 'networkidle' }); + await elements.nth(i).click(); + await page.waitForSelector('#root'); + await expect(page).toHaveScreenshot(`${storyId}-${elements.innerText}.png`); + } + } + } +}); diff --git a/packages/storybook8/test/utils.ts b/packages/storybook8/test/utils.ts new file mode 100644 index 00000000000..cadab655b50 --- /dev/null +++ b/packages/storybook8/test/utils.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { Page } from '@playwright/test'; + +/** + * Load a specific Storybook story for Playwright testing. + * @param page - The Playwright page object. + * @param storyId - The ID of the story to load. + */ +export async function loadStory(page: Page, storyId: string) { + const url = `https://azure.github.io/communication-ui-library/?path=/${storyId}`; + console.log(url); + await page.goto(url, { waitUntil: 'networkidle' }); + await page.waitForSelector('#root'); +} + +/** + * Get all Storybook story IDs. + * @param page - The Playwright page object. + * @returns An array of story IDs. + */ +export async function getStoryIds(page: Page): Promise { + await page.goto('https://azure.github.io/communication-ui-library/?path=/docs/overview--docs'); + await page.waitForSelector('#root'); + const storyIds = await page.evaluate(() => { + const elements = document.querySelectorAll('a'); + const ids: string[] = []; + for (const element of elements) { + if (element.getAttribute('id') !== null) { + ids.push(element.getAttribute('id') ?? ''); + } + } + return ids; + }); + return storyIds; +} diff --git a/packages/storybook8/tsconfig.json b/packages/storybook8/tsconfig.json index 6a6189c0202..56743e87af7 100644 --- a/packages/storybook8/tsconfig.json +++ b/packages/storybook8/tsconfig.json @@ -2,6 +2,15 @@ "baseUrl": ".", "extends": "../../common/config/tsc/tsconfig.json", "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "rootDir": "./", "outDir": "./dist", "paths": { "@azure/communication-react": ["../communication-react/src"], @@ -16,6 +25,6 @@ } }, "typeRoots": ["./node_modules/@types"], - "include": ["stories/**/*"], + "include": ["stories/**/*","src", "test"], "exclude": ["dist", "node_modules"] }