Skip to content

Commit 466612a

Browse files
committed
minor #3013 Use Playwright for Browser testing (Kocal)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- Use Playwright for Browser testing | Q | A | ------------- | --- | Bug fix? | no | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Docs? | no <!-- required for new features --> | Issues | Fix #3010 <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead --> | License | MIT <!-- Replace this notice by a description of your feature/bugfix. This will help reviewers and should be a good start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - For new features, provide some code snippets to help understand usage. - Features and deprecations must be submitted against branch main. - Update/add documentation as required (we can help!) - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry - Never break backward compatibility (see https://symfony.com/bc). --> Following #3010 (comment) 😅 Commits ------- c5b37fc Use Playwright to run E2E tests a13d427 Rework test_package.sh to allow passing tail args to vitest 6c474d4 Rename back vitest.config.unit.mjs to vitest.config.mjs
2 parents 3a53dd6 + c5b37fc commit 466612a

Some content is hidden

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

45 files changed

+298
-140
lines changed

.github/workflows/browser-tests.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,18 @@ jobs:
3636
src/**/package.json
3737
- run: pnpm install --frozen-lockfile
3838

39-
- name: Install browsers
39+
- name: Install custom browsers
4040
run: node ./bin/get_browsers.mjs
4141

42+
- name: Install browsers with Playwright
43+
run: pnpm exec playwright install firefox ffmpeg
44+
4245
# TODO: Install the E2E app + run webserver
4346
- run: pnpm run test:browser
47+
48+
- uses: actions/upload-artifact@v4
49+
if: ${{ !cancelled() }}
50+
with:
51+
name: playwright-report
52+
path: .playwright-report/
53+
retention-days: 7

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ node_modules
88
/vendor
99

1010
/browsers
11+
.last-run.json
12+
.playwright-report/

bin/get_browsers.mjs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
Browser,
44
BrowserTag,
55
detectBrowserPlatform,
6-
install as installBrowser,
6+
install,
77
resolveBuildId,
88
} from '@puppeteer/browsers';
99

