зеркало из
1
0
Форкнуть 0

Playwright components testing setup (#4096)

This commit is contained in:
vhuseinova-msft 2024-02-07 11:37:36 -08:00 коммит произвёл GitHub
Родитель 4dce2080c7
Коммит 872eb3ce96
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
33 изменённых файлов: 3207 добавлений и 1996 удалений

61
.github/workflows/ci.yml поставляемый
Просмотреть файл

@ -500,6 +500,67 @@ jobs:
repo: context.repo.repo,
body: 'Failed to pass the composite UI Test. If this PR is for UI change and the error is snapshot mismatch, please add "update_snapshots" label to the PR for updating the snapshot.'
})
components_automation_test:
needs: get_matrix
name: 'Components automation test (${{ matrix.flavor }})'
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJSON(needs.get_matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: common/temp/pnpm-store
key: ${{ runner.os }}-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }}
- name: Install rush
run: npm install -g @microsoft/rush
- name: Install dependencies
run: rush install --max-install-attempts 3
- uses: browser-actions/setup-chrome@v1
id: setup-chrome
with:
chrome-version: 120.0.6099
- name: Switch flavor for build
id: switch-flavor
if: ${{ matrix.flavor != 'beta' }}
run: |
rush switch-flavor:${{ matrix.flavor }}
node ./common/scripts/force-build-flavor.mjs ${{ matrix.flavor }}
- name: Run dependency update for stable
if: ${{ matrix.flavor == 'stable' }}
run: rush update:stable
- name: Components Visual Regression Tests
id: visualregressiontests
run: |
cd packages/react-components
rushx test:components
env:
CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
- name: Upload snapshot diff
if: ${{ always() && steps.visualregressiontests.outcome == 'failure' }}
uses: actions/upload-artifact@v3
with:
name: snapshots
path: packages/react-components/tests/
- name: Comment on PR
if: ${{ github.event_name == 'pull_request' && always() && steps.visualregressiontests.outcome == 'failure' && !contains( github.event.pull_request.labels.*.name, 'update_snapshots') }}
uses: actions/github-script@v3
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Failed to pass the UI Test. If this PR is for UI change and the error is snapshot mismatch, please add "update_snapshots" label to the PR for updating the snapshot.'
})
build_storybook:
name: Build Storybook

88
.github/workflows/update-snapshots.yml поставляемый
Просмотреть файл

