Skip to content

Commit 3290dc1

Browse files
committed
feat(playwright): sync test apps
1 parent 80f1ce7 commit 3290dc1

File tree

104 files changed

+2679
-539
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+2679
-539
lines changed

packages/e2e-playwright/build.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export default defineBuildConfig({
2525
// as peerDependencies in package.json.
2626
externals: ['@playwright/experimental-ct-vue', '@playwright/test'],
2727

28+
rollup: {
29+
// Explicitly enable generating the CJS bundle.
30+
emitCJS: true,
31+
},
32+
2833
// There is some strange warning about missing package.json. It doesn't affect the build however.
2934
// It is most likely a false positive. So for now, let's not fail the build on this warning.
3035
// See: https://github.com/unjs/unbuild/issues/268

packages/e2e-playwright/package.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"vite-plugin-istanbul": "^7.0.0"
6262
},
6363
"devDependenciesComments": {
64-
"rimraf": "Requires node 20+, so let's not update it to continue supporting lower versions"
64+
"rimraf": "Requires node 20 || >=22, so let's not update it to continue supporting lower versions"
6565
},
6666
"devDependencies": {
6767
"@eslint/js": "^9.18.0",
@@ -79,7 +79,12 @@
7979
"unbuild": "^3.5.0"
8080
},
8181
"peerDependencies": {
82-
"@playwright/test": "^1.49.1",
83-
"@playwright/experimental-ct-vue": "^1.50.0"
82+
"@playwright/test": "^1.40.0",
83+
"@playwright/experimental-ct-vue": "^1.40.0"
84+
},
85+
"peerDependenciesMeta": {
86+
"eslint-plugin-playwright": {
87+
"optional": true
88+
}
8489
}
8590
}

packages/e2e-playwright/src/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ export default async function (api) {
2525

2626
api.extendViteConf((viteConf) => {
2727
viteConf.plugins.push(
28-
istanbul({
29-
forceBuildInstrument: api.ctx.prod,
30-
requireEnv: true,
31-
}),
28+
istanbul({ forceBuildInstrument: api.ctx.prod, requireEnv: true }),
3229
);
3330
});
3431
}

packages/e2e-playwright/src/install.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ function getCompatibleDevDependencies(packageNames) {
6969
return devDependencies;
7070
}
7171

72+
// eslint-plugin-playwright works well with both eslint v8 and eslint v9
7273
let extendPackageJson = {
7374
devDependencies: getCompatibleDevDependencies([
74-
'eslint-plugin-playwright',
7575
'@playwright/test',
76-
'@playwright/experimental-ct-vue',
76+
'eslint-plugin-playwright',
7777
]),
7878
};
7979