@@ -18,7 +18,7 @@ const installBrowserCommonOpts = {
1818
// see https://browsersl.ist/#q=defaults+and+fully+supports+es6-module
1919

2020
export const browsers = {
21-
'chrome@lowest': await installBrowser({
21+
'chrome@lowest': await install({
2222
...installBrowserCommonOpts,
2323
browser: Browser.CHROME,
2424
// The lowest version where:
@@ -28,21 +28,29 @@ export const browsers = {
2828
// @see https://raw.githubusercontent.com/GoogleChromeLabs/chrome-for-testing/refs/heads/main/data/known-good-versions-with-downloads.json
2929
buildId: '130.0.6669.0',
3030
}),
31-
'chrome@latest': await installBrowser({
32-
...installBrowserCommonOpts,
33-
browser: Browser.CHROME,
34-
buildId: await resolveBuildId(Browser.CHROME, platform, BrowserTag.STABLE),
35-
}),
36-
'firefox@lowest': await installBrowser({
37-
...installBrowserCommonOpts,
38-
browser: Browser.FIREFOX,
39-
buildId: 'stable_128.0',
40-
}),
41-
'firefox@latest': await installBrowser({
42-
...installBrowserCommonOpts,
43-
browser: Browser.FIREFOX,
44-
buildId: await resolveBuildId(Browser.FIREFOX, platform, BrowserTag.STABLE),
31+
32+
'chrome@latest': await install({
33+
...installBrowserCommonOpts,
34+
browser: Browser.CHROME,
35+
buildId: await resolveBuildId(Browser.CHROME, platform, BrowserTag.STABLE),
4536
}),
37+
38+
// TODO: I don't find a way to install a specific Firefox version and make it usable
39+
// with Playwright. It's surely related to patch things (https://playwright.dev/docs/browsers#firefox),
40+
// but even a non-branded version like Nightly doesn't work.
41+
42+
// 'firefox@lowest': await install({
43+
// ...installBrowserCommonOpts,
44+
// browser: Browser.FIREFOX,
45+
// buildId: '128.0a1',
46+
// baseUrl: 'https://ftp.mozilla.org/pub/firefox/nightly/2024/06/2024-06-01-09-33-40-mozilla-central'
47+
// }),
48+
//
49+
// 'firefox@latest': await install({
50+
// ...installBrowserCommonOpts,
51+
// browser: Browser.FIREFOX,
52+
// buildId: await resolveBuildId(Browser.FIREFOX, platform, BrowserTag.NIGHTLY),
53+
// }),
4654
};
4755

4856
if (import.meta.main) {

bin/test_package.sh

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,45 @@ PROJECT_DIR=$(dirname "$SCRIPT_DIR")
99
# Flag to track if any test fails
1010
all_tests_passed=true
1111

12-
# Check if we have enough arguments
12+
# Check if we have at least two arguments
1313
if [ $# -ne 2 ]; then
1414
echo "No arguments supplied, please provide the package's path and the test type (e.g. --unit or --browser)"
15+
echo "Usage: $0 <package_path> <test_type> [args...]"
1516
fi
1617

18+
location="$(realpath "$PWD/$1")"
19+
if [ ! -d "$location" ]; then
20+
echo "The provided package path does not exist or is not a directory: $location"
21+
exit 1
22+
fi
23+
24+
shift
25+
case "$1" in
26+
--unit) testType="unit" ;;
27+
--browser) testType="browser" ;;
28+
*) echo "Unknown test type: $2. Please use --unit or --browser."; exit 1 ;;
29+
esac
30+
31+
shift
32+
args=("$@")
33+
1734
# Check if jq is installed
1835
if ! command -v jq &> /dev/null; then
1936
echo "jq is required but not installed. Aborting."
2037
exit 1
2138
fi
2239

2340
runTestSuite() {
24-
local testProject="$1"
25-
if [ "$testProject" != "unit" ] && [ "$testProject" != "browser" ]; then
26-
echo "Unknown test project: $testProject. Please use 'unit' or 'browser'."
27-
exit 1
41+
if [ "$testType" == "unit" ]; then
42+
echo -e "🧪 Running unit tests for $workspace...\n"
43+
pnpm exec vitest --run "${args[@]}" || { all_tests_passed=false; }
44+
elif [ "$testType" == "browser" ]; then
45+
echo -e "🧪 Running browser tests for $workspace...\n"
46+
# TODO: to implement
2847
fi
29-
30-
echo -e "🧪 Running $testProject tests for $workspace...\n"
31-
pnpm exec vitest --run --config "vitest.config.$testProject.mjs" || { all_tests_passed=false; }
3248
}
3349

3450
processWorkspace() {
35-
local location="$1"
36-
local testProject="$2"
37-
3851
if [ ! -d "$location" ]; then
3952
echo "⚠ No directory found at $location"
4053
return
@@ -89,7 +102,7 @@ processWorkspace() {
89102
echo -e " - Install $library@$trimmed_version for $workspace\n"
90103
pnpm add "$library@$trimmed_version" --save-peer --filter "$workspace"
91104

92-
runTestSuite "$testProject"
105+
runTestSuite
93106
fi
94107
done
95108
done
@@ -98,17 +111,11 @@ processWorkspace() {
98111
git checkout -- "$package_json_path" "$PROJECT_DIR/pnpm-lock.yaml"
99112
else
100113
echo -e " -> No peerDependencies found with multiple versions defined\n"
101-
runTestSuite "$testProject"
114+
runTestSuite
102115
fi
103116
}
104117

105-
case "$2" in
106-
--unit) testProject="unit" ;;
107-
--browser) testProject="browser" ;;
108-
*) echo "Unknown test type: $2. Please use --unit or --browser."; exit 1 ;;
109-
esac
110-
111-
processWorkspace "$(realpath "$PWD/$1")" "$testProject"
118+
processWorkspace
112119

113120
# Check the flag at the end and exit with code 1 if any test failed
114121
if [ "$all_tests_passed" = false ]; then

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
"build": "pnpm run --filter @symfony/ux-map build && pnpm run -r --aggregate-output build",
1111
"test": "pnpm run -r --workspace-concurrency=1 test",
1212
"test:unit": "pnpm run -r --aggregate-output test:unit",
13-
"test:browser": "pnpm run -r --workspace-concurrency=1 test:browser",
13+
"test:browser": "pnpm exec playwright test",
1414
"check": "biome check",
1515
"ci": "biome ci"
1616
},
1717
"devDependencies": {
1818
"@biomejs/biome": "^2.0.4",
19+
"@playwright/test": "^1.54.2",
1920
"@puppeteer/browsers": "^2.10.6",
2021
"@testing-library/dom": "^10.4.0",
2122
"@testing-library/jest-dom": "^6.6.3",

playwright.config.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
import { browsers } from './bin/get_browsers.mjs';
4+
5+
export default defineConfig({
6+
testMatch:[
7+
'src/**/assets/test/browser/**/*.{test,spec}.ts',
8+
'src/**/assets/test/**/*.browser.{test,spec}.ts',
9+
],
10+
testIgnore: [
11+
// TODO: Temporary, as the Map tests require some TypeScript code to be compiled
12+
// and so fails (which is expected). To remove once the tests are real E2E.
13+
/Map/
14+
],
15+
16+
reporter: [
17+
['list'],
18+
['html', { open: process.env.CI ? 'never' : 'on-failure', outputFolder: '.playwright-report' }],
19+
],
20+
21+
use: {
22+
// Base URL to use in actions like `await page.goto('/')`.
23+
baseURL: 'http://localhost:9876',
24+
25+
screenshot: 'only-on-failure',
26+
video: 'retain-on-failure',
27+
trace: 'retain-on-failure'
28+
},
29+
30+
//webServer: {
31+
// command: 'cd test_apps/e2e-app && symfony serve',
32+
// url: 'http://localhost:9876',
33+
// reuseExistingServer: !process.env.CI,
34+
// stderr: 'pipe',
35+
//},
36+
37+
projects: [
38+
{
39+
name: 'chrome-lowest',
40+
use: {
41+
...devices['Desktop Chrome'],
42+
channel: 'chrome',
43+
launchOptions: {
44+
executablePath: browsers['chrome@lowest'].executablePath,
45+
}
46+
},
47+
},
48+
{
49+
name: 'chrome-latest',
50+
use: {
51+
...devices['Desktop Chrome'],
52+
channel: 'chrome',
53+
launchOptions: {
54+
executablePath: browsers['chrome@latest'].executablePath,
55+
}
56+
},
57+
},
58+
59+
// TODO: Until we found a way to run a specific version of Firefox
60+
//{
61+
// name: 'firefox-lowest',
62+
// use: {
63+
// ...devices['Desktop Firefox'],
64+
// launchOptions: {
65+
// executablePath: browsers['firefox@lowest'].executablePath,
66+
// }
67+
// },
68+
//},
69+
{
70+
name: 'firefox-latest',
71+
use: {
72+
...devices['Desktop Firefox'],
73+
},
74+
}
75+
],
76+
});

pnpm-lock.yaml

Lines changed: 13 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import { describe, expect, it } from 'vitest';
1+
import { expect, test } from '@playwright/test';
22

3-
describe('Placeholder', () => {
4-
it('pass', () => {
5-
expect(true).toBe(true);
6-
});
3+
test('get started link', async ({ page }) => {
4+
await page.goto('https://playwright.dev/');
5+
6+
// Click the get started link.
7+
await page.getByRole('link', { name: 'Get started' }).click();
8+
9+
// Expects page to have a heading with the name of Installation.
10+
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
711
});
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { mergeConfig } from 'vitest/config';
2-
import configShared from '../../../vitest.config.unit.mjs';
2+
import configShared from '../../../vitest.config.mjs';
33

44
export default mergeConfig(configShared, {});
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import { describe, expect, it } from 'vitest';
1+
import { expect, test } from '@playwright/test';
22

3-
describe('Placeholder', () => {
4-
it('pass', () => {
5-
expect(true).toBe(true);
6-
});
3+
test('get started link', async ({ page }) => {
4+
await page.goto('https://playwright.dev/');
5+
6+
// Click the get started link.
7+
await page.getByRole('link', { name: 'Get started' }).click();
8+
9+
// Expects page to have a heading with the name of Installation.
10+
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
711
});

0 commit comments

Comments
 (0)