main
ts 139 lines 4.76 KB
Raw
1 import { defineConfig, devices } from '@playwright/test';
2 import { execSync } from 'node:child_process';
3 import { readFileSync } from 'node:fs';
4 import { resolve } from 'node:path';
5 import yaml from 'yaml';
6
7 const snapshotBranch = getSnapshotBranch()
8 // use the same test port source as tests/test.ts to avoid config drift
9 const testPort = Number(yaml.parse(readFileSync(resolve(process.cwd(), 'tests/config.yaml'), 'utf8')).port)
10
11 /**
12 * Read environment variables from file.
13 * https://github.com/motdotla/dotenv
14 */
15 // import dotenv from 'dotenv';
16 // import path from 'path';
17 // dotenv.config({ path: path.resolve(__dirname, '.env') });
18
19 /**
20 * See https://playwright.dev/docs/test-configuration.
21 */
22 export default defineConfig({
23 testDir: './e2e',
24 snapshotPathTemplate: `{testDir}/{testFilePath}-snapshots-${snapshotBranch}/{arg}-{projectName}-{platform}{ext}`,
25 timeout: 30_000,
26 fullyParallel: true, // Run tests in files in parallel
27 forbidOnly: !!process.env.CI, // Fail the build on CI if you accidentally left test.only in the source code.
28 retries: process.env.CI ? 2 : 0, // Retry on CI only
29 updateSnapshots: 'missing', // keep new baseline screenshots from failing the run; existing screenshots still compare normally
30 //workers: process.env.CI ? 1 : undefined, // Opt out of parallel tests on CI.
31 reporter: 'html', // Reporter to use. See https://playwright.dev/docs/test-reporters
32 use: { // Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions.
33 /* Base URL to use in actions like `await page.goto('/')`. */
34 // baseURL: 'http://127.0.0.1:3000',
35
36 /* Keep the failed attempt and the retry trace together so flake diffs are easier to compare. */
37 trace: 'retain-on-failure-and-retries',
38 screenshot: 'only-on-failure',
39 timezoneId: 'Europe/Rome',
40 },
41
42 /* Configure projects for major browsers */
43 projects: [
44 {
45 name: 'chromium',
46 use: {
47 ...devices['Desktop Chrome'],
48 viewport: { width: 1920, height: 1080 },
49 },
50 },
51 {
52 name: 'Android',
53 use: { ...devices['Pixel 7'] },
54 },
55 {
56 name: 'iPhone 6',
57 use: { ...devices['iPhone 6'] },
58 },
59 {
60 name: 'firefox',
61 use: {
62 ...devices['Desktop Firefox'],
63 launchOptions: {
64 // Firefox can purge localhost-like state during bounce-tracker heuristics in tests.
65 firefoxUserPrefs: { 'privacy.bounceTrackingProtection.mode': 0 },
66 },
67 },
68 },
69 /*
70 {
71 name: 'firefox',
72 use: { ...devices['Desktop Firefox'] },
73 },
74
75 {
76 name: 'webkit',
77 use: { ...devices['Desktop Safari'] },
78 },*/
79
80 /* Test against mobile viewports. */
81 // {
82 // name: 'Mobile Chrome',
83 // use: { ...devices['Pixel 5'] },
84 // },
85 // {
86 // name: 'Mobile Safari',
87 // use: { ...devices['iPhone 12'] },
88 // },
89
90 /* Test against branded browsers. */
91 // {
92 // name: 'Microsoft Edge',
93 // use: { ...devices['Desktop Edge'], channel: 'msedge' },
94 // },
95 // {
96 // name: 'Google Chrome',
97 // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
98 // },
99 ],
100
101 expect: {
102 toHaveScreenshot: {
103 stylePath: 'e2e/screenshot.css',
104 threshold: 0.5,
105 },
106 },
107 /* Run your local dev server before starting the tests */
108 webServer: [{
109 command: `mkdir -p tests/work/plugins/test`
110 + ` && printf '%s\\n' "exports.apiRequired = 1" "exports.config = {" " icons: { type: 'array', fields: { iconFile: { type: 'real_path' } } }," "}" > tests/work/plugins/test/plugin.js`
111 + ` && npm run server-for-test${process.env.TEST_WITH_UI ? '-dev' : ''}`, // use server-for-test-dev only for "test-with-ui"
112 url: `http://127.0.0.1:${testPort}`,
113 reuseExistingServer: !process.env.CI,
114 }, { // launch a second server for tests with an empty/default config
115 command: 'rm -rf tests/work2 && node dist/src --cwd tests/work2 --debug --port 8082 --open_browser_at_start false', // the port here is just to avoid getting the "port busy" console warning
116 reuseExistingServer: !process.env.CI,
117 }]
118 });
119
120 function getSnapshotBranch() {
121 // CI often runs in detached HEAD, so allow callers to force the logical branch name.
122 const branchName = process.env.PLAYWRIGHT_SNAPSHOT_BRANCH || getGitBranchName() || 'main'
123 return branchName.replace(/[^a-zA-Z0-9._-]/g, '_')
124 }
125
126 function getGitBranchName() {
127 return (gitOutput('git branch --show-current')
128 || gitOutput('git for-each-ref --format="%(refname:short)" --contains HEAD refs/heads refs/remotes'))
129 ?.split('\n')
130 .map(x => x.trim())
131 .filter(x => x && !x.endsWith('/HEAD'))
132 .map(x => x.replace(/^[^/]+\//, ''))
133 .at(0)
134 }
135
136 function gitOutput(command: string) {
137 try { return execSync(command, { encoding: 'utf8' }).trim() }
138 catch {}
139 }