From 7c1a425787b38828a2bc6b59e941c817ab6ff934 Mon Sep 17 00:00:00 2001 From: janni06 Date: Tue, 13 May 2025 17:40:24 +0200 Subject: [PATCH 01/10] base playwright setup --- .github/workflows/playwright.yml | 27 +++++++++++ .gitignore | 6 +++ package-lock.json | 64 ++++++++++++++++++++++++++ package.json | 5 +- playwright.config.ts | 79 ++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/playwright.yml create mode 100644 playwright.config.ts diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000000..3eb13143c3 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index febbb5c964..86463a2582 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ /node_modules /build + +# Playwright +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/package-lock.json b/package-lock.json index 2deb1eaac4..e065345c0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ }, "devDependencies": { "@opencast/eslint-config-ts-react": "^0.3.0", + "@playwright/test": "^1.52.0", "@redux-devtools/extension": "^3.3.0", "@types/lodash": "^4.17.16", "@types/node": "^22.13.17", @@ -1973,6 +1974,22 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@playwright/test": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", + "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -6390,6 +6407,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", + "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", + "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", diff --git a/package.json b/package.json index 38af2b80d9..aacf66d1ab 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,9 @@ "start": "vite", "build": "tsc && eslint . --max-warnings=0 && vite build", "serve": "vite preview", - "test": "vitest" + "test": "vitest", + "test:e2e": "playwright test --ui", + "test:e2e:headless": "playwright test" }, "browserslist": { "production": [ @@ -62,6 +64,7 @@ }, "devDependencies": { "@opencast/eslint-config-ts-react": "^0.3.0", + "@playwright/test": "^1.52.0", "@redux-devtools/extension": "^3.3.0", "@types/lodash": "^4.17.16", "@types/node": "^22.13.17", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000000..4694003697 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './webtests', + /* Run tests in files 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. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + { + name: 'Microsoft Edge', + use: { ...devices['Desktop Edge'], channel: 'msedge' }, + }, + { + name: 'Google Chrome', + use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm start', + url: 'http://127.0.0.1:3000', + reuseExistingServer: !process.env.CI, + }, +}); From e0b0b7a77555085f82c2b55dbe8db56e5f7d5bab Mon Sep 17 00:00:00 2001 From: janni06 Date: Tue, 13 May 2025 17:40:53 +0200 Subject: [PATCH 02/10] Adding an example test for language dropdown --- webtests/header.spec.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 webtests/header.spec.ts diff --git a/webtests/header.spec.ts b/webtests/header.spec.ts new file mode 100644 index 0000000000..48599af338 --- /dev/null +++ b/webtests/header.spec.ts @@ -0,0 +1,26 @@ +import { test, expect, type Page } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('/'); +}); +test.describe("Header", () => { + test('check existence of header items', async ({ page }) => { + await expect(page.getByRole('banner')).toBeVisible(); + await expect(page.locator('#lang-dd')).toBeVisible(); + await expect(page.locator('div:nth-child(2)').first()).toBeVisible(); + await expect(page.locator('#nav-dd-container > div:nth-child(3)')).toBeVisible(); + await expect(page.locator('#info-dd')).toBeVisible(); + await expect(page.locator('#help-dd')).toBeVisible(); + }); + + test('check language change dropdown', async ({ page }) => { + test.setTimeout(120_000); + await page.goto("/#/recordings/recordings"); + await page.locator('#lang-dd').click(); + await page.getByRole('button', { name: 'English (US)' }).click(); + await expect(page.locator('h1')).toContainText('Locations', {timeout: 120_000}); // the full page reload after changing the color takes much longer on the firefox browser + await page.locator('#lang-dd').click(); + await page.getByRole('button', { name: 'Deutsch' }).click(); + await expect(page.locator('h1')).toContainText('Standorte', {timeout: 120_000}); + }); +}); From 2b585ced54a3161b763fcf5abe6d46dc525532e2 Mon Sep 17 00:00:00 2001 From: janni06 Date: Tue, 13 May 2025 17:58:03 +0200 Subject: [PATCH 03/10] Add small documentation for playwright --- webtests/writing_tests.md | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 webtests/writing_tests.md diff --git a/webtests/writing_tests.md b/webtests/writing_tests.md new file mode 100644 index 0000000000..b621813df0 --- /dev/null +++ b/webtests/writing_tests.md @@ -0,0 +1,46 @@ +# Frontend End-to-End Testing with Playwright + +## Overview + +Playwright is a powerful testing framework that allows automated testing of web applications across multiple browsers (Chromium, Firefox, WebKit). It enables reliable end-to-end testing through its robust auto-waiting capabilities and resilient selector engine. + +## Setup Browsers + +There are multiple browsers setup in `../playwright.config.ts`: + +General browsers: + +- Desktop Chromium +- Desktop Firefox +- Desktop Safari + +Branded Browsers: + +- Microsoft Edge +- Google Chrome + +## Basic Structure + +1. Import Playwright test modules +2. Define test scenarios with `test()` function +3. Use page interactions (click, fill, etc.) +4. Assert expected outcomes + +## Developing tests + +For developing new tests you can have a look at the references below. To execute the tests locally, there are multiple options: + +**Running the tests headless:** +Execute `npm run test:e2e:headless` or `npx playwright test` in the terminal. + +**Running the tests in the UI:** +Execute `npm run test:e2e` or `npx playwright test --ui` in the terminal. + +In both cases you can add `--trace on` to get a trace view of the tests. + +## References + +- [Playwright Documentation](https://playwright.dev/docs/intro) +- [Getting Started Guide](https://playwright.dev/docs/getting-started-intro) +- [Test API Reference](https://playwright.dev/docs/api/class-test) +- [Assertions Documentation](https://playwright.dev/docs/assertions) From bcf05d2bd13bcb60f0aae35af9efa192e76ce3d9 Mon Sep 17 00:00:00 2001 From: janni06 Date: Tue, 13 May 2025 18:04:54 +0200 Subject: [PATCH 04/10] Edit description --- webtests/writing_tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webtests/writing_tests.md b/webtests/writing_tests.md index b621813df0..03dbaa8e9b 100644 --- a/webtests/writing_tests.md +++ b/webtests/writing_tests.md @@ -2,7 +2,7 @@ ## Overview -Playwright is a powerful testing framework that allows automated testing of web applications across multiple browsers (Chromium, Firefox, WebKit). It enables reliable end-to-end testing through its robust auto-waiting capabilities and resilient selector engine. +Playwright is a testing framework that allows automated testing of web applications across multiple browsers (Chromium, Firefox, WebKit). ## Setup Browsers From c1e183e87bd4404f1e7e749dbf7b4ec58e97c6b0 Mon Sep 17 00:00:00 2001 From: janni06 Date: Tue, 13 May 2025 18:08:22 +0200 Subject: [PATCH 05/10] documentation change references --- webtests/writing_tests.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/webtests/writing_tests.md b/webtests/writing_tests.md index 03dbaa8e9b..fdf00a3d01 100644 --- a/webtests/writing_tests.md +++ b/webtests/writing_tests.md @@ -41,6 +41,3 @@ In both cases you can add `--trace on` to get a trace view of the tests. ## References - [Playwright Documentation](https://playwright.dev/docs/intro) -- [Getting Started Guide](https://playwright.dev/docs/getting-started-intro) -- [Test API Reference](https://playwright.dev/docs/api/class-test) -- [Assertions Documentation](https://playwright.dev/docs/assertions) From 917064c8fd4f2235e089373096fe49f74315f138 Mon Sep 17 00:00:00 2001 From: janni06 Date: Wed, 21 May 2025 14:41:26 +0200 Subject: [PATCH 06/10] Increase server timeout to 120s --- playwright.config.ts | 115 ++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 4694003697..5be6e6fc3c 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -12,68 +12,69 @@ import { defineConfig, devices } from '@playwright/test'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './webtests', - /* Run tests in files 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. See https://playwright.dev/docs/test-reporters */ - reporter: 'html', - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: 'http://127.0.0.1:3000', + testDir: "./webtests", + /* Run tests in files 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. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: "http://127.0.0.1:3000", - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, - /* Test against branded browsers. */ - { - name: 'Microsoft Edge', - use: { ...devices['Desktop Edge'], channel: 'msedge' }, - }, - { - name: 'Google Chrome', - use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - }, - ], + /* Test against branded browsers. */ + { + name: "Microsoft Edge", + use: { ...devices["Desktop Edge"], channel: "msedge" }, + }, + { + name: "Google Chrome", + use: { ...devices["Desktop Chrome"], channel: "chrome" }, + }, + ], - /* Run your local dev server before starting the tests */ - webServer: { - command: 'npm start', - url: 'http://127.0.0.1:3000', - reuseExistingServer: !process.env.CI, - }, + /* Run your local dev server before starting the tests */ + webServer: { + command: "npm start", + url: "http://127.0.0.1:3000", + reuseExistingServer: !process.env.CI, + timeout: 120 * 1000, // increase the timeout to 120s (from default 60s) for the server to start + }, }); From 55cc78f6fc412ceddc32bb392a72f879290cc291 Mon Sep 17 00:00:00 2001 From: janni06 Date: Wed, 21 May 2025 14:58:55 +0200 Subject: [PATCH 07/10] ensure that the CI uses its own server --- playwright.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/playwright.config.ts b/playwright.config.ts index 5be6e6fc3c..cdf956a939 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -74,7 +74,6 @@ export default defineConfig({ webServer: { command: "npm start", url: "http://127.0.0.1:3000", - reuseExistingServer: !process.env.CI, timeout: 120 * 1000, // increase the timeout to 120s (from default 60s) for the server to start }, }); From a683b6b63c619c0f101285d7ee4493bbe2377188 Mon Sep 17 00:00:00 2001 From: janni06 Date: Wed, 21 May 2025 15:50:19 +0200 Subject: [PATCH 08/10] Run tests on production build --- .github/workflows/playwright.yml | 2 +- package.json | 1 + playwright.config.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 3eb13143c3..7a84e5b07e 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -18,7 +18,7 @@ jobs: - name: Install Playwright Browsers run: npx playwright install --with-deps - name: Run Playwright tests - run: npx playwright test + run: npm run test:e2e:headless - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} with: diff --git a/package.json b/package.json index 59d5d1ff79..99091e2da1 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "build": "tsc && eslint . --max-warnings=0 && vite build", "serve": "vite preview", "test": "vitest", + "test:serve": "vite build && vite preview", "test:e2e": "playwright test --ui", "test:e2e:headless": "playwright test" }, diff --git a/playwright.config.ts b/playwright.config.ts index cdf956a939..f4065f2b6d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -72,7 +72,7 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { - command: "npm start", + command: "npm run test:serve", url: "http://127.0.0.1:3000", timeout: 120 * 1000, // increase the timeout to 120s (from default 60s) for the server to start }, From c5685a80294d2d64f24625302455ed9a7a6d365b Mon Sep 17 00:00:00 2001 From: janni06 Date: Wed, 21 May 2025 16:00:33 +0200 Subject: [PATCH 09/10] Use dynamic URL --- playwright.config.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index f4065f2b6d..4d6a259edf 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from "@playwright/test"; /** * Read environment variables from file. @@ -26,7 +26,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - baseURL: "http://127.0.0.1:3000", + baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || "http://localhost:3000", /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: "on-first-retry", @@ -72,8 +72,7 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { - command: "npm run test:serve", - url: "http://127.0.0.1:3000", + command: "npm start", timeout: 120 * 1000, // increase the timeout to 120s (from default 60s) for the server to start }, }); From 1a405ebfa6998ffeeff8cb5454f73483d5b64241 Mon Sep 17 00:00:00 2001 From: janni06 Date: Wed, 21 May 2025 16:30:41 +0200 Subject: [PATCH 10/10] Update writing_tests.md to enhance installation and local test execution instructions --- webtests/writing_tests.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/webtests/writing_tests.md b/webtests/writing_tests.md index fdf00a3d01..b6b25d0f5c 100644 --- a/webtests/writing_tests.md +++ b/webtests/writing_tests.md @@ -28,7 +28,13 @@ Branded Browsers: ## Developing tests -For developing new tests you can have a look at the references below. To execute the tests locally, there are multiple options: +### Installation + +Besides the dependencies in the ```package.json``` file which need to be install to run the webserver at all, playwright has browser dependencies as well. To install the extra broser dependencies, run: ```npx playwright install --with-deps``` + +### Run tests locally + +To execute the tests locally, there are multiple options: **Running the tests headless:** Execute `npm run test:e2e:headless` or `npx playwright test` in the terminal. @@ -38,6 +44,10 @@ Execute `npm run test:e2e` or `npx playwright test --ui` in the terminal. In both cases you can add `--trace on` to get a trace view of the tests. +### Developing + +Please have a look at the official playwright documentation on how to develop new tests. + ## References - [Playwright Documentation](https://playwright.dev/docs/intro)