From 23d1ad5eb0f467a1caa98a32236dbc29341e50be Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 1 Dec 2023 11:32:24 +0100 Subject: [PATCH 01/29] test: install and initialize Playwright --- web/frontend/.gitignore | 5 +- web/frontend/package-lock.json | 71 ++++++++++++++++++++++++++++ web/frontend/package.json | 5 +- web/frontend/playwright.config.ts | 77 +++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 web/frontend/playwright.config.ts diff --git a/web/frontend/.gitignore b/web/frontend/.gitignore index f2e59e5f7..0f2aa48fc 100644 --- a/web/frontend/.gitignore +++ b/web/frontend/.gitignore @@ -25,4 +25,7 @@ yarn-error.log* .idea .vscode - +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/web/frontend/package-lock.json b/web/frontend/package-lock.json index 30dcfa2ce..3d558a594 100644 --- a/web/frontend/package-lock.json +++ b/web/frontend/package-lock.json @@ -31,6 +31,7 @@ "yup": "^0.32.11" }, "devDependencies": { + "@playwright/test": "^1.40.1", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.5", "@types/file-saver": "^2.0.5", @@ -2865,6 +2866,21 @@ "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", "dev": true }, + "node_modules/@playwright/test": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", + "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==", + "dev": true, + "dependencies": { + "playwright": "1.40.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz", @@ -12221,6 +12237,36 @@ "node": ">=6" } }, + "node_modules/playwright": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", + "dev": true, + "dependencies": { + "playwright-core": "1.40.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -18706,6 +18752,15 @@ "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", "dev": true }, + "@playwright/test": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", + "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==", + "dev": true, + "requires": { + "playwright": "1.40.1" + } + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz", @@ -25657,6 +25712,22 @@ } } }, + "playwright": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.40.1" + } + }, + "playwright-core": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", + "dev": true + }, "postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", diff --git a/web/frontend/package.json b/web/frontend/package.json index b3a63d718..ccb6f6526 100644 --- a/web/frontend/package.json +++ b/web/frontend/package.json @@ -23,6 +23,7 @@ "file-saver": "^2.0.5", "i18next": "^21.6.10", "i18next-browser-languagedetector": "^6.1.3", + "pg": "^8.11.1", "prop-types": "^15.8.1", "react": "^17.0.1", "react-beautiful-dnd": "^13.1.0", @@ -33,10 +34,10 @@ "react-scripts": "5.0.0", "short-unique-id": "^4.4.4", "web-vitals": "^2.1.4", - "yup": "^0.32.11", - "pg": "^8.11.1" + "yup": "^0.32.11" }, "devDependencies": { + "@playwright/test": "^1.40.1", "@testing-library/jest-dom": "^5.16.2", "@testing-library/react": "^12.1.5", "@types/file-saver": "^2.0.5", diff --git a/web/frontend/playwright.config.ts b/web/frontend/playwright.config.ts new file mode 100644 index 000000000..baaca056f --- /dev/null +++ b/web/frontend/playwright.config.ts @@ -0,0 +1,77 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '././tests', + /* 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 run start', + // url: 'http://127.0.0.1:3000', + // reuseExistingServer: !process.env.CI, + // }, +}); From b85f7d833731f471dbe7f0035f4cf28b3a57f4e7 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 1 Dec 2023 13:39:41 +0100 Subject: [PATCH 02/29] test: add initalizing i18next --- web/frontend/tests/shared.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 web/frontend/tests/shared.ts diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts new file mode 100644 index 000000000..0752450db --- /dev/null +++ b/web/frontend/tests/shared.ts @@ -0,0 +1,10 @@ +import en from './../src/language/en.json'; +import fr from './../src/language/fr.json'; +import de from './../src/language/de.json'; + +export function initI18n () { + i18n.init({ + resources: { en, fr, de }, + fallbackLng: ['en', 'fr', 'de'], + }); +} From 7cb3d629bf3838c761f6f74e864b0f1c0b585751 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 1 Dec 2023 17:07:29 +0100 Subject: [PATCH 03/29] test: add login/logout utils --- .../tests/hars/get_dev_login.376842.har | 14 +++++ .../tests/hars/get_dev_login.789012.har | 61 +++++++++++++++++++ web/frontend/tests/hars/logout.har | 60 ++++++++++++++++++ web/frontend/tests/mocks.ts | 26 ++++++++ web/frontend/tests/shared.ts | 15 +++++ 5 files changed, 176 insertions(+) create mode 100644 web/frontend/tests/hars/get_dev_login.376842.har create mode 100644 web/frontend/tests/hars/get_dev_login.789012.har create mode 100644 web/frontend/tests/hars/logout.har create mode 100644 web/frontend/tests/mocks.ts diff --git a/web/frontend/tests/hars/get_dev_login.376842.har b/web/frontend/tests/hars/get_dev_login.376842.har new file mode 100644 index 000000000..3b9cb5b4c --- /dev/null +++ b/web/frontend/tests/hars/get_dev_login.376842.har @@ -0,0 +1,14 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/get_dev_login.789012.har b/web/frontend/tests/hars/get_dev_login.789012.har new file mode 100644 index 000000000..86dac568f --- /dev/null +++ b/web/frontend/tests/hars/get_dev_login.789012.har @@ -0,0 +1,61 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-01T16:02:23.779Z", + "time": -1, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/get_dev_login/789012", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, + { "name": "accept", "value": "*/*" }, + { "name": "accept-encoding", "value": "gzip,deflate,br" }, + { "name": "cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 302, + "statusText": "Found", + "httpVersion": "1.1", + "cookies": [], + "headers": [ + { "name": "x-powered-by", "value": "Express" }, + { "name": "location", "value": "/logged" }, + { "name": "vary", "value": "Accept" }, + { "name": "content-type", "value": "text/plain; charset=utf-8" }, + { "name": "content-length", "value": "29" }, + { "name": "set-cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc; Path=/; Expires=Sat, 02 Dec 2023 16:02:23 GMT; HttpOnly" }, + { "name": "date", "value": "Fri, 01 Dec 2023 16:02:23 GMT" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "keep-alive", "value": "timeout=5" } + ], + "content": { + "size": 0, + "mimeType": "text/plain; charset=utf-8" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "/logged" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": -1 }, + "_apiRequest": true + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/logout.har b/web/frontend/tests/hars/logout.har new file mode 100644 index 000000000..2ea8883b0 --- /dev/null +++ b/web/frontend/tests/hars/logout.har @@ -0,0 +1,60 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-01T16:02:23.793Z", + "time": -1, + "request": { + "method": "POST", + "url": "http://127.0.0.1:3000/api/logout", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, + { "name": "accept", "value": "*/*" }, + { "name": "accept-encoding", "value": "gzip,deflate,br" }, + { "name": "cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 302, + "statusText": "Found", + "httpVersion": "1.1", + "cookies": [], + "headers": [ + { "name": "x-powered-by", "value": "Express" }, + { "name": "location", "value": "/" }, + { "name": "vary", "value": "Accept" }, + { "name": "content-type", "value": "text/plain; charset=utf-8" }, + { "name": "content-length", "value": "23" }, + { "name": "date", "value": "Fri, 01 Dec 2023 16:02:23 GMT" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "keep-alive", "value": "timeout=5" } + ], + "content": { + "size": 0, + "mimeType": "text/plain; charset=utf-8" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "/" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": -1 }, + "_apiRequest": true + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts new file mode 100644 index 000000000..716a02c59 --- /dev/null +++ b/web/frontend/tests/mocks.ts @@ -0,0 +1,26 @@ +export const SCIPER_ADMIN = process.env.REACT_APP_SCIPER_ADMIN; +export const SCIPER_USER = '789012'; + +export async function mockGetDevLogin (page: any) { + await page.routeFromHAR( + `./tests/hars/get_dev_login.${SCIPER_ADMIN}.har`, + { + url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, + update: false, + }); + await page.routeFromHAR( + `./tests/hars/get_dev_login.${SCIPER_USER}.har`, + { + url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`, + update: false, + }); +} + +export async function mockLogout (page: any) { + await page.routeFromHAR( + './tests/hars/logout.har', + { + url: `${process.env.FRONT_END_URL}/api/logout`, + update: false, + }); +} diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 0752450db..5c7a61bab 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -1,6 +1,7 @@ import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; +import { SCIPER_ADMIN, SCIPER_USER, mockGetDevLogin, mockLogout } from './mocks'; export function initI18n () { i18n.init({ @@ -8,3 +9,17 @@ export function initI18n () { fallbackLng: ['en', 'fr', 'de'], }); } + +export async function logIn (page: any, admin = false) { + await mockGetDevLogin(page); + await page.context().request.get( + `${process.env.FRONT_END_URL}/api/get_dev_login/${admin ? SCIPER_ADMIN : SCIPER_USER}` + ); + await page.reload(); +} + +export async function logOut (page: any) { + await mockLogout(page); + await page.context().request.post(`${process.env.FRONT_END_URL}/api/logout`); + await page.reload(); +} From 260175de5d1bda611d084672c8b9e72cbbcb5f75 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 1 Dec 2023 17:29:41 +0100 Subject: [PATCH 04/29] fix: add missing import --- web/frontend/tests/shared.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 5c7a61bab..4ca0be706 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -1,3 +1,4 @@ +import { default as i18n } from 'i18next'; import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; From 24c8f2f4db8b32e5aa0b0600ce711963ee77b7c1 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 1 Dec 2023 17:57:40 +0100 Subject: [PATCH 05/29] test: add navigation bar tests for authenticated/admin users --- web/frontend/tests/navigation.spec.ts | 36 +++++++++++++++++++++++++++ web/frontend/tests/shared.ts | 16 ++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 web/frontend/tests/navigation.spec.ts diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts new file mode 100644 index 000000000..1359ad7dc --- /dev/null +++ b/web/frontend/tests/navigation.spec.ts @@ -0,0 +1,36 @@ +import { default as i18n } from 'i18next'; +import { test, expect } from '@playwright/test'; +import { + initI18n, + logIn, + logOut, + assertOnlyVisibleToAuthenticated, + assertOnlyVisibleToAdmin, +} from './shared'; + +initI18n(); + +// authenticated non-admin + +test('Assert "Profile" button is visible upon logging in', async({ page }) => { + await page.goto(process.env.FRONT_END_URL); + await assertOnlyVisibleToAuthenticated( + page, page.getByRole('button', { name: i18n.t('Profile') }) + ); +}); + +// admin + +test('Assert "Create form" button is (only) visible to admin', async({ page }) => { + await page.goto(process.env.FRONT_END_URL); + await assertOnlyVisibleToAdmin( + page, page.getByRole('link', { name: i18n.t('navBarCreateForm')}) + ); +}); + +test('Assert "Admin" button is (only) visible to admin', async({ page }) => { + await page.goto(process.env.FRONT_END_URL); + await assertOnlyVisibleToAdmin( + page, page.getByRole('link', { name: i18n.t('navBarAdmin') }) + ); +}); diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 4ca0be706..72870e67a 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -1,4 +1,5 @@ import { default as i18n } from 'i18next'; +import { test, expect } from '@playwright/test'; import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; @@ -24,3 +25,18 @@ export async function logOut (page: any) { await page.context().request.post(`${process.env.FRONT_END_URL}/api/logout`); await page.reload(); } + +export async function assertOnlyVisibleToAuthenticated (page: any, locator: any) { + await expect(locator).toBeHidden(); // assert is hidden to unauthenticated user + await logIn(page); + await expect(locator).toBeVisible(); // assert is visible to authenticated user +} + +export async function assertOnlyVisibleToAdmin (page: any, locator: any) { + await expect(locator).toBeHidden(); // assert is hidden to unauthenticated user + await logIn(page); + await expect(locator).toBeHidden(); // assert is hidden to authenticated non-admin user + await logOut(page); + await logIn(page, true); + await expect(locator).toBeVisible(); // assert is visible to admin user +} From a3f146ae335f03befc2c025033cbec918993da81 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 13:58:37 +0100 Subject: [PATCH 06/29] fix: remove duplicate logo --- web/frontend/src/layout/NavBar.tsx | 1 - web/frontend/tests/navigation.spec.ts | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/web/frontend/src/layout/NavBar.tsx b/web/frontend/src/layout/NavBar.tsx index 3ac090269..fc2721824 100644 --- a/web/frontend/src/layout/NavBar.tsx +++ b/web/frontend/src/layout/NavBar.tsx @@ -179,7 +179,6 @@ const LeftSideNavBar = ({ authCtx, t }) => (
- Workflow Workflow
diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 1359ad7dc..82ef642bb 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -10,6 +10,16 @@ import { initI18n(); +// unauthenticated + +test('Assert D-Voting logo is present', async({ page }) => { + await page.goto(`${process.env.FRONT_END_URL}/about`); + const logo = await page.getByAltText(i18n.t('Workflow')); + await expect(logo).toBeVisible(); + await logo.click(); + await expect(page).toHaveURL(process.env.FRONT_END_URL); +}); + // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { From 16a75f34c51472a434947b829140709d6323201f Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 14:14:08 +0100 Subject: [PATCH 07/29] test: start each test at 'About' page --- web/frontend/tests/navigation.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 82ef642bb..bc71e98f2 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -10,10 +10,13 @@ import { initI18n(); +test.beforeEach(async ({ page }) => { + await page.goto(`${process.env.FRONT_END_URL}/about`); +}); + // unauthenticated test('Assert D-Voting logo is present', async({ page }) => { - await page.goto(`${process.env.FRONT_END_URL}/about`); const logo = await page.getByAltText(i18n.t('Workflow')); await expect(logo).toBeVisible(); await logo.click(); @@ -23,7 +26,6 @@ test('Assert D-Voting logo is present', async({ page }) => { // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { - await page.goto(process.env.FRONT_END_URL); await assertOnlyVisibleToAuthenticated( page, page.getByRole('button', { name: i18n.t('Profile') }) ); @@ -32,14 +34,12 @@ test('Assert "Profile" button is visible upon logging in', async({ page }) => { // admin test('Assert "Create form" button is (only) visible to admin', async({ page }) => { - await page.goto(process.env.FRONT_END_URL); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarCreateForm')}) ); }); test('Assert "Admin" button is (only) visible to admin', async({ page }) => { - await page.goto(process.env.FRONT_END_URL); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarAdmin') }) ); From b114a4cbf4f646e72733911926fc7bd92ada919f Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 14:21:40 +0100 Subject: [PATCH 08/29] test: added test for link to form list --- web/frontend/tests/navigation.spec.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index bc71e98f2..51c3d830b 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -23,6 +23,13 @@ test('Assert D-Voting logo is present', async({ page }) => { await expect(page).toHaveURL(process.env.FRONT_END_URL); }); +test('Assert link to form table is present', async({ page }) => { + const forms = await page.getByRole('link', { name: i18n.t('navBarStatus') }); + await expect(forms).toBeVisible(); + await forms.click(); + await expect(page).toHaveURL(`${process.env.FRONT_END_URL}/form/index`); +}); + // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { From c71808559d0db09bb34ea121b53e18b3450bae8d Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 14:24:27 +0100 Subject: [PATCH 09/29] docs: added README for automated tests --- web/frontend/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 web/frontend/README.md diff --git a/web/frontend/README.md b/web/frontend/README.md new file mode 100644 index 000000000..34a6cca09 --- /dev/null +++ b/web/frontend/README.md @@ -0,0 +1,33 @@ +# Automated Tests w/ Playwright + +## Setup + +Run + +``` +npx playwright install-deps --dry-run +``` + +to be shown the dependencies that you need to install on your machine (requires `root` access). + +You need to have the D-Voting application and DELA network running. You also need to make sure +that the environment variables from the D-Voting application are set (e.g. `FRONT_END_URL`) in +the shell you'll be executing the tests in. + +## Run tests + +Run + +``` +npx playwright test +``` + +to run the tests. This will open a window in your browser w/ the test results. + +To run interactive tests, run + +``` +npx playwright test --ui +``` + +this will open an user interface where you can interactively run and evaluate tests. From c8023ccb5bb6381cb799b2ec0c8e7604ba71a9f8 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 17:03:27 +0100 Subject: [PATCH 10/29] fix: do not include SCIPER_ADMIN in filename as it might be different for other devs --- .../hars/{get_dev_login.376842.har => get_dev_login.admin.har} | 0 web/frontend/tests/mocks.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename web/frontend/tests/hars/{get_dev_login.376842.har => get_dev_login.admin.har} (100%) diff --git a/web/frontend/tests/hars/get_dev_login.376842.har b/web/frontend/tests/hars/get_dev_login.admin.har similarity index 100% rename from web/frontend/tests/hars/get_dev_login.376842.har rename to web/frontend/tests/hars/get_dev_login.admin.har diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index 716a02c59..f28c64cfa 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -3,7 +3,7 @@ export const SCIPER_USER = '789012'; export async function mockGetDevLogin (page: any) { await page.routeFromHAR( - `./tests/hars/get_dev_login.${SCIPER_ADMIN}.har`, + `./tests/hars/get_dev_login.admin.har`, { url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, update: false, From bf17a929a541e7222fec2997b1241d5fc5ef06bd Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 17:26:31 +0100 Subject: [PATCH 11/29] fix: clean up Playwright config --- web/frontend/playwright.config.ts | 36 +------------------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/web/frontend/playwright.config.ts b/web/frontend/playwright.config.ts index baaca056f..5b38b9975 100644 --- a/web/frontend/playwright.config.ts +++ b/web/frontend/playwright.config.ts @@ -1,16 +1,10 @@ import { defineConfig, devices } from '@playwright/test'; -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: '././tests', + testDir: './tests', /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ @@ -23,8 +17,6 @@ export default defineConfig({ 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', @@ -46,32 +38,6 @@ export default defineConfig({ 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 run start', - // url: 'http://127.0.0.1:3000', - // reuseExistingServer: !process.env.CI, - // }, }); From 96ce8a574c2c7900523c186250c74bfd7a3f43c2 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 17:45:10 +0100 Subject: [PATCH 12/29] fix: use fixed admin sciper for mocks --- .../tests/hars/get_dev_login.123456.har | 61 +++++++++++++++++++ web/frontend/tests/mocks.ts | 4 +- 2 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 web/frontend/tests/hars/get_dev_login.123456.har diff --git a/web/frontend/tests/hars/get_dev_login.123456.har b/web/frontend/tests/hars/get_dev_login.123456.har new file mode 100644 index 000000000..3c6bd55e7 --- /dev/null +++ b/web/frontend/tests/hars/get_dev_login.123456.har @@ -0,0 +1,61 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-04T16:43:22.400Z", + "time": -1, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/get_dev_login/123456", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, + { "name": "accept", "value": "*/*" }, + { "name": "accept-encoding", "value": "gzip,deflate,br" }, + { "name": "cookie", "value": "connect.sid=s%3AZwwbh1O0l2yOuZFfDW4Os1Lhl7xg3sMq.%2B%2BsVN1Vd%2FikujBxcBTcXR%2FeHn8iHGI4Zpo90ej%2FUj00" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 302, + "statusText": "Found", + "httpVersion": "1.1", + "cookies": [], + "headers": [ + { "name": "x-powered-by", "value": "Express" }, + { "name": "location", "value": "/logged" }, + { "name": "vary", "value": "Accept" }, + { "name": "content-type", "value": "text/plain; charset=utf-8" }, + { "name": "content-length", "value": "29" }, + { "name": "set-cookie", "value": "connect.sid=s%3AZwwbh1O0l2yOuZFfDW4Os1Lhl7xg3sMq.%2B%2BsVN1Vd%2FikujBxcBTcXR%2FeHn8iHGI4Zpo90ej%2FUj00; Path=/; Expires=Tue, 05 Dec 2023 16:43:22 GMT; HttpOnly" }, + { "name": "date", "value": "Mon, 04 Dec 2023 16:43:22 GMT" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "keep-alive", "value": "timeout=5" } + ], + "content": { + "size": 0, + "mimeType": "text/plain; charset=utf-8" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "/logged" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": -1 }, + "_apiRequest": true + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index f28c64cfa..1d75bacb5 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -1,9 +1,9 @@ -export const SCIPER_ADMIN = process.env.REACT_APP_SCIPER_ADMIN; +export const SCIPER_ADMIN = '123456'; export const SCIPER_USER = '789012'; export async function mockGetDevLogin (page: any) { await page.routeFromHAR( - `./tests/hars/get_dev_login.admin.har`, + `./tests/hars/get_dev_login.${SCIPER_ADMIN}.har`, { url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, update: false, From d75b181a9bcf148e52f8562f8e9a168e4dd05947 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Mon, 4 Dec 2023 18:26:18 +0100 Subject: [PATCH 13/29] fix: add missing API mock --- ...5240cb33cb9e581ea0ce24c4e728a04e2a5d1.json | 1 + ...037964db4d746517f562ccb09b049db7f7a12.json | 1 + .../tests/hars/get_dev_login.admin.har | 14 -- .../tests/hars/personal_info.123456.har | 61 +++++++ .../tests/hars/personal_info.789012.har | 152 ++++++++++++++++++ web/frontend/tests/mocks.ts | 9 ++ web/frontend/tests/shared.ts | 3 +- 7 files changed, 226 insertions(+), 15 deletions(-) create mode 100644 web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json create mode 100644 web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json delete mode 100644 web/frontend/tests/hars/get_dev_login.admin.har create mode 100644 web/frontend/tests/hars/personal_info.123456.har create mode 100644 web/frontend/tests/hars/personal_info.789012.har diff --git a/web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json b/web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json new file mode 100644 index 000000000..fbbb5fb20 --- /dev/null +++ b/web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json @@ -0,0 +1 @@ +{"sciper":789012,"lastName":"789012","firstName":"sciper-#","isLoggedIn":true,"authorization":{}} \ No newline at end of file diff --git a/web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json b/web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json new file mode 100644 index 000000000..18abd32b4 --- /dev/null +++ b/web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json @@ -0,0 +1 @@ +{"sciper":123456,"lastName":"123456","firstName":"sciper-#","isLoggedIn":true,"authorization":{"roles":["add","list","remove"],"proxies":["post","put","delete"],"election":["create"]}} \ No newline at end of file diff --git a/web/frontend/tests/hars/get_dev_login.admin.har b/web/frontend/tests/hars/get_dev_login.admin.har deleted file mode 100644 index 3b9cb5b4c..000000000 --- a/web/frontend/tests/hars/get_dev_login.admin.har +++ /dev/null @@ -1,14 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Playwright", - "version": "1.40.1" - }, - "browser": { - "name": "chromium", - "version": "120.0.6099.28" - }, - "entries": [] - } -} \ No newline at end of file diff --git a/web/frontend/tests/hars/personal_info.123456.har b/web/frontend/tests/hars/personal_info.123456.har new file mode 100644 index 000000000..abed1763f --- /dev/null +++ b/web/frontend/tests/hars/personal_info.123456.har @@ -0,0 +1,61 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-04T17:23:04.317Z", + "time": 93.518, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "access-control-allow-origin", "value": "*" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "content-length", "value": "184" }, + { "name": "content-type", "value": "application/json; charset=utf-8" }, + { "name": "date", "value": "Mon, 04 Dec 2023 17:23:04 GMT" }, + { "name": "etag", "value": "W/\"b8-oDA3lk2010ZRf1YsywmwSdt/ehI\"" }, + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "x-powered-by", "value": "Express" } + ], + "content": { + "size": -1, + "mimeType": "application/json; charset=utf-8", + "_file": "a03037964db4d746517f562ccb09b049db7f7a12.json" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 93.518 } + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/personal_info.789012.har b/web/frontend/tests/hars/personal_info.789012.har new file mode 100644 index 000000000..7463cf7d1 --- /dev/null +++ b/web/frontend/tests/hars/personal_info.789012.har @@ -0,0 +1,152 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-04T17:23:03.108Z", + "time": 101.408, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Cookie", "value": "connect.sid=s%3AQ2aSAOTq7ZqQf5AgogqF_LFwWNEHzCEQ.cQzj5Bk4VecUqLBBGDIRqx8MYyOXEcr4XgJKJiPwjWA" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "access-control-allow-origin", "value": "*" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "content-length", "value": "97" }, + { "name": "content-type", "value": "application/json; charset=utf-8" }, + { "name": "date", "value": "Mon, 04 Dec 2023 17:23:03 GMT" }, + { "name": "etag", "value": "W/\"61-XwUkDLM8ueWB6gziTE5yigTipdE\"" }, + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "x-powered-by", "value": "Express" } + ], + "content": { + "size": -1, + "mimeType": "application/json; charset=utf-8", + "_file": "5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 101.408 } + }, + { + "startedDateTime": "2023-12-04T17:23:03.691Z", + "time": 70.777, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Cookie", "value": "connect.sid=s%3AQ2aSAOTq7ZqQf5AgogqF_LFwWNEHzCEQ.cQzj5Bk4VecUqLBBGDIRqx8MYyOXEcr4XgJKJiPwjWA" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 401, + "statusText": "Unauthorized", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "connection", "value": "keep-alive" }, + { "name": "content-length", "value": "15" }, + { "name": "content-type", "value": "text/html; charset=utf-8" }, + { "name": "date", "value": "Mon, 04 Dec 2023 17:23:03 GMT" }, + { "name": "etag", "value": "W/\"f-n9L/T8H7FjcXU5+wSuxCD+6xHlo\"" }, + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "set-cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg; Path=/; Expires=Tue, 05 Dec 2023 17:23:03 GMT; HttpOnly" }, + { "name": "x-powered-by", "value": "Express" } + ], + "content": { + "size": -1, + "mimeType": "text/html; charset=utf-8" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 70.777 } + }, + { + "startedDateTime": "2023-12-04T17:23:04.317Z", + "time": 93.518, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "access-control-allow-origin", "value": "*" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "content-length", "value": "184" }, + { "name": "content-type", "value": "application/json; charset=utf-8" }, + { "name": "date", "value": "Mon, 04 Dec 2023 17:23:04 GMT" }, + { "name": "etag", "value": "W/\"b8-oDA3lk2010ZRf1YsywmwSdt/ehI\"" }, + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "x-powered-by", "value": "Express" } + ], + "content": { + "size": -1, + "mimeType": "application/json; charset=utf-8", + "_file": "a03037964db4d746517f562ccb09b049db7f7a12.json" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 93.518 } + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index 1d75bacb5..4108a2583 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -1,6 +1,15 @@ export const SCIPER_ADMIN = '123456'; export const SCIPER_USER = '789012'; +export async function mockPersonalInfo (page: any, admin = false) { + await page.routeFromHAR( + `./tests/hars/personal_info.${admin ? SCIPER_ADMIN : SCIPER_USER}.har`, + { + url: `${process.env.FRONT_END_URL}/api/personal_info`, + update: false, + }); +} + export async function mockGetDevLogin (page: any) { await page.routeFromHAR( `./tests/hars/get_dev_login.${SCIPER_ADMIN}.har`, diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 72870e67a..8cf8295d5 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'; import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; -import { SCIPER_ADMIN, SCIPER_USER, mockGetDevLogin, mockLogout } from './mocks'; +import { SCIPER_ADMIN, SCIPER_USER, mockPersonalInfo, mockGetDevLogin, mockLogout } from './mocks'; export function initI18n () { i18n.init({ @@ -14,6 +14,7 @@ export function initI18n () { export async function logIn (page: any, admin = false) { await mockGetDevLogin(page); + await mockPersonalInfo(page, admin); await page.context().request.get( `${process.env.FRONT_END_URL}/api/get_dev_login/${admin ? SCIPER_ADMIN : SCIPER_USER}` ); From 715edbf63745ad446c7e56ec968789af80ccf189 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Dec 2023 09:49:27 +0100 Subject: [PATCH 14/29] docs: updated README w/ installation instructions and required environment variables --- web/frontend/README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/web/frontend/README.md b/web/frontend/README.md index 34a6cca09..b6fb74854 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -2,6 +2,16 @@ ## Setup +To install Playwright run + +``` +npx install playwright +``` + +which will install the module and its dependencies. In +order to execute the environment necessary for the tests, +additional system dependencies need to be installed. + Run ``` @@ -11,15 +21,19 @@ npx playwright install-deps --dry-run to be shown the dependencies that you need to install on your machine (requires `root` access). You need to have the D-Voting application and DELA network running. You also need to make sure -that the environment variables from the D-Voting application are set (e.g. `FRONT_END_URL`) in -the shell you'll be executing the tests in. +that the environment variables from the D-Voting application are set: + +- `FRONT_END_URL` must be set to your locally running instance +- `REACT_APP_DEV_LOGIN` must be set to `true` + +in the shell you'll be executing the tests in. ## Run tests Run ``` -npx playwright test +FRONT_END_URL= REACT_APP_DEV_LOGIN=true npx playwright test ``` to run the tests. This will open a window in your browser w/ the test results. @@ -27,7 +41,7 @@ to run the tests. This will open a window in your browser w/ the test results. To run interactive tests, run ``` -npx playwright test --ui +FRONT_END_URL= REACT_APP_DEV_LOGIN=true npx playwright test --ui ``` this will open an user interface where you can interactively run and evaluate tests. From a4b412d9c8671c9855ee72f259d7c3ab4346f38b Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Dec 2023 11:50:04 +0100 Subject: [PATCH 15/29] WIP: fix log in/log out mocks --- web/frontend/tests/shared.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 8cf8295d5..8057f4c4d 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -13,11 +13,7 @@ export function initI18n () { } export async function logIn (page: any, admin = false) { - await mockGetDevLogin(page); await mockPersonalInfo(page, admin); - await page.context().request.get( - `${process.env.FRONT_END_URL}/api/get_dev_login/${admin ? SCIPER_ADMIN : SCIPER_USER}` - ); await page.reload(); } From df1111ecb8ff749edbe8e6b38833055e4be39133 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Dec 2023 15:34:16 +0100 Subject: [PATCH 16/29] fix: fix log in/log out helper functions --- ...2ff4fc1fb163717539fb04aec420feeb11e5a.html | 1 + web/frontend/tests/hars/personal_info.har | 67 +++++++++++++++++++ web/frontend/tests/mocks.ts | 11 ++- web/frontend/tests/navigation.spec.ts | 2 + web/frontend/tests/shared.ts | 5 +- 5 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html create mode 100644 web/frontend/tests/hars/personal_info.har diff --git a/web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html b/web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html new file mode 100644 index 000000000..e2c1c215e --- /dev/null +++ b/web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html @@ -0,0 +1 @@ +Unauthenticated \ No newline at end of file diff --git a/web/frontend/tests/hars/personal_info.har b/web/frontend/tests/hars/personal_info.har new file mode 100644 index 000000000..d381ea761 --- /dev/null +++ b/web/frontend/tests/hars/personal_info.har @@ -0,0 +1,67 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "firefox", + "version": "119.0" + }, + "entries": [ + { + "startedDateTime": "2023-12-05T14:25:28.081Z", + "time": 0.06, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Host", "value": "127.0.0.1:3000" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:119.0) Gecko/20100101 Firefox/119.0" }, + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Accept-Encoding", "value": "gzip, deflate, br" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "Connection", "value": "keep-alive" }, + { "name": "Sec-Fetch-Dest", "value": "empty" }, + { "name": "Sec-Fetch-Mode", "value": "cors" }, + { "name": "Sec-Fetch-Site", "value": "same-origin" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 401, + "statusText": "Unauthorized", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "x-powered-by", "value": "Express" }, + { "name": "content-type", "value": "text/html; charset=utf-8" }, + { "name": "content-length", "value": "15" }, + { "name": "etag", "value": "W/\"f-n9L/T8H7FjcXU5+wSuxCD+6xHlo\"" }, + { "name": "set-cookie", "value": "connect.sid=s%3AO6aDExYv7Ocwz6IQUJ7l0I3u0XA7OHMg.Hq5%2FbR4nwsJbDjh1kVYuXweeFTmPF9d0Tx8t%2F1T3hOQ; Path=/; Expires=Wed, 06 Dec 2023 14:25:28 GMT; HttpOnly" }, + { "name": "date", "value": "Tue" }, + { "name": "date", "value": "05 Dec 2023 14:25:28 GMT" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "keep-alive", "value": "timeout=5" } + ], + "content": { + "size": -1, + "mimeType": "text/html; charset=utf-8", + "_file": "9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 0.06 } + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index 4108a2583..f0b5dd3cd 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -1,7 +1,16 @@ export const SCIPER_ADMIN = '123456'; export const SCIPER_USER = '789012'; -export async function mockPersonalInfo (page: any, admin = false) { +export async function mockPersonalInfo (page: any, authenticated = false, admin = false) { + if (!authenticated) { + await page.routeFromHAR( + './tests/hars/personal_info.har', + { + url: `${process.env.FRONT_END_URL}/api/personal_info`, + update: false, + }); + return; + } await page.routeFromHAR( `./tests/hars/personal_info.${admin ? SCIPER_ADMIN : SCIPER_USER}.har`, { diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 51c3d830b..905d07547 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -7,10 +7,12 @@ import { assertOnlyVisibleToAuthenticated, assertOnlyVisibleToAdmin, } from './shared'; +import { mockPersonalInfo } from './mocks'; initI18n(); test.beforeEach(async ({ page }) => { + await mockPersonalInfo(page); await page.goto(`${process.env.FRONT_END_URL}/about`); }); diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 8057f4c4d..5275bcf0e 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -13,13 +13,12 @@ export function initI18n () { } export async function logIn (page: any, admin = false) { - await mockPersonalInfo(page, admin); + await mockPersonalInfo(page, true, admin); await page.reload(); } export async function logOut (page: any) { - await mockLogout(page); - await page.context().request.post(`${process.env.FRONT_END_URL}/api/logout`); + await mockPersonalInfo(page) await page.reload(); } From 0e6c079d9acdb77466f33e17388597b4d0f4a4e0 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Tue, 5 Dec 2023 15:41:56 +0100 Subject: [PATCH 17/29] docs: add mandatory FRONT_END_URL value to READMEs --- README.docker.md | 2 +- web/frontend/README.md | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.docker.md b/README.docker.md index e99fef976..23f8ff29e 100644 --- a/README.docker.md +++ b/README.docker.md @@ -21,7 +21,7 @@ DATABASE_PASSWORD=XXX # choose any PostgreSQL password DATABASE_HOST=db DATABASE_PORT=5432 DB_PATH=dvoting # LMDB database path -FRONT_END_URL=http://127.0.0.1:3000 +FRONT_END_URL=http://127.0.0.1:3000 # the automated frontend tests expect this value do not change it BACKEND_HOST=backend BACKEND_PORT=5000 SESSION_SECRET=XXX # choose any secret diff --git a/web/frontend/README.md b/web/frontend/README.md index b6fb74854..42e89b5f9 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -24,7 +24,6 @@ You need to have the D-Voting application and DELA network running. You also nee that the environment variables from the D-Voting application are set: - `FRONT_END_URL` must be set to your locally running instance -- `REACT_APP_DEV_LOGIN` must be set to `true` in the shell you'll be executing the tests in. @@ -33,7 +32,7 @@ in the shell you'll be executing the tests in. Run ``` -FRONT_END_URL= REACT_APP_DEV_LOGIN=true npx playwright test +FRONT_END_URL=http://127.0.0.1:3000 npx playwright test ``` to run the tests. This will open a window in your browser w/ the test results. @@ -41,7 +40,7 @@ to run the tests. This will open a window in your browser w/ the test results. To run interactive tests, run ``` -FRONT_END_URL= REACT_APP_DEV_LOGIN=true npx playwright test --ui +FRONT_END_URL=http://127.0.0.1:3000 npx playwright test --ui ``` this will open an user interface where you can interactively run and evaluate tests. From b50a584c73ea949c0fc3b2176ac9e8da000961aa Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Thu, 7 Dec 2023 10:08:51 +0100 Subject: [PATCH 18/29] test: clean up authentication mocks --- web/frontend/tests/mocks.ts | 37 ++++++++++++------------------------ web/frontend/tests/shared.ts | 27 ++++++++++++++++++-------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index f0b5dd3cd..fb16a3d24 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -1,42 +1,29 @@ -export const SCIPER_ADMIN = '123456'; -export const SCIPER_USER = '789012'; - -export async function mockPersonalInfo (page: any, authenticated = false, admin = false) { - if (!authenticated) { - await page.routeFromHAR( - './tests/hars/personal_info.har', - { - url: `${process.env.FRONT_END_URL}/api/personal_info`, - update: false, - }); - return; - } +export async function mockPersonalInfo (page: any, sciper) { await page.routeFromHAR( - `./tests/hars/personal_info.${admin ? SCIPER_ADMIN : SCIPER_USER}.har`, + sciper ? `./tests/hars/personal_info.${sciper}.har` : './tests/hars/personal_info.har', { url: `${process.env.FRONT_END_URL}/api/personal_info`, update: false, }); } -export async function mockGetDevLogin (page: any) { - await page.routeFromHAR( - `./tests/hars/get_dev_login.${SCIPER_ADMIN}.har`, - { - url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, - update: false, - }); +export async function mockGetDevLogin (page: any, sciper) { await page.routeFromHAR( - `./tests/hars/get_dev_login.${SCIPER_USER}.har`, + `./tests/hars/get_dev_login.${sciper}.har`, { - url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`, + url: `${process.env.FRONT_END_URL}/api/get_dev_login/${sciper}`, update: false, }); + // dummy route for "Login" button depending on local configuration + await page.route( + `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}`, + async route => {await route.fulfill({});} + ); } -export async function mockLogout (page: any) { +export async function mockLogout (page: any, sciper) { await page.routeFromHAR( - './tests/hars/logout.har', + `./tests/hars/logout.${sciper}.har`, { url: `${process.env.FRONT_END_URL}/api/logout`, update: false, diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 5275bcf0e..7e8ac77c2 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'; import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; -import { SCIPER_ADMIN, SCIPER_USER, mockPersonalInfo, mockGetDevLogin, mockLogout } from './mocks'; +import { mockPersonalInfo, mockGetDevLogin, mockLogout } from './mocks'; export function initI18n () { i18n.init({ @@ -12,27 +12,38 @@ export function initI18n () { }); } -export async function logIn (page: any, admin = false) { - await mockPersonalInfo(page, true, admin); +export const SCIPER_ADMIN = '123456'; +export const SCIPER_USER = '789012'; + +export async function logIn (page: any, sciper) { + await mockGetDevLogin(page, sciper); + await mockPersonalInfo(page, sciper); + // uncomment the following line to update the HAR files + await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${sciper}`); await page.reload(); + await expect(page).toHaveURL(page.url()); // make sure that page is loaded correctly } -export async function logOut (page: any) { - await mockPersonalInfo(page) +export async function logOut (page: any, sciper) { + await mockLogout(page, sciper); +// await mockPersonalInfo(page, null); + // uncomment the following line to update the HAR files + await page.context().request.post(`${process.env.FRONT_END_URL}/api/logout`); await page.reload(); + await expect(page).toHaveURL(page.url()); // make sure that page is loaded correctly } export async function assertOnlyVisibleToAuthenticated (page: any, locator: any) { await expect(locator).toBeHidden(); // assert is hidden to unauthenticated user - await logIn(page); + await logIn(page, SCIPER_USER); await expect(locator).toBeVisible(); // assert is visible to authenticated user } export async function assertOnlyVisibleToAdmin (page: any, locator: any) { await expect(locator).toBeHidden(); // assert is hidden to unauthenticated user - await logIn(page); + await logIn(page, SCIPER_USER); await expect(locator).toBeHidden(); // assert is hidden to authenticated non-admin user await logOut(page); - await logIn(page, true); + await logIn(page, SCIPER_ADMIN); await expect(locator).toBeVisible(); // assert is visible to admin user } From 8db9f9eb17aa128ca592e3037ae19ccc2a1e57a4 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Thu, 7 Dec 2023 16:30:12 +0100 Subject: [PATCH 19/29] test: clean up HAR file management and authentication mocking --- ...037964db4d746517f562ccb09b049db7f7a12.json | 0 .../tests/hars/123456/get_dev_login.har | 14 ++ .../personal_info.har} | 10 +- ...5240cb33cb9e581ea0ce24c4e728a04e2a5d1.json | 0 .../tests/hars/789012/get_dev_login.har | 14 ++ .../tests/hars/789012/personal_info.har | 61 +++++++ ...2ff4fc1fb163717539fb04aec420feeb11e5a.html | 0 .../hars/{ => anonymous}/personal_info.har | 31 ++-- .../tests/hars/get_dev_login.123456.har | 61 ------- .../tests/hars/get_dev_login.789012.har | 61 ------- web/frontend/tests/hars/logout.har | 60 ------- .../tests/hars/personal_info.789012.har | 152 ------------------ web/frontend/tests/mocks.ts | 46 ++++-- web/frontend/tests/navigation.spec.ts | 39 ++++- web/frontend/tests/shared.ts | 25 +-- 15 files changed, 179 insertions(+), 395 deletions(-) rename web/frontend/tests/hars/{ => 123456}/a03037964db4d746517f562ccb09b049db7f7a12.json (100%) create mode 100644 web/frontend/tests/hars/123456/get_dev_login.har rename web/frontend/tests/hars/{personal_info.123456.har => 123456/personal_info.har} (83%) rename web/frontend/tests/hars/{ => 789012}/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json (100%) create mode 100644 web/frontend/tests/hars/789012/get_dev_login.har create mode 100644 web/frontend/tests/hars/789012/personal_info.har rename web/frontend/tests/hars/{ => anonymous}/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html (100%) rename web/frontend/tests/hars/{ => anonymous}/personal_info.har (58%) delete mode 100644 web/frontend/tests/hars/get_dev_login.123456.har delete mode 100644 web/frontend/tests/hars/get_dev_login.789012.har delete mode 100644 web/frontend/tests/hars/logout.har delete mode 100644 web/frontend/tests/hars/personal_info.789012.har diff --git a/web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json b/web/frontend/tests/hars/123456/a03037964db4d746517f562ccb09b049db7f7a12.json similarity index 100% rename from web/frontend/tests/hars/a03037964db4d746517f562ccb09b049db7f7a12.json rename to web/frontend/tests/hars/123456/a03037964db4d746517f562ccb09b049db7f7a12.json diff --git a/web/frontend/tests/hars/123456/get_dev_login.har b/web/frontend/tests/hars/123456/get_dev_login.har new file mode 100644 index 000000000..3b9cb5b4c --- /dev/null +++ b/web/frontend/tests/hars/123456/get_dev_login.har @@ -0,0 +1,14 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/personal_info.123456.har b/web/frontend/tests/hars/123456/personal_info.har similarity index 83% rename from web/frontend/tests/hars/personal_info.123456.har rename to web/frontend/tests/hars/123456/personal_info.har index abed1763f..1482d5dda 100644 --- a/web/frontend/tests/hars/personal_info.123456.har +++ b/web/frontend/tests/hars/123456/personal_info.har @@ -11,8 +11,8 @@ }, "entries": [ { - "startedDateTime": "2023-12-04T17:23:04.317Z", - "time": 93.518, + "startedDateTime": "2023-12-07T15:16:05.427Z", + "time": 63.36, "request": { "method": "GET", "url": "http://127.0.0.1:3000/api/personal_info", @@ -21,7 +21,7 @@ "headers": [ { "name": "Accept", "value": "*/*" }, { "name": "Accept-Language", "value": "en-US" }, - { "name": "Cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg" }, + { "name": "Cookie", "value": "connect.sid=s%3AxeUPf49ZYc9AUrUtzig9-O4g0Z_RVtVV.ChZVAx%2FL%2BIzfgIlkxzUxTLVduImdZIp68OdvODtveTU" }, { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } ], @@ -39,7 +39,7 @@ { "name": "connection", "value": "keep-alive" }, { "name": "content-length", "value": "184" }, { "name": "content-type", "value": "application/json; charset=utf-8" }, - { "name": "date", "value": "Mon, 04 Dec 2023 17:23:04 GMT" }, + { "name": "date", "value": "Thu, 07 Dec 2023 15:16:05 GMT" }, { "name": "etag", "value": "W/\"b8-oDA3lk2010ZRf1YsywmwSdt/ehI\"" }, { "name": "keep-alive", "value": "timeout=5" }, { "name": "x-powered-by", "value": "Express" } @@ -54,7 +54,7 @@ "redirectURL": "" }, "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": 93.518 } + "timings": { "send": -1, "wait": -1, "receive": 63.36 } } ] } diff --git a/web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json b/web/frontend/tests/hars/789012/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json similarity index 100% rename from web/frontend/tests/hars/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json rename to web/frontend/tests/hars/789012/5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json diff --git a/web/frontend/tests/hars/789012/get_dev_login.har b/web/frontend/tests/hars/789012/get_dev_login.har new file mode 100644 index 000000000..3b9cb5b4c --- /dev/null +++ b/web/frontend/tests/hars/789012/get_dev_login.har @@ -0,0 +1,14 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/789012/personal_info.har b/web/frontend/tests/hars/789012/personal_info.har new file mode 100644 index 000000000..2f68ed6a7 --- /dev/null +++ b/web/frontend/tests/hars/789012/personal_info.har @@ -0,0 +1,61 @@ +{ + "log": { + "version": "1.2", + "creator": { + "name": "Playwright", + "version": "1.40.1" + }, + "browser": { + "name": "chromium", + "version": "120.0.6099.28" + }, + "entries": [ + { + "startedDateTime": "2023-12-07T15:14:39.129Z", + "time": 56.608, + "request": { + "method": "GET", + "url": "http://127.0.0.1:3000/api/personal_info", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "Accept", "value": "*/*" }, + { "name": "Accept-Language", "value": "en-US" }, + { "name": "Cookie", "value": "connect.sid=s%3AAN1F283daySUs-3ytVagTfigWaedTgqO.iahChcGgJKx0khpkcm1jBBrQ89QsRN5cW9tOWnIgKgs" }, + { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1 + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "HTTP/1.1", + "cookies": [], + "headers": [ + { "name": "access-control-allow-origin", "value": "*" }, + { "name": "connection", "value": "keep-alive" }, + { "name": "content-length", "value": "97" }, + { "name": "content-type", "value": "application/json; charset=utf-8" }, + { "name": "date", "value": "Thu, 07 Dec 2023 15:14:39 GMT" }, + { "name": "etag", "value": "W/\"61-XwUkDLM8ueWB6gziTE5yigTipdE\"" }, + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "x-powered-by", "value": "Express" } + ], + "content": { + "size": -1, + "mimeType": "application/json; charset=utf-8", + "_file": "5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json" + }, + "headersSize": -1, + "bodySize": -1, + "redirectURL": "" + }, + "cache": {}, + "timings": { "send": -1, "wait": -1, "receive": 56.608 } + } + ] + } +} \ No newline at end of file diff --git a/web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html b/web/frontend/tests/hars/anonymous/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html similarity index 100% rename from web/frontend/tests/hars/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html rename to web/frontend/tests/hars/anonymous/9fd2ff4fc1fb163717539fb04aec420feeb11e5a.html diff --git a/web/frontend/tests/hars/personal_info.har b/web/frontend/tests/hars/anonymous/personal_info.har similarity index 58% rename from web/frontend/tests/hars/personal_info.har rename to web/frontend/tests/hars/anonymous/personal_info.har index d381ea761..91474fd6a 100644 --- a/web/frontend/tests/hars/personal_info.har +++ b/web/frontend/tests/hars/anonymous/personal_info.har @@ -6,29 +6,23 @@ "version": "1.40.1" }, "browser": { - "name": "firefox", - "version": "119.0" + "name": "chromium", + "version": "120.0.6099.28" }, "entries": [ { - "startedDateTime": "2023-12-05T14:25:28.081Z", - "time": 0.06, + "startedDateTime": "2023-12-07T15:11:00.609Z", + "time": 50.718, "request": { "method": "GET", "url": "http://127.0.0.1:3000/api/personal_info", "httpVersion": "HTTP/1.1", "cookies": [], "headers": [ - { "name": "Host", "value": "127.0.0.1:3000" }, - { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:119.0) Gecko/20100101 Firefox/119.0" }, { "name": "Accept", "value": "*/*" }, { "name": "Accept-Language", "value": "en-US" }, - { "name": "Accept-Encoding", "value": "gzip, deflate, br" }, { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, - { "name": "Connection", "value": "keep-alive" }, - { "name": "Sec-Fetch-Dest", "value": "empty" }, - { "name": "Sec-Fetch-Mode", "value": "cors" }, - { "name": "Sec-Fetch-Site", "value": "same-origin" } + { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } ], "queryString": [], "headersSize": -1, @@ -40,15 +34,14 @@ "httpVersion": "HTTP/1.1", "cookies": [], "headers": [ - { "name": "x-powered-by", "value": "Express" }, - { "name": "content-type", "value": "text/html; charset=utf-8" }, + { "name": "connection", "value": "keep-alive" }, { "name": "content-length", "value": "15" }, + { "name": "content-type", "value": "text/html; charset=utf-8" }, + { "name": "date", "value": "Thu, 07 Dec 2023 15:11:00 GMT" }, { "name": "etag", "value": "W/\"f-n9L/T8H7FjcXU5+wSuxCD+6xHlo\"" }, - { "name": "set-cookie", "value": "connect.sid=s%3AO6aDExYv7Ocwz6IQUJ7l0I3u0XA7OHMg.Hq5%2FbR4nwsJbDjh1kVYuXweeFTmPF9d0Tx8t%2F1T3hOQ; Path=/; Expires=Wed, 06 Dec 2023 14:25:28 GMT; HttpOnly" }, - { "name": "date", "value": "Tue" }, - { "name": "date", "value": "05 Dec 2023 14:25:28 GMT" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "keep-alive", "value": "timeout=5" } + { "name": "keep-alive", "value": "timeout=5" }, + { "name": "set-cookie", "value": "connect.sid=s%3AQhEmafnnGB6uPjxRFKwNdJg9MDQYmbkB.r0PBLNSKHdFLqMKbOVv%2FrgQVtN1i6JnbLElS%2Fzt7q%2F8; Path=/; Expires=Fri, 08 Dec 2023 15:11:00 GMT; HttpOnly" }, + { "name": "x-powered-by", "value": "Express" } ], "content": { "size": -1, @@ -60,7 +53,7 @@ "redirectURL": "" }, "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": 0.06 } + "timings": { "send": -1, "wait": -1, "receive": 50.718 } } ] } diff --git a/web/frontend/tests/hars/get_dev_login.123456.har b/web/frontend/tests/hars/get_dev_login.123456.har deleted file mode 100644 index 3c6bd55e7..000000000 --- a/web/frontend/tests/hars/get_dev_login.123456.har +++ /dev/null @@ -1,61 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Playwright", - "version": "1.40.1" - }, - "browser": { - "name": "chromium", - "version": "120.0.6099.28" - }, - "entries": [ - { - "startedDateTime": "2023-12-04T16:43:22.400Z", - "time": -1, - "request": { - "method": "GET", - "url": "http://127.0.0.1:3000/api/get_dev_login/123456", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, - { "name": "accept", "value": "*/*" }, - { "name": "accept-encoding", "value": "gzip,deflate,br" }, - { "name": "cookie", "value": "connect.sid=s%3AZwwbh1O0l2yOuZFfDW4Os1Lhl7xg3sMq.%2B%2BsVN1Vd%2FikujBxcBTcXR%2FeHn8iHGI4Zpo90ej%2FUj00" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 302, - "statusText": "Found", - "httpVersion": "1.1", - "cookies": [], - "headers": [ - { "name": "x-powered-by", "value": "Express" }, - { "name": "location", "value": "/logged" }, - { "name": "vary", "value": "Accept" }, - { "name": "content-type", "value": "text/plain; charset=utf-8" }, - { "name": "content-length", "value": "29" }, - { "name": "set-cookie", "value": "connect.sid=s%3AZwwbh1O0l2yOuZFfDW4Os1Lhl7xg3sMq.%2B%2BsVN1Vd%2FikujBxcBTcXR%2FeHn8iHGI4Zpo90ej%2FUj00; Path=/; Expires=Tue, 05 Dec 2023 16:43:22 GMT; HttpOnly" }, - { "name": "date", "value": "Mon, 04 Dec 2023 16:43:22 GMT" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "keep-alive", "value": "timeout=5" } - ], - "content": { - "size": 0, - "mimeType": "text/plain; charset=utf-8" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "/logged" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": -1 }, - "_apiRequest": true - } - ] - } -} \ No newline at end of file diff --git a/web/frontend/tests/hars/get_dev_login.789012.har b/web/frontend/tests/hars/get_dev_login.789012.har deleted file mode 100644 index 86dac568f..000000000 --- a/web/frontend/tests/hars/get_dev_login.789012.har +++ /dev/null @@ -1,61 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Playwright", - "version": "1.40.1" - }, - "browser": { - "name": "chromium", - "version": "120.0.6099.28" - }, - "entries": [ - { - "startedDateTime": "2023-12-01T16:02:23.779Z", - "time": -1, - "request": { - "method": "GET", - "url": "http://127.0.0.1:3000/api/get_dev_login/789012", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, - { "name": "accept", "value": "*/*" }, - { "name": "accept-encoding", "value": "gzip,deflate,br" }, - { "name": "cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 302, - "statusText": "Found", - "httpVersion": "1.1", - "cookies": [], - "headers": [ - { "name": "x-powered-by", "value": "Express" }, - { "name": "location", "value": "/logged" }, - { "name": "vary", "value": "Accept" }, - { "name": "content-type", "value": "text/plain; charset=utf-8" }, - { "name": "content-length", "value": "29" }, - { "name": "set-cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc; Path=/; Expires=Sat, 02 Dec 2023 16:02:23 GMT; HttpOnly" }, - { "name": "date", "value": "Fri, 01 Dec 2023 16:02:23 GMT" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "keep-alive", "value": "timeout=5" } - ], - "content": { - "size": 0, - "mimeType": "text/plain; charset=utf-8" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "/logged" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": -1 }, - "_apiRequest": true - } - ] - } -} \ No newline at end of file diff --git a/web/frontend/tests/hars/logout.har b/web/frontend/tests/hars/logout.har deleted file mode 100644 index 2ea8883b0..000000000 --- a/web/frontend/tests/hars/logout.har +++ /dev/null @@ -1,60 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Playwright", - "version": "1.40.1" - }, - "browser": { - "name": "chromium", - "version": "120.0.6099.28" - }, - "entries": [ - { - "startedDateTime": "2023-12-01T16:02:23.793Z", - "time": -1, - "request": { - "method": "POST", - "url": "http://127.0.0.1:3000/api/logout", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "user-agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" }, - { "name": "accept", "value": "*/*" }, - { "name": "accept-encoding", "value": "gzip,deflate,br" }, - { "name": "cookie", "value": "connect.sid=s%3AbBcBe58fDXREbXhfOtnasIBZgRm0HZjx.Q6TqSHcScxdSaGC%2FwWF1szhFn390pehAeagNzc0Dztc" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 302, - "statusText": "Found", - "httpVersion": "1.1", - "cookies": [], - "headers": [ - { "name": "x-powered-by", "value": "Express" }, - { "name": "location", "value": "/" }, - { "name": "vary", "value": "Accept" }, - { "name": "content-type", "value": "text/plain; charset=utf-8" }, - { "name": "content-length", "value": "23" }, - { "name": "date", "value": "Fri, 01 Dec 2023 16:02:23 GMT" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "keep-alive", "value": "timeout=5" } - ], - "content": { - "size": 0, - "mimeType": "text/plain; charset=utf-8" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "/" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": -1 }, - "_apiRequest": true - } - ] - } -} \ No newline at end of file diff --git a/web/frontend/tests/hars/personal_info.789012.har b/web/frontend/tests/hars/personal_info.789012.har deleted file mode 100644 index 7463cf7d1..000000000 --- a/web/frontend/tests/hars/personal_info.789012.har +++ /dev/null @@ -1,152 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Playwright", - "version": "1.40.1" - }, - "browser": { - "name": "chromium", - "version": "120.0.6099.28" - }, - "entries": [ - { - "startedDateTime": "2023-12-04T17:23:03.108Z", - "time": 101.408, - "request": { - "method": "GET", - "url": "http://127.0.0.1:3000/api/personal_info", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "Accept", "value": "*/*" }, - { "name": "Accept-Language", "value": "en-US" }, - { "name": "Cookie", "value": "connect.sid=s%3AQ2aSAOTq7ZqQf5AgogqF_LFwWNEHzCEQ.cQzj5Bk4VecUqLBBGDIRqx8MYyOXEcr4XgJKJiPwjWA" }, - { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, - { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "access-control-allow-origin", "value": "*" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "content-length", "value": "97" }, - { "name": "content-type", "value": "application/json; charset=utf-8" }, - { "name": "date", "value": "Mon, 04 Dec 2023 17:23:03 GMT" }, - { "name": "etag", "value": "W/\"61-XwUkDLM8ueWB6gziTE5yigTipdE\"" }, - { "name": "keep-alive", "value": "timeout=5" }, - { "name": "x-powered-by", "value": "Express" } - ], - "content": { - "size": -1, - "mimeType": "application/json; charset=utf-8", - "_file": "5f05240cb33cb9e581ea0ce24c4e728a04e2a5d1.json" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": 101.408 } - }, - { - "startedDateTime": "2023-12-04T17:23:03.691Z", - "time": 70.777, - "request": { - "method": "GET", - "url": "http://127.0.0.1:3000/api/personal_info", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "Accept", "value": "*/*" }, - { "name": "Accept-Language", "value": "en-US" }, - { "name": "Cookie", "value": "connect.sid=s%3AQ2aSAOTq7ZqQf5AgogqF_LFwWNEHzCEQ.cQzj5Bk4VecUqLBBGDIRqx8MYyOXEcr4XgJKJiPwjWA" }, - { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, - { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 401, - "statusText": "Unauthorized", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "connection", "value": "keep-alive" }, - { "name": "content-length", "value": "15" }, - { "name": "content-type", "value": "text/html; charset=utf-8" }, - { "name": "date", "value": "Mon, 04 Dec 2023 17:23:03 GMT" }, - { "name": "etag", "value": "W/\"f-n9L/T8H7FjcXU5+wSuxCD+6xHlo\"" }, - { "name": "keep-alive", "value": "timeout=5" }, - { "name": "set-cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg; Path=/; Expires=Tue, 05 Dec 2023 17:23:03 GMT; HttpOnly" }, - { "name": "x-powered-by", "value": "Express" } - ], - "content": { - "size": -1, - "mimeType": "text/html; charset=utf-8" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": 70.777 } - }, - { - "startedDateTime": "2023-12-04T17:23:04.317Z", - "time": 93.518, - "request": { - "method": "GET", - "url": "http://127.0.0.1:3000/api/personal_info", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "Accept", "value": "*/*" }, - { "name": "Accept-Language", "value": "en-US" }, - { "name": "Cookie", "value": "connect.sid=s%3Al_rokw2lbl6SlBqtggyMNmtIZBAD7xA1.q7QASu8UppgHK%2FofjQM%2BrL5zJL2NmqL2wiXcFRRM3Fg" }, - { "name": "Referer", "value": "http://127.0.0.1:3000/about" }, - { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.28 Safari/537.36" } - ], - "queryString": [], - "headersSize": -1, - "bodySize": -1 - }, - "response": { - "status": 200, - "statusText": "OK", - "httpVersion": "HTTP/1.1", - "cookies": [], - "headers": [ - { "name": "access-control-allow-origin", "value": "*" }, - { "name": "connection", "value": "keep-alive" }, - { "name": "content-length", "value": "184" }, - { "name": "content-type", "value": "application/json; charset=utf-8" }, - { "name": "date", "value": "Mon, 04 Dec 2023 17:23:04 GMT" }, - { "name": "etag", "value": "W/\"b8-oDA3lk2010ZRf1YsywmwSdt/ehI\"" }, - { "name": "keep-alive", "value": "timeout=5" }, - { "name": "x-powered-by", "value": "Express" } - ], - "content": { - "size": -1, - "mimeType": "application/json; charset=utf-8", - "_file": "a03037964db4d746517f562ccb09b049db7f7a12.json" - }, - "headersSize": -1, - "bodySize": -1, - "redirectURL": "" - }, - "cache": {}, - "timings": { "send": -1, "wait": -1, "receive": 93.518 } - } - ] - } -} \ No newline at end of file diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index fb16a3d24..4911ede53 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -1,31 +1,43 @@ +export const SCIPER_ADMIN = '123456'; +export const SCIPER_USER = '789012'; +export const UPDATE = false; + export async function mockPersonalInfo (page: any, sciper) { + // clear current mock + await page.unroute(`${process.env.FRONT_END_URL}/api/personal_info`); await page.routeFromHAR( - sciper ? `./tests/hars/personal_info.${sciper}.har` : './tests/hars/personal_info.har', + sciper ? `./tests/hars/${sciper}/personal_info.har` : './tests/hars/anonymous/personal_info.har', { url: `${process.env.FRONT_END_URL}/api/personal_info`, - update: false, + update: UPDATE, }); } -export async function mockGetDevLogin (page: any, sciper) { +export async function mockGetDevLogin (page: any) { await page.routeFromHAR( - `./tests/hars/get_dev_login.${sciper}.har`, + `./tests/hars/${SCIPER_ADMIN}/get_dev_login.har`, { - url: `${process.env.FRONT_END_URL}/api/get_dev_login/${sciper}`, - update: false, + url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, + update: UPDATE, }); - // dummy route for "Login" button depending on local configuration - await page.route( - `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}`, - async route => {await route.fulfill({});} - ); -} - -export async function mockLogout (page: any, sciper) { await page.routeFromHAR( - `./tests/hars/logout.${sciper}.har`, + `./tests/hars/${SCIPER_USER}/get_dev_login.har`, { - url: `${process.env.FRONT_END_URL}/api/logout`, - update: false, + url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`, + update: UPDATE, }); + if (process.env.REACT_APP_SCIPER_ADMIN !== undefined && process.env.REACT_APP_SCIPER_ADMIN !== SCIPER_ADMIN) { + // dummy route for "Login" button depending on local configuration + await page.route( + `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}`, + async route => {await route.fulfill({});} + ); + } +} + +export async function mockLogout (page: any) { + await page.route( + `${process.env.FRONT_END_URL}/api/logout`, + async route => {await route.fulfill({});} + ); } diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 905d07547..e1cffb51f 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -2,23 +2,52 @@ import { default as i18n } from 'i18next'; import { test, expect } from '@playwright/test'; import { initI18n, + setUp, logIn, logOut, assertOnlyVisibleToAuthenticated, assertOnlyVisibleToAdmin, } from './shared'; -import { mockPersonalInfo } from './mocks'; +import { SCIPER_ADMIN, SCIPER_USER, UPDATE, mockPersonalInfo } from './mocks'; initI18n(); test.beforeEach(async ({ page }) => { - await mockPersonalInfo(page); - await page.goto(`${process.env.FRONT_END_URL}/about`); + if (UPDATE === true) { + return; + } + await setUp(page, `${process.env.FRONT_END_URL}`); +}); + +// helper tests to update related HAR files + +test('Assert anonymous user HAR files are up-to-date', async({ page }) => { + // comment the next line to update HAR files + test.skip(UPDATE == false, 'Do not update HAR files'); + await mockPersonalInfo(page, ''); + await setUp(page, `${process.env.FRONT_END_URL}/about`); +}); + +test('Assert non-admin user HAR files are up-to-date', async({ page }) => { + // comment the next line to update HAR files + test.skip(UPDATE == false, 'Do not update HAR files'); + await mockPersonalInfo(page, SCIPER_USER); + await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`); + await setUp(page, `${process.env.FRONT_END_URL}/about`); +}); + +test('Assert admin user HAR files are up-to-date', async({ page }) => { + // comment the next line to update HAR files + test.skip(UPDATE == false, 'Do not update HAR files'); + await mockPersonalInfo(page, SCIPER_ADMIN); + await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`); + await setUp(page, `${process.env.FRONT_END_URL}/about`); }); // unauthenticated test('Assert D-Voting logo is present', async({ page }) => { + test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); const logo = await page.getByAltText(i18n.t('Workflow')); await expect(logo).toBeVisible(); await logo.click(); @@ -26,6 +55,7 @@ test('Assert D-Voting logo is present', async({ page }) => { }); test('Assert link to form table is present', async({ page }) => { + test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); const forms = await page.getByRole('link', { name: i18n.t('navBarStatus') }); await expect(forms).toBeVisible(); await forms.click(); @@ -35,6 +65,7 @@ test('Assert link to form table is present', async({ page }) => { // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { + test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAuthenticated( page, page.getByRole('button', { name: i18n.t('Profile') }) ); @@ -43,12 +74,14 @@ test('Assert "Profile" button is visible upon logging in', async({ page }) => { // admin test('Assert "Create form" button is (only) visible to admin', async({ page }) => { + test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarCreateForm')}) ); }); test('Assert "Admin" button is (only) visible to admin', async({ page }) => { + test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarAdmin') }) ); diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 7e8ac77c2..35a75450b 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -3,7 +3,7 @@ import { test, expect } from '@playwright/test'; import en from './../src/language/en.json'; import fr from './../src/language/fr.json'; import de from './../src/language/de.json'; -import { mockPersonalInfo, mockGetDevLogin, mockLogout } from './mocks'; +import { SCIPER_ADMIN, SCIPER_USER, mockPersonalInfo, mockGetDevLogin, mockLogout } from './mocks'; export function initI18n () { i18n.init({ @@ -12,25 +12,17 @@ export function initI18n () { }); } -export const SCIPER_ADMIN = '123456'; -export const SCIPER_USER = '789012'; +export async function setUp(page: any, url) { + await mockGetDevLogin(page); + await mockLogout(page); + await page.goto(url); + await expect(page).toHaveURL(url); // make sure that page is loaded +} export async function logIn (page: any, sciper) { - await mockGetDevLogin(page, sciper); await mockPersonalInfo(page, sciper); - // uncomment the following line to update the HAR files - await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${sciper}`); - await page.reload(); - await expect(page).toHaveURL(page.url()); // make sure that page is loaded correctly -} - -export async function logOut (page: any, sciper) { - await mockLogout(page, sciper); -// await mockPersonalInfo(page, null); - // uncomment the following line to update the HAR files - await page.context().request.post(`${process.env.FRONT_END_URL}/api/logout`); await page.reload(); - await expect(page).toHaveURL(page.url()); // make sure that page is loaded correctly + await expect(page).toHaveURL(page.url()); // make sure that page is loaded } export async function assertOnlyVisibleToAuthenticated (page: any, locator: any) { @@ -43,7 +35,6 @@ export async function assertOnlyVisibleToAdmin (page: any, locator: any) { await expect(locator).toBeHidden(); // assert is hidden to unauthenticated user await logIn(page, SCIPER_USER); await expect(locator).toBeHidden(); // assert is hidden to authenticated non-admin user - await logOut(page); await logIn(page, SCIPER_ADMIN); await expect(locator).toBeVisible(); // assert is visible to admin user } From 990cb43c24c39dd89ce3967cdec3535f38a148ac Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Thu, 7 Dec 2023 16:43:27 +0100 Subject: [PATCH 20/29] test: add authentication UI tests --- web/frontend/tests/navigation.spec.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index e1cffb51f..15015f945 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -8,7 +8,7 @@ import { assertOnlyVisibleToAuthenticated, assertOnlyVisibleToAdmin, } from './shared'; -import { SCIPER_ADMIN, SCIPER_USER, UPDATE, mockPersonalInfo } from './mocks'; +import { SCIPER_ADMIN, SCIPER_USER, UPDATE, mockPersonalInfo, mockLogout } from './mocks'; initI18n(); @@ -46,6 +46,11 @@ test('Assert admin user HAR files are up-to-date', async({ page }) => { // unauthenticated +test('Assert cookie is set', async({ page }) => { + const cookies = await page.context().cookies(); + expect(cookies.find(cookie => cookie.name === 'connect.sid')).toBeTruthy(); +}); + test('Assert D-Voting logo is present', async({ page }) => { test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); const logo = await page.getByAltText(i18n.t('Workflow')); @@ -62,6 +67,13 @@ test('Assert link to form table is present', async({ page }) => { await expect(page).toHaveURL(`${process.env.FRONT_END_URL}/form/index`); }); +test('Assert "Login" button calls login API', async({ page }) => { + const loginRequest = page.waitForRequest( + `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}` + ); + await page.getByRole('button', { name: i18n.t('login') }).click(); +}); + // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { @@ -71,6 +83,17 @@ test('Assert "Profile" button is visible upon logging in', async({ page }) => { ); }); +test('Assert "Logout" calls logout API', async({ page }) => { + await mockLogout(page); + await logIn(page, SCIPER_USER); + const logoutRequestPromise = page.waitForRequest( + request => request.url() === `${process.env.FRONT_END_URL}/api/logout` && request.method() === 'POST' + ); + for (const [role, key] of [['button', 'Profile'], ['menuitem', 'logout'], ['button', 'continue']]) { + await page.getByRole(role, { name: i18n.t(key) }).click(); + } +}); + // admin test('Assert "Create form" button is (only) visible to admin', async({ page }) => { From 75f5bdd9332ba9196eac44092d629e1b9d367c6c Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Thu, 7 Dec 2023 18:16:19 +0100 Subject: [PATCH 21/29] docs: add updating HAR files to README --- web/frontend/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/frontend/README.md b/web/frontend/README.md index 42e89b5f9..661759a0b 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -44,3 +44,13 @@ FRONT_END_URL=http://127.0.0.1:3000 npx playwright test --ui ``` this will open an user interface where you can interactively run and evaluate tests. + +## Update HAR files + +To update the HAR files, you need to make sure + +* that a complete D-Voting setup is running, as the API will be called for real, and +* the `REACT_APP_SCIPER_ADMIN` of the D-Voting instance value is set to `123456` (i.e. the `SCIPER_ADMIN` value in the mocks). + +You then change the `UPDATE = false` value in `tests/mocks.ts` to `UPDATE = true` and execute +the tests as usual. The tests that update the mocks will be run and the other tests will be skipped. From a46a0fb2e466e90bd1af577b2c077a8c5f2535b7 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 15:00:20 +0100 Subject: [PATCH 22/29] fix: apply code review suggestions --- web/frontend/README.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/web/frontend/README.md b/web/frontend/README.md index 661759a0b..5afafe5a7 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -5,7 +5,8 @@ To install Playwright run ``` -npx install playwright +npm ci +npm install playwright ``` which will install the module and its dependencies. In @@ -20,19 +21,14 @@ npx playwright install-deps --dry-run to be shown the dependencies that you need to install on your machine (requires `root` access). -You need to have the D-Voting application and DELA network running. You also need to make sure -that the environment variables from the D-Voting application are set: - -- `FRONT_END_URL` must be set to your locally running instance - -in the shell you'll be executing the tests in. +Your local frontend must be accessible at `http://127.0.0.1:3000`. ## Run tests Run ``` -FRONT_END_URL=http://127.0.0.1:3000 npx playwright test +npx playwright test ``` to run the tests. This will open a window in your browser w/ the test results. @@ -40,7 +36,7 @@ to run the tests. This will open a window in your browser w/ the test results. To run interactive tests, run ``` -FRONT_END_URL=http://127.0.0.1:3000 npx playwright test --ui +npx playwright test --ui ``` this will open an user interface where you can interactively run and evaluate tests. From a51d8a9648408fc42a3f4805c9b92dfeb0e0e466 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 15:04:10 +0100 Subject: [PATCH 23/29] test: do not test WebKit --- web/frontend/playwright.config.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/frontend/playwright.config.ts b/web/frontend/playwright.config.ts index 5b38b9975..c6a7439f1 100644 --- a/web/frontend/playwright.config.ts +++ b/web/frontend/playwright.config.ts @@ -33,11 +33,6 @@ export default defineConfig({ name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, - - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, ], }); From 9f6222bdf2414a16e8ef1ac1b8f2a04f9b9c953d Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 15:32:31 +0100 Subject: [PATCH 24/29] test: use hard-coded baseURL instead of local configuration --- web/frontend/playwright.config.ts | 2 +- web/frontend/tests/mocks.ts | 12 ++++++------ web/frontend/tests/navigation.spec.ts | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/web/frontend/playwright.config.ts b/web/frontend/playwright.config.ts index c6a7439f1..e29a0ce76 100644 --- a/web/frontend/playwright.config.ts +++ b/web/frontend/playwright.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { - + 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', }, diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index 4911ede53..1ed1a8d52 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -4,11 +4,11 @@ export const UPDATE = false; export async function mockPersonalInfo (page: any, sciper) { // clear current mock - await page.unroute(`${process.env.FRONT_END_URL}/api/personal_info`); + await page.unroute('/api/personal_info'); await page.routeFromHAR( sciper ? `./tests/hars/${sciper}/personal_info.har` : './tests/hars/anonymous/personal_info.har', { - url: `${process.env.FRONT_END_URL}/api/personal_info`, + url: '/api/personal_info', update: UPDATE, }); } @@ -17,19 +17,19 @@ export async function mockGetDevLogin (page: any) { await page.routeFromHAR( `./tests/hars/${SCIPER_ADMIN}/get_dev_login.har`, { - url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`, + url: `/api/get_dev_login/${SCIPER_ADMIN}`, update: UPDATE, }); await page.routeFromHAR( `./tests/hars/${SCIPER_USER}/get_dev_login.har`, { - url: `${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`, + url: `/api/get_dev_login/${SCIPER_USER}`, update: UPDATE, }); if (process.env.REACT_APP_SCIPER_ADMIN !== undefined && process.env.REACT_APP_SCIPER_ADMIN !== SCIPER_ADMIN) { // dummy route for "Login" button depending on local configuration await page.route( - `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}`, + `/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}`, async route => {await route.fulfill({});} ); } @@ -37,7 +37,7 @@ export async function mockGetDevLogin (page: any) { export async function mockLogout (page: any) { await page.route( - `${process.env.FRONT_END_URL}/api/logout`, + '/api/logout', async route => {await route.fulfill({});} ); } diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 15015f945..ec72fd99c 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -16,7 +16,7 @@ test.beforeEach(async ({ page }) => { if (UPDATE === true) { return; } - await setUp(page, `${process.env.FRONT_END_URL}`); + await setUp(page, '/about'); }); // helper tests to update related HAR files @@ -25,23 +25,23 @@ test('Assert anonymous user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files test.skip(UPDATE == false, 'Do not update HAR files'); await mockPersonalInfo(page, ''); - await setUp(page, `${process.env.FRONT_END_URL}/about`); + await setUp(page, '/about'); }); test('Assert non-admin user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files test.skip(UPDATE == false, 'Do not update HAR files'); await mockPersonalInfo(page, SCIPER_USER); - await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_USER}`); - await setUp(page, `${process.env.FRONT_END_URL}/about`); + await page.context().request.get(`/api/get_dev_login/${SCIPER_USER}`); + await setUp(page, '/about'); }); test('Assert admin user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files test.skip(UPDATE == false, 'Do not update HAR files'); await mockPersonalInfo(page, SCIPER_ADMIN); - await page.context().request.get(`${process.env.FRONT_END_URL}/api/get_dev_login/${SCIPER_ADMIN}`); - await setUp(page, `${process.env.FRONT_END_URL}/about`); + await page.context().request.get(`/api/get_dev_login/${SCIPER_ADMIN}`); + await setUp(page, '/about'); }); // unauthenticated @@ -56,7 +56,7 @@ test('Assert D-Voting logo is present', async({ page }) => { const logo = await page.getByAltText(i18n.t('Workflow')); await expect(logo).toBeVisible(); await logo.click(); - await expect(page).toHaveURL(process.env.FRONT_END_URL); + await expect(page).toHaveURL('/'); }); test('Assert link to form table is present', async({ page }) => { @@ -64,12 +64,12 @@ test('Assert link to form table is present', async({ page }) => { const forms = await page.getByRole('link', { name: i18n.t('navBarStatus') }); await expect(forms).toBeVisible(); await forms.click(); - await expect(page).toHaveURL(`${process.env.FRONT_END_URL}/form/index`); + await expect(page).toHaveURL('/form/index'); }); test('Assert "Login" button calls login API', async({ page }) => { const loginRequest = page.waitForRequest( - `${process.env.FRONT_END_URL}/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}` + `/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}` ); await page.getByRole('button', { name: i18n.t('login') }).click(); }); @@ -83,11 +83,11 @@ test('Assert "Profile" button is visible upon logging in', async({ page }) => { ); }); -test('Assert "Logout" calls logout API', async({ page }) => { +test('Assert "Logout" calls logout API', async({ page, baseURL }) => { await mockLogout(page); await logIn(page, SCIPER_USER); const logoutRequestPromise = page.waitForRequest( - request => request.url() === `${process.env.FRONT_END_URL}/api/logout` && request.method() === 'POST' + request => request.url() === `${baseURL}/api/logout` && request.method() === 'POST' ); for (const [role, key] of [['button', 'Profile'], ['menuitem', 'logout'], ['button', 'continue']]) { await page.getByRole(role, { name: i18n.t(key) }).click(); From a7fe8fb7cd1c745f52428d67e3d5092af1dd3c46 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 15:51:41 +0100 Subject: [PATCH 25/29] test: apply review suggestions --- web/frontend/tests/mocks.ts | 4 ++-- web/frontend/tests/navigation.spec.ts | 18 +++++++++--------- web/frontend/tests/shared.ts | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/web/frontend/tests/mocks.ts b/web/frontend/tests/mocks.ts index 1ed1a8d52..fdbef3b07 100644 --- a/web/frontend/tests/mocks.ts +++ b/web/frontend/tests/mocks.ts @@ -2,11 +2,11 @@ export const SCIPER_ADMIN = '123456'; export const SCIPER_USER = '789012'; export const UPDATE = false; -export async function mockPersonalInfo (page: any, sciper) { +export async function mockPersonalInfo (page: any, sciper?: string) { // clear current mock await page.unroute('/api/personal_info'); await page.routeFromHAR( - sciper ? `./tests/hars/${sciper}/personal_info.har` : './tests/hars/anonymous/personal_info.har', + `./tests/hars/${sciper ?? 'anonymous'}/personal_info.har`, { url: '/api/personal_info', update: UPDATE, diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index ec72fd99c..3c0179584 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -23,14 +23,14 @@ test.beforeEach(async ({ page }) => { test('Assert anonymous user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files - test.skip(UPDATE == false, 'Do not update HAR files'); - await mockPersonalInfo(page, ''); + test.skip(UPDATE === false, 'Do not update HAR files'); + await mockPersonalInfo(page); await setUp(page, '/about'); }); test('Assert non-admin user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files - test.skip(UPDATE == false, 'Do not update HAR files'); + test.skip(UPDATE === false, 'Do not update HAR files'); await mockPersonalInfo(page, SCIPER_USER); await page.context().request.get(`/api/get_dev_login/${SCIPER_USER}`); await setUp(page, '/about'); @@ -38,7 +38,7 @@ test('Assert non-admin user HAR files are up-to-date', async({ page }) => { test('Assert admin user HAR files are up-to-date', async({ page }) => { // comment the next line to update HAR files - test.skip(UPDATE == false, 'Do not update HAR files'); + test.skip(UPDATE === false, 'Do not update HAR files'); await mockPersonalInfo(page, SCIPER_ADMIN); await page.context().request.get(`/api/get_dev_login/${SCIPER_ADMIN}`); await setUp(page, '/about'); @@ -52,7 +52,7 @@ test('Assert cookie is set', async({ page }) => { }); test('Assert D-Voting logo is present', async({ page }) => { - test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); + test.skip(UPDATE === true, 'Do not run regular tests when updating HAR files'); const logo = await page.getByAltText(i18n.t('Workflow')); await expect(logo).toBeVisible(); await logo.click(); @@ -60,7 +60,7 @@ test('Assert D-Voting logo is present', async({ page }) => { }); test('Assert link to form table is present', async({ page }) => { - test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); + test.skip(UPDATE === true, 'Do not run regular tests when updating HAR files'); const forms = await page.getByRole('link', { name: i18n.t('navBarStatus') }); await expect(forms).toBeVisible(); await forms.click(); @@ -77,7 +77,7 @@ test('Assert "Login" button calls login API', async({ page }) => { // authenticated non-admin test('Assert "Profile" button is visible upon logging in', async({ page }) => { - test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); + test.skip(UPDATE === true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAuthenticated( page, page.getByRole('button', { name: i18n.t('Profile') }) ); @@ -97,14 +97,14 @@ test('Assert "Logout" calls logout API', async({ page, baseURL }) => { // admin test('Assert "Create form" button is (only) visible to admin', async({ page }) => { - test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); + test.skip(UPDATE === true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarCreateForm')}) ); }); test('Assert "Admin" button is (only) visible to admin', async({ page }) => { - test.skip(UPDATE == true, 'Do not run regular tests when updating HAR files'); + test.skip(UPDATE === true, 'Do not run regular tests when updating HAR files'); await assertOnlyVisibleToAdmin( page, page.getByRole('link', { name: i18n.t('navBarAdmin') }) ); diff --git a/web/frontend/tests/shared.ts b/web/frontend/tests/shared.ts index 35a75450b..d33f532c1 100644 --- a/web/frontend/tests/shared.ts +++ b/web/frontend/tests/shared.ts @@ -12,14 +12,14 @@ export function initI18n () { }); } -export async function setUp(page: any, url) { +export async function setUp(page: any, url: string) { await mockGetDevLogin(page); await mockLogout(page); await page.goto(url); await expect(page).toHaveURL(url); // make sure that page is loaded } -export async function logIn (page: any, sciper) { +export async function logIn (page: any, sciper: string) { await mockPersonalInfo(page, sciper); await page.reload(); await expect(page).toHaveURL(page.url()); // make sure that page is loaded From bc582d399ef02a54c99fcb2a6323d2b70f2bc101 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 15:54:29 +0100 Subject: [PATCH 26/29] fix: re-add accidentally removed mockPersonalInfo in setUp function --- web/frontend/tests/navigation.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index 3c0179584..c3fdca67d 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -16,6 +16,7 @@ test.beforeEach(async ({ page }) => { if (UPDATE === true) { return; } + await mockPersonalInfo(page); await setUp(page, '/about'); }); From b251113b372f30a14f903b4e684a7e988a0fd394 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 16:50:37 +0100 Subject: [PATCH 27/29] fix: use regexp for local configuration --- web/frontend/tests/navigation.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/tests/navigation.spec.ts b/web/frontend/tests/navigation.spec.ts index c3fdca67d..06d96a527 100644 --- a/web/frontend/tests/navigation.spec.ts +++ b/web/frontend/tests/navigation.spec.ts @@ -70,7 +70,7 @@ test('Assert link to form table is present', async({ page }) => { test('Assert "Login" button calls login API', async({ page }) => { const loginRequest = page.waitForRequest( - `/api/get_dev_login/${process.env.REACT_APP_SCIPER_ADMIN}` + new RegExp("/api/get_dev_login/[0-9]{6}") ); await page.getByRole('button', { name: i18n.t('login') }).click(); }); From 707f2d67c74b3bca0f2e5f6c8a019bb263f361e7 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 16:52:17 +0100 Subject: [PATCH 28/29] docs: fix npm command in README --- web/frontend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/README.md b/web/frontend/README.md index 5afafe5a7..9938ba88a 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -6,7 +6,7 @@ To install Playwright run ``` npm ci -npm install playwright +npm playwright install ``` which will install the module and its dependencies. In From e9b84b74c1113d885d0ca16161628d98aff8ec20 Mon Sep 17 00:00:00 2001 From: Carine Dengler Date: Fri, 8 Dec 2023 16:58:31 +0100 Subject: [PATCH 29/29] docs: fix npx command --- web/frontend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/README.md b/web/frontend/README.md index 9938ba88a..6625e1319 100644 --- a/web/frontend/README.md +++ b/web/frontend/README.md @@ -6,7 +6,7 @@ To install Playwright run ``` npm ci -npm playwright install +npx playwright install ``` which will install the module and its dependencies. In