@ -540,6 +540,94 @@ jobs:
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
git push
components:
needs: [precondition, get_matrix]
if: needs.precondition.outputs.met
name: Update packages/react-components browser test snapshots
runs-on: ubuntu-latest
permissions: read-all
strategy:
matrix: ${{ fromJSON(needs.get_matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# Use a machine account when checking out. This is to workaround the issue where GitHub
# actions, when using the default account, cannot trigger other actions.
# This machine account is only for this PAT, pwd was created and thrown away
# If an update is needed, create a new account, add access to the repo and generate a new PAT
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
- name: Checkout branch if on a PR
if: ${{ github.event_name != 'workflow_dispatch' }}
# On the `pull_request` event, actions/checkout@v3 leaves the local checkout in a detached head state.
# Explicitly checkout the target branch so we can push later.
run: git checkout ${{ github.event.pull_request.head.ref }}
- name: Setup bot git information
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
run: |
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "github-actions[bot]"
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '20.x'
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: common/temp/pnpm-store
key: ${{ runner.os }}-${{ hashFiles('common/config/rush/pnpm-lock.yaml') }}
- name: Install rush
run: npm install -g @microsoft/rush@5.112.2
- name: Install dependencies
run: rush install --max-install-attempts 3
- uses: browser-actions/setup-chrome@v1
id: setup-chrome
with:
chrome-version: 120.0.6099
- name: Switch flavor for build
if: ${{ matrix.flavor != 'beta' }}
run: rush switch-flavor:${{ matrix.flavor }}
- name: Update components snapshots
id: update-components-snapshots
run: rushx test:components:update
working-directory: ./packages/react-components
env:
CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
- name: Upload snapshot diff
if: ${{ always() && steps.update-components-snapshots.outcome == 'failure' }}
uses: actions/upload-artifact@v3
with:
name: snapshots
path: packages/react-components/tests/temp/
# Check if files have changed
# More information see: https://stackoverflow.com/questions/3878624/how-do-i-programmatically-determine-if-there-are-uncommitted-changes
- name: Check for snapshot changes
id: changescheck
run: |
if [[ -z $(git status packages -s) ]]
then
echo "hasChanged=false" >> $GITHUB_OUTPUT
else
echo "hasChanged=true" >> $GITHUB_OUTPUT
fi
- name: Push new snapshots, if any
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
# This allows multiple snapshot update jobs in this action to run concurrently.
# - The only files updated locally are UI snapshots
# - Each job is responsible for a unique set of UI snapshots
# Thus we do not expect any merge conflicts due to the concurrent jobs from this workflows.
#
# If the UI snapshots are updated in the upstream branch while this job was running
# (e.g., due to a merge from the base_ref for a PR), this merge will fail, and the
# workflow will have to be triggered again. This is the desired behavior because the workflow
# should not silently overwrite updates to the target branch.
run: |
git add packages/react-components/*.png
git commit -m 'Update packages/react-components browser test snapshots'
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
git push
push_updated_snapshots:
needs: [component_examples, html_bundle, call_composite, chat_composite, callwithchat_composite]
if: needs.precondition.outputs.met

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "none",
"area": "feature",
"workstream": "Reliability",
"comment": "Playwright components testing setup",
"packageName": "@azure/communication-react",
"email": "98852890+vhuseinova-msft@users.noreply.github.com",
"dependentChangeType": "none"
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "none",
"area": "feature",
"workstream": "Reliability",
"comment": "Playwright components testing setup",
"packageName": "@azure/communication-react",
"email": "98852890+vhuseinova-msft@users.noreply.github.com",
"dependentChangeType": "none"
}

Просмотреть файл

@ -18,6 +18,7 @@
"devDependencies": {
"@actions/core": "^1.10.1",
"@octokit/rest": "~19.0.3",
"@playwright/test": "~1.39.0",
"@rollup/plugin-commonjs": "~25.0.7",
"@rollup/plugin-json": "^6.0.1",
"@types/node": "^20.11.10",

Просмотреть файл

@ -0,0 +1,74 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { PlaywrightTestConfig, devices } from '@playwright/test';
import {
ANDROID_USER_AGENT,
DESKTOP_4_TO_3_VIEWPORT,
DESKTOP_USER_AGENT,
MINUTE,
chromeLaunchOptions,
TestOptions
} from './playwrightConfigConstants';
const isBetaBuild = process.env['COMMUNICATION_REACT_FLAVOR'] === 'beta';
export const config: PlaywrightTestConfig<TestOptions> = {
// Extend per-test timeout for local debugging so that developers can single-step through
// the test in playwright inspector.
timeout: process.env.LOCAL_DEBUG ? 10 * MINUTE : 2 * MINUTE,
// Do not allow `.only` to be committed to the codebase. `.only` should only be used for diagnosing issues.
forbidOnly: !!process.env.CI,
// One chance to retry a test on failure
retries: 1,
// Applies to all projects
use: {
headless: !process.env.LOCAL_DEBUG,
video: 'on-first-retry', // No traces on first attempt - this seems to make tests flaky.
},
projects: [
{
name: 'Desktop Chrome',
use: {
viewport: DESKTOP_4_TO_3_VIEWPORT,
launchOptions: { ...chromeLaunchOptions },
contextOptions: {
userAgent: DESKTOP_USER_AGENT
},
isBetaBuild: isBetaBuild
}
},
{
name: 'Mobile Android Portrait',
use: {
...devices['Nexus 5'],
launchOptions: { ...chromeLaunchOptions },
userAgent: ANDROID_USER_AGENT,
isBetaBuild: isBetaBuild
}
},
{
name: 'Mobile Android Landscape',
use: {
userAgent: ANDROID_USER_AGENT,
// Support smallest supported mobile viewport (iPhone 5/SE) ({ width: 568, height: 320 })
viewport: { width: 568, height: 320 },
deviceScaleFactor: 2,
isMobile: true,
hasTouch: true,
defaultBrowserType: 'chromium',
launchOptions: { ...chromeLaunchOptions },
isBetaBuild: isBetaBuild
}
}
],
expect: {
toMatchSnapshot: {
maxDiffPixels: 1
}
}
};

Просмотреть файл

@ -0,0 +1,49 @@
import { LaunchOptions } from '@playwright/test';
import path from 'path';
export const DESKTOP_4_TO_3_VIEWPORT = {
width: 1024,
height: 768
};
export const DESKTOP_16_TO_9_VIEWPORT = {
width: 1024,
height: 576
};
export const chromeLaunchOptions: LaunchOptions = {
channel: 'chrome',
permissions: ['notifications', 'camera', 'microphone'],
args: [
'--font-render-hinting=none', // Ensures that fonts are rendered consistently.
'--enable-font-antialiasing', // Ensures that fonts are rendered consistently.
'--disable-gpu', // Ensures that fonts are rendered consistently.
'--allow-file-access',
'--use-fake-ui-for-media-stream',
'--use-fake-device-for-media-stream',
`--use-file-for-fake-video-capture=${path.join(__dirname, 'test.y4m')}`,
'--lang=en-US',
'--mute-audio'
],
ignoreDefaultArgs: [
'--hide-scrollbars' // Don't hide scrollbars in headless mode.
],
// Use the CHROME_PATH environment variable if it's set, otherwise use the default installed browser by playwright.
// We use a pinned version in GitHub actions to ensure newer versions of Chrome don't suddenly impact our tests.
// For more information see: [Automated Tests - Pinned version of Chrome](../../docs/automated-tests.md#pinned-version-of-chrome)
executablePath: process.env.CHROME_PATH ? process.env.CHROME_PATH : undefined
};
const SECOND = 1000;
export const MINUTE = 60 * SECOND;
// Using chromium useragent with a very high version to avoid breaking the unsupportedBrowser page
export const DESKTOP_USER_AGENT = 'Windows Chrome/999.0.0.0';
export const ANDROID_USER_AGENT = 'Android 99 Chrome/999.0.0.0 Mobile';
/**
* Represents the option that should be used to skip tests for stable
*/
export type TestOptions = {
isBetaBuild: boolean;
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -47,6 +47,7 @@ Most often, you should write a combination of unit-tests and hermetic browser te
| Test Type | Characteristics | When to write |
| ----------------- | --------------------------------- | ------------------------------------------- |
| unit-tests | +fast, +not-flakey, -narrow | Complex business logic, helper functions |
| components | +fast, less-flakey | Validate features for components only |
| browser: hermetic | fast-ish, less-flakey, e2e/static | Validate features, composite snapshots |
| browser: live | -slow, -flakey, +faithful | Smoke testing, critical user journeys |
| storybook | ?? | ?? |

Просмотреть файл

@ -90,6 +90,13 @@ module.exports = {
env: {
jest: true
}
},
{
// disable no-restricted-imports for playwright tests
files: ['./tests/browser/**/*.spec.ts', './tests/browser/**/*.spec.tsx'],
rules: {
'no-restricted-imports': 'off'
}
}
]
};

8
packages/react-components/.gitignore поставляемый
Просмотреть файл

@ -8,4 +8,10 @@ SDK/scripts/
SDK/cached-package.json
# Output files
*.tgz
*.tgz
#Playwright
**/test-results/
**/playwright-report/
**/blob-report/
**/playwright/.cache/

Просмотреть файл

@ -32,7 +32,9 @@
"_build:by-flavor": "rushx clean && rushx build:esm && rushx build:cjs && rushx _api-extractor:by-flavor",
"_by-flavor": "rushx _current-flavor && env-cmd -f ../../common/config/env/.env --use-shell",
"_current-flavor": "echo You are running under COMMUNICATION_REACT_FLAVOR: && env-cmd -f ../../common/config/env/.env node -p process.env.COMMUNICATION_REACT_FLAVOR",
"_test:by-flavor": "(npm run _if-preprocess && rushx preprocess || if-env COMMUNICATION_REACT_FLAVOR=beta && echo \"skip preprocess\") && jest"
"_test:by-flavor": "(npm run _if-preprocess && rushx preprocess || if-env COMMUNICATION_REACT_FLAVOR=beta && echo \"skip preprocess\") && jest",
"test:components": "rushx _by-flavor \"npx playwright test -c playwright.config.components.ts\"",
"test:components:update": "rushx _by-flavor \"npx playwright test -c playwright.config.components.ts --update-snapshots\""
},
"license": "MIT",
"dependencies": {
@ -70,6 +72,7 @@
"@babel/preset-env": "7.23.9",
"@microsoft/api-documenter": "~7.23.20",
"@microsoft/api-extractor": "~7.39.4",
"@playwright/experimental-ct-react": "~1.39.0",
"@rollup/plugin-json": "^6.0.1",
"@testing-library/dom": "^9.3.1",
"@testing-library/jest-dom": "^6.3.0",
@ -85,6 +88,7 @@
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^6.19.1",
"@typescript-eslint/parser": "^6.19.1",
"@vitejs/plugin-react": "~4.2.1",
"ajv": "^8.12.0",
"babel-jest": "^29.5.0",
"babel-loader": "8.1.0",
@ -105,6 +109,7 @@
"eslint": "^7.7.0",
"husky": "^8.0.3",
"if-env": "^1.0.4",
"jest-environment-jsdom": "^29.5.0",
"jest-fetch-mock": "^3.0.3",
"jest-junit": "^16.0.0",
"jest": "29.7.0",
@ -125,7 +130,6 @@
"ts-node": "^10.9.2",
"type-fest": "^3.13.1",
"typescript": "5.3.3",
"webpack": "5.89.0",
"jest-environment-jsdom": "^29.5.0"
"webpack": "5.89.0"
}
}

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { PlaywrightTestConfig, defineConfig, devices } from '@playwright/experimental-ct-react';
import react from '@vitejs/plugin-react';
import { TestOptions } from '../../common/config/playwright/playwrightConfigConstants';
import { config as commonConfig } from '../../common/config/playwright/playwright.config.common';
const isBetaBuild = process.env['COMMUNICATION_REACT_FLAVOR'] === 'beta';
const componentsConfig: PlaywrightTestConfig<TestOptions> = {
...commonConfig,
outputDir: './tests/temp/',
testDir: './tests/browser/',
testMatch: '*.spec.tsx',
snapshotDir: isBetaBuild ? './tests/snapshots/beta' : './tests/snapshots/stable'
};
const ctViteConfig = {
plugins: [
react({
include: /\.(js|jsx|ts|tsx)$/,
babel: {
// Use .babelrc files
babelrc: true,
// Use babel.config.js files
configFile: true
}
})
]
};
if (componentsConfig.use) {
componentsConfig.use.ctViteConfig = ctViteConfig;
} else {
componentsConfig.use = { ctViteConfig };
}
export default defineConfig<TestOptions>(componentsConfig);