@@ -144,8 +144,7 @@ export default async function (api) {
144144

145145
let testEnvCommand = 'cross-env NODE_ENV=test';
146146
if (shouldEnableCodeCoverage) {
147-
// With this we can set requireEnv in istanbul to true, and it if the user removes this flag
148-
// then istanbul will not instrument the code
147+
// We have set requireEnv in istanbul to true, so this is needed for instrumentation to work
149148
testEnvCommand += ' VITE_COVERAGE=true';
150149
}
151150

@@ -163,6 +162,10 @@ export default async function (api) {
163162
if (shouldEnableCodeCoverage) {
164163
api.render('./templates/code-coverage');
165164

165+
// Let's add the playwright-ct-vue package to the devDependencies
166+
extendPackageJson.devDependencies['@playwright/experimental-ct-vue'] =
167+
aeDevDependencies['@playwright/experimental-ct-vue'];
168+
166169
scripts.scripts['test'] += ` && ${packageManager} coverage-report`;
167170
scripts.scripts['coverage-report'] =
168171
'nyc report --reporter=html --reporter=text';
@@ -196,6 +199,18 @@ export default async function (api) {
196199
if (api.prompts.installBrowsers) {
197200
installPlaywrightBrowsers();
198201
}
202+
203+
if (api.prompts.enableCodeCoverage && api.hasWebpack) {
204+
api.onExitLog(
205+
"Playwright doesn't support code coverage for Webpack yet. Please use Vite CLI instead.",
206+
);
207+
}
208+
209+
if (await api.hasLint()) {
210+
api.onExitLog(
211+
'Check out https://github.com/quasarframework/quasar-testing/tree/dev/packages/e2e-playwright to see how to add proper Playwright linting configuration to your project.',
212+
);
213+
}
199214
} catch (error) {
200215
console.error('An error occurred while installing the extension:', error);
201216

packages/e2e-playwright/src/utils/coverage.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,35 @@ function generateUUID() {
1010
return crypto.randomBytes(16).toString('hex');
1111
}
1212

13-
export async function addCoverageToContext(context: BrowserContext, use: (r: BrowserContext) => Promise<void>) {
13+
/**
14+
* Sets up and collects code coverage for the given Playwright browser context.
15+
* Coverage collection is conditionally enabled based on the `VITE_COVERAGE` environment variable.
16+
*
17+
* The function performs the following steps when coverage is enabled:
18+
* 1. Adds an initialization script to the browser context. This script runs before
19+
* every page load within the context and attaches a 'beforeunload' event listener
20+
* to the browser's `window`. This listener attempts to capture the `window.__coverage__`
21+
* object (standard for Istanbul/v8 coverage) and send it back to Node.js
22+
* via an exposed function before the page unloads.
23+
* 2. Creates the output directory for coverage reports on the Node.js file system.
24+
* 3. Exposes a Node.js function named `collectIstanbulCoverage` to the browser's `window` object.
25+
* When this browser-side function is called (by the init script or later `page.evaluate` calls),
26+
* the corresponding Node.js function executes, receiving the coverage JSON string
27+
* and writing it to a unique JSON file in the designated output directory.
28+
* 4. Executes the main test logic provided by the `use` function.
29+
* 5. After the main test logic completes, it iterates through all pages currently open
30+
* in the context and explicitly evaluates a script on each. This script manually
31+
* calls the exposed `window.collectIstanbulCoverage` function to ensure any remaining
32+
* coverage data from pages that didn't trigger 'beforeunload' (e.g., tests that
33+
* finished without navigation or closing the page) is collected.
34+
*
35+
* @param context The Playwright browser context for which to collect coverage.
36+
* @param use The Playwright test fixture's `use` function,
37+
* which is called to execute the main test body with the configured context.
38+
*/
39+
40+
// @link https://github.com/anishkny/playwright-test-coverage
41+
export async function addCoverageToContext(context: BrowserContext, use: (_: BrowserContext) => Promise<void>) {
1442
if (process.env.VITE_COVERAGE !== 'true') {
1543
// `requireEnv` of istanbul should also prevent instrumentation if this flag is not set. So even if
1644
// we remove this check, the coverage will not be collected if the flag is not set.
@@ -47,7 +75,7 @@ export async function addCoverageToContext(context: BrowserContext, use: (r: Bro
4775

4876
await use(context);
4977

50-
// Collect coverage from all pages after tests
78+
// Goes through all browser pages in the page context and collects the coverage using the exposed function.
5179
for (const page of context.pages()) {
5280
await page.evaluate(
5381
() => {

test-project-playwright/playwright-ct.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { defineConfig, devices, type PlaywrightTestConfig } from '@playwright/ex
22
import vue from '@vitejs/plugin-vue';
33
import { quasar, transformAssetUrls } from '@quasar/vite-plugin';
44
import istanbul from 'vite-plugin-istanbul';
5+
import { type PluginOption } from 'vite';
56
// import { fileURLToPath } from 'node:url';
67
// import AutoImport from 'unplugin-auto-import/vite';
78
// import Components from 'unplugin-vue-components/vite';
@@ -75,7 +76,7 @@ export default defineConfig({
7576
checkProd: false,
7677
cypress: false,
7778
}),
78-
],
79+
] as PluginOption[],
7980
},
8081
},
8182

test-vite-app-v1-vite4/.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,15 @@ yarn-error.log*
3434

3535
.nyc_output
3636
coverage/
37+
38+
39+
# Playwright
40+
/test-results/
41+
/playwright-report/
42+
/blob-report
43+
/playwright/.cache/
44+
45+
46+
# Coverage
47+
.nyc_output
48+
/coverage

test-vite-app-v1-vite4/.nycrc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
{
2-
"extends": "@quasar/quasar-app-extension-testing-e2e-cypress/nyc-config-preset"
3-
}
1+
{
2+
"extends": "@quasar/quasar-app-extension-testing-e2e-playwright/nyc-preset"
3+
}

test-vite-app-v1-vite4/package.json

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@
1111
"invoke:cypress": "quasar ext invoke @quasar/testing-e2e-cypress && yarn format",
1212
"invoke:all": "yarn invoke:cypress",
1313
"sync:invoke:cypress": "yarn sync:cypress && yarn invoke:cypress",
14+
"sync:playwright": "yarn --cwd ../packages/e2e-playwright build:local && yarn add -D ../packages/e2e-playwright",
15+
"invoke:playwright": "quasar ext invoke @quasar/testing-e2e-playwright && yarn format",
16+
"sync:invoke:playwright": "yarn sync:playwright && yarn invoke:playwright",
1417
"sync:invoke:all": "yarn sync:invoke:cypress",
1518
"test:cypress": "yarn test:e2e:ci && yarn test:component:ci",
1619
"test:all": "yarn test:cypress",
1720
"sync:invoke:test:cypress": "yarn sync:invoke:cypress && yarn test:cypress",
1821
"sync:invoke:test:all": "yarn sync:invoke:test:cypress",
1922
"lint": "eslint --ext .js,.ts,.vue ./",
2023
"format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore",
21-
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
22-
"test:e2e": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://127.0.0.1:8080 \"cypress open --e2e\"",
23-
"test:e2e:ci": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://127.0.0.1:8080 \"cypress run --e2e\"",
24-
"test:component": "cross-env NODE_ENV=test cypress open --component",
25-
"test:component:ci": "cross-env NODE_ENV=test cypress run --component"
24+
"test": "yarn test:clear && yarn test:component:ci && yarn test:e2e:ci && yarn coverage-report",
25+
"test:e2e": "cross-env NODE_ENV=test VITE_COVERAGE=true playwright test --ui",
26+
"test:e2e:ci": "cross-env NODE_ENV=test VITE_COVERAGE=true playwright test",
27+
"test:component": "cross-env NODE_ENV=test VITE_COVERAGE=true playwright test -c playwright-ct.config.ts --ui",
28+
"test:component:ci": "cross-env NODE_ENV=test VITE_COVERAGE=true playwright test -c playwright-ct.config.ts",
29+
"test:clear": "rimraf .nyc_output coverage",
30+
"test:report": "playwright show-report",
31+
"coverage-report": "nyc report --reporter=html --reporter=text"
2632
},
2733
"dependencies": {
2834
"@quasar/extras": "^1.16.6",
@@ -40,6 +46,7 @@
4046
"@intlify/vite-plugin-vue-i18n": "^3.3.1",
4147
"@quasar/app-vite": "^1.7.1",
4248
"@quasar/quasar-app-extension-testing-e2e-cypress": "../packages/e2e-cypress",
49+
"@quasar/quasar-app-extension-testing-e2e-playwright": "../packages/e2e-playwright",
4350
"@types/node": "^18.17.15",
4451
"@typescript-eslint/eslint-plugin": "^5.54.0",
4552
"@typescript-eslint/parser": "^5.54.0",
@@ -51,7 +58,10 @@
5158
"eslint-plugin-cypress": "^3.6.0",
5259
"eslint-plugin-vue": "^9.17.0",
5360
"prettier": "^3.0.3",
54-
"typescript": "^4.9.5"
61+
"typescript": "^4.9.5",
62+
"@playwright/test": "^1.49.1",
63+
"eslint-plugin-playwright": "^2.1.0",
64+
"@playwright/experimental-ct-vue": "^1.50.0"
5565
},
5666
"resolutionsComments": {
5767
"vite": "See workaround https://github.com/quasarframework/quasar/issues/14077#issuecomment-1353213893, since Quasar Vite v1 only supports up to Vite 3",
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import {
2+
defineConfig,
3+
devices,
4+
type PlaywrightTestConfig,
5+
} from '@playwright/experimental-ct-vue';
6+
import vue from '@vitejs/plugin-vue';
7+
import { quasar, transformAssetUrls } from '@quasar/vite-plugin';
8+
import istanbul from 'vite-plugin-istanbul';
9+
import { type PluginOption } from 'vite';
10+
// import { fileURLToPath } from 'node:url';
11+
// import AutoImport from 'unplugin-auto-import/vite';
12+
// import Components from 'unplugin-vue-components/vite';
13+
14+
/**
15+
* See https://playwright.dev/docs/test-configuration.
16+
*/
17+
export default defineConfig({
18+
testDir: './src/components',
19+
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
20+
snapshotDir: './__snapshots__',
21+
/* Maximum time one test can run for. */
22+
timeout: 10 * 1000,
23+
/* Run tests in files in parallel */
24+
fullyParallel: true,
25+
/* Fail the build on CI if you accidentally left test.only in the source code. */
26+
forbidOnly: !!process.env.CI,
27+
/* Retry on CI only */
28+
retries: process.env.CI ? 2 : 0,
29+
/* Opt out of parallel tests on CI. */
30+
workers: process.env.CI ? 1 : undefined,
31+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
32+
reporter: 'html',
33+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
34+
use: {
35+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
36+
trace: 'on-first-retry',
37+
38+
/* Port to use for Playwright component endpoint. */
39+
ctPort: 3100,
40+
41+
ctViteConfig: {
42+
build: {
43+
sourcemap: true,
44+
},
45+
plugins: [
46+
vue({ template: { transformAssetUrls } }),
47+
// AutoImport({
48+
// imports: [
49+
// 'vue',
50+
// 'vue-router',
51+
// '@vueuse/head',
52+
// 'pinia',
53+
// 'quasar',
54+
// {
55+
// '@/store': ['useStore'],
56+
// },
57+
// ],
58+
// dts: 'src/auto-imports.d.ts',
59+
// eslintrc: {
60+
// enabled: true,
61+
// },
62+
// }),
63+
// Components({
64+
// dirs: ['src/components'],
65+
// extensions: ['vue'],
66+
// }),
67+
quasar({
68+
// sassVariables: fileURLToPath(
69+
// new URL('./src/quasar-variables.sass', import.meta.url),
70+
// ),
71+
}),
72+
73+
// Instrument the code for nyc/istanbul code coverage
74+
istanbul({
75+
include: ['src/**/*'],
76+
exclude: ['node_modules', 'test/', 'dist/', 'coverage/', '__tests__'],
77+
extension: ['.js', '.ts', '.vue'],
78+
requireEnv: true,
79+
forceBuildInstrument: true,
80+
checkProd: false,
81+
cypress: false,
82+
}),
83+
] as PluginOption[],
84+
},
85+
},
86+
87+
/* Configure projects for major browsers */
88+
projects: [
89+
{
90+
name: 'chromium',
91+
use: { ...devices['Desktop Chrome'] },
92+
},
93+
{
94+
name: 'firefox',
95+
use: { ...devices['Desktop Firefox'] },
96+
},
97+
{
98+
name: 'webkit',
99+
use: { ...devices['Desktop Safari'] },
100+
},
101+
],
102+
} as PlaywrightTestConfig);

0 commit comments

Comments
 (0)