Просмотреть файл

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Testing Page</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// Apply theme here, add anything your component needs at runtime here.

Просмотреть файл

@ -0,0 +1,91 @@
# Components browser tests
This folder contains some Playwright browser tests for the components. See the [top-level testing documentation](../../../docs/references/automated-tests.md) to understand how these tests fit into our overall testing strategy.
## Folder structure
* [../playwright.config.components.ts](../playwright.config.components.ts) Configuration for components tests
* [../playwright](../playwright) - Files needed for Playwright component testing
* [../playwright/.cache](../playwright/.cache) - Vite cache
* [../tests](../tests) - Top folder for snapshot tests, snapshots and tests output
* [../tests/browser](../tests/browser) - Components tests
* [../tests/snapshots](../tests/snapshots) - Snapshots for the beta and stable flavors
* [../tests/temp](../tests/temp) - Tests output (including the diff for failed tests)
## Run tests
In `packages/react-components`, run
```sh
rushx test:components
```
The tests will be run for the current flavor.
## Update snapshots
Snapshots must only be updated as part of the CI pipeline. This is because the build agents may run on a different OS and have different graphics setup that your local machine (so there will be slight pixel differences between locally generated snapshots and ones generated by the CI pipeline).
To update snapshots,
- Add the `update_snapshots` label to your PR.
- The [update-snapshots.yml](https://github.com/Azure/communication-ui-library/actions/workflows/update-snapshots.yml) GitHub action will generate new snapshots and push commit to your branch.
- The workflow will remove the `update_snapshots` label from your PR. If you need to update snapshots again, you must add the label once again.
### Manual updates
As mentioned above, you should not need to update snapshots manually. This section describes the tooling available for snapshot update. This tooling is also used by the GitHub action mentioned above.
The CI job uses
```sh
rushx test:components:update
```
script to update the snapshots.
## Test development
The components tests are lightweight and use less resources comparing with the usual Playwright tests.
A file with extension `.spec.tsx` should be created for new components tests.
### Conditional Compilation
Just like the rest of the UI library code, the components test use babel plugin to process the code. But the tests themselves can't use conditional compilation flags to be processed and need to use skip and fixtures feature in Playwright to be run for different flavors.
The fixture flag is already added to the Playwright configuration file and `FlavoredBaseTest.tsx` to be reused during future development.
In order to use the functionality, you will need:
- import `test` from `FlavoredBaseTest.tsx`
```Typescript
import { test as betaTest } from './FlavoredBaseTest';
```
- add a separate `describe` block and use skip function inside it before any beta tests (there may be a few descibe block for different beta functionality)
```Typescript
//This is an example of a description with a eta only test
betaTest.describe('TypingIndicator beta only test', () => {
betaTest.skip(({ isBetaBuild }) => !isBetaBuild, 'The tests should be run for beta flavor only');
betaTest('TypingIndicator should be shown correctly 123', async ({ mount }) => {
// some test
});
});
```
### Local debugging and UI mode
Run `rushx test:components --debug` command in Terminal from the `packages/react-components` folder to debug tests locally.
Run `rushx test:components --ui` command in Terminal from the `packages/react-components` folder to run tests in UI mode.
In debug mode the script runs the test under [Playwright Inspector](https://playwright.dev/docs/debug). Additionally, some internal test timeouts are relaxed to allow you to single-step through the tests via the inspector.
This mode requires a display device because the tests need to run in a browser with a display. In particular, this means that you can not use this mode on GitHub Codespaces.
To debug a particular test,
* Select the test to run via [`test.only`](https://playwright.dev/docs/api/class-test#test-only)
```typescript
test.describe('describe example', () => {
test.only('test example', async () => {
...
```
* Run the relevant test suite, usually selecting a single project: `rushx test:components --debug`
* Single-step through the test, record a video etc through the Inspector.

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { test as base } from '@playwright/experimental-ct-react';
import { TestOptions } from '../../../../common/config/playwright/playwrightConfigConstants';
/**
* The test function that should be used to skip tests for stable
*/
export const test = base.extend<TestOptions>({
// Define an option and provide a default value.
// This will be overridden in the config.
isBetaBuild: [true, { option: true }]
});

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React from 'react';
import { test, expect } from '@playwright/experimental-ct-react';
import { TypingIndicator } from '../../src/components/TypingIndicator';
// import { test as betaTest } from './FlavoredBaseTest';
test.describe('TypingIndicator tests', () => {
test('TypingIndicator should be shown correctly when 1 user is typing', async ({ mount }) => {
const component = await mount(<TypingIndicator typingUsers={[{ userId: '1', displayName: 'User 1' }]} />);
await component.evaluate(() => document.fonts.ready);
await expect(component).toContainText('User 1 is typing ...');
await expect(component).toHaveScreenshot('typing-indicator-1-user.png');
});
test('TypingIndicator should be shown correctly when 5 users are typing', async ({ mount }) => {
const users: { userId: string; displayName: string }[] = [];
for (let i = 1; i <= 5; i++) {
users.push({ userId: `${i}`, displayName: `User ${i}` });
}
const component = await mount(<TypingIndicator typingUsers={users} />);
await component.evaluate(() => document.fonts.ready);
await expect(component).toContainText('User 1, User 2, User 3, User 4 and 1 other are typing ...');
await expect(component).toHaveScreenshot('typing-indicator-5-users.png');
});
});
// This is an example of beta only test, to be deleted when we have some beta tests examples
// betaTest.describe('TypingIndicator beta only test', () => {
// betaTest.skip(({ isStableBuild }) => isStableBuild, 'The tests should be run for beta flavor only');
//
// betaTest('TypingIndicator should be shown correctly 123', async ({ mount }) => {
// const component = await mount(<TypingIndicator typingUsers={[{ userId: '1', displayName: 'User 1' }]} />);
// await component.evaluate(() => document.fonts.ready);
// await expect(component).toContainText('User 1 is typing ...');
// await expect(component).toHaveScreenshot('typing-indicator-1-user-123.png');
// });
// });

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

Просмотреть файл

@ -1,18 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { PlaywrightTestConfig, devices, ReporterDescription } from '@playwright/test';
import path from 'path';
const DESKTOP_4_TO_3_VIEWPORT = {
width: 1024,
height: 768
};
const DESKTOP_16_TO_9_VIEWPORT = {
width: 1024,
height: 576
};
import { ReporterDescription } from '@playwright/test';
import {
DESKTOP_16_TO_9_VIEWPORT,
DESKTOP_USER_AGENT,
chromeLaunchOptions
} from '../../common/config/playwright/playwrightConfigConstants';
import { config as commonConfig } from '../../common/config/playwright/playwright.config.common';
const testDir = process.env.TEST_DIR;
if (!testDir) {
@ -27,109 +22,27 @@ if (!outputDir) {
throw new Error('Environment variable PLAYWRIGHT_OUTPUT_DIR not set');
}
const chromeLaunchOptions = {
channel: 'chrome',
permissions: ['notifications', 'camera', 'microphone'],
args: [
'--font-render-hinting=none', // Ensures that fonts are rendered consistently.
'--enable-font-antialiasing', // Ensures that fonts are rendered consistently.
'--disable-gpu', // Ensures that fonts are rendered consistently.
'--allow-file-access',
'--use-fake-ui-for-media-stream',
'--use-fake-device-for-media-stream',
`--use-file-for-fake-video-capture=${path.join(__dirname, 'tests', 'browser', 'common', 'test.y4m')}`,
'--lang=en-US',
'--mute-audio'
],
ignoreDefaultArgs: [
'--hide-scrollbars' // Don't hide scrollbars in headless mode.
],
// Use the CHROME_PATH environment variable if it's set, otherwise use the default installed browser by playwright.
// We use a pinned version in GitHub actions to ensure newer versions of Chrome don't suddenly impact our tests.
// For more information see: [Automated Tests - Pinned version of Chrome](../../docs/automated-tests.md#pinned-version-of-chrome)
executablePath: process.env.CHROME_PATH ? process.env.CHROME_PATH : undefined
};
const CI_REPORTERS: ReporterDescription[] = [['dot'], ['json', { outputFile: `${outputDir}/e2e-results.json` }]];
const LOCAL_REPORTERS: ReporterDescription[] = [['list']];
const SECOND = 1000;
const MINUTE = 60 * SECOND;
// Using chromium useragent with a very high version to avoid breaking the unsupportedBrowser page
const DESKTOP_USER_AGENT = 'Windows Chrome/999.0.0.0';
const ANDROID_USER_AGENT = 'Android 99 Chrome/999.0.0.0 Mobile';
const config: PlaywrightTestConfig = {
const config = {
...commonConfig,
outputDir: outputDir,
// Extend per-test timeout for local debugging so that developers can single-step through
// the test in playwright inspector.
timeout: process.env.LOCAL_DEBUG ? 10 * MINUTE : 2 * MINUTE,
// Do not allow `.only` to be committed to the codebase. `.only` should only be used for diagnosing issues.
forbidOnly: !!process.env.CI,
// One chance to retry a test on failure
retries: 1,
// Applies to all projects
use: {
headless: !process.env.LOCAL_DEBUG,
video: 'on-first-retry' // No traces on first attempt - this seems to make tests flaky.
},
projects: [
{
name: 'Desktop Chrome',
use: {
viewport: DESKTOP_4_TO_3_VIEWPORT,
launchOptions: { ...chromeLaunchOptions },
contextOptions: {
userAgent: DESKTOP_USER_AGENT
}
}
},
{
name: 'Desktop Chrome 16:9',
use: {
viewport: DESKTOP_16_TO_9_VIEWPORT,
launchOptions: { ...chromeLaunchOptions },
contextOptions: {
userAgent: DESKTOP_USER_AGENT
}
},
testMatch: ['OverflowGallery.test.ts']
},
{
name: 'Mobile Android Portrait',
use: {
...devices['Nexus 5'],
launchOptions: { ...chromeLaunchOptions },
userAgent: ANDROID_USER_AGENT
}
},
{
name: 'Mobile Android Landscape',
use: {
userAgent: ANDROID_USER_AGENT,
// Support smallest supported mobile viewport (iPhone 5/SE) ({ width: 568, height: 320 })
viewport: { width: 568, height: 320 },
deviceScaleFactor: 2,
isMobile: true,
hasTouch: true,
defaultBrowserType: 'chromium',
launchOptions: { ...chromeLaunchOptions }
}
}
],
expect: {
toMatchSnapshot: {
maxDiffPixels: 1
}
},
reporter: process.env.CI ? CI_REPORTERS : LOCAL_REPORTERS,
testDir: testDir,
snapshotDir: snapshotDir
};
config.projects?.push({
name: 'Desktop Chrome 16:9',
use: {
viewport: DESKTOP_16_TO_9_VIEWPORT,
launchOptions: { ...chromeLaunchOptions },
contextOptions: {
userAgent: DESKTOP_USER_AGENT
}
},
testMatch: ['OverflowGallery.test.ts']
});
export default config;