diff --git a/package-lock.json b/package-lock.json index 2cb72b3c..ed1a3a52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9620,6 +9620,23 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@playwright/test": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "playwright": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@pnpm/config.env-replace": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", @@ -24504,12 +24521,13 @@ } }, "node_modules/playwright": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", - "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", - "dev": true, + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.56.1" + "playwright-core": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -24522,10 +24540,11 @@ } }, "node_modules/playwright-core": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", - "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", - "dev": true, + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "devOptional": true, + "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -29505,6 +29524,7 @@ "web-haptics": "^0.0.6" }, "devDependencies": { + "@playwright/test": "^1.59.1", "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", diff --git a/src/webapp/.gitignore b/src/webapp/.gitignore new file mode 100644 index 00000000..335bd46d --- /dev/null +++ b/src/webapp/.gitignore @@ -0,0 +1,8 @@ + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ diff --git a/src/webapp/e2e/auth-redirect.spec.ts b/src/webapp/e2e/auth-redirect.spec.ts new file mode 100644 index 00000000..56576c35 --- /dev/null +++ b/src/webapp/e2e/auth-redirect.spec.ts @@ -0,0 +1,26 @@ +import { test, expect } from '@playwright/test'; + +test('unauthenticated /settings visit redirects to /login', async ({ + page, +}) => { + const response = await page.goto('/settings'); + console.log('status:', response?.status(), 'final url:', page.url()); + + await expect(page).toHaveURL('/login'); +}); + +test('unauthenticated /notifications visit redirects to /login', async ({ + page, +}) => { + const response = await page.goto('/notifications'); + console.log('status:', response?.status(), 'final url:', page.url()); + + await expect(page).toHaveURL('/login'); +}); + +test('unauthenticated /home visit redirects to /login', async ({ page }) => { + const response = await page.goto('/home'); + console.log('status:', response?.status(), 'final url:', page.url()); + + await expect(page).toHaveURL('/login'); +}); diff --git a/src/webapp/e2e/example.spec.ts b/src/webapp/e2e/example.spec.ts new file mode 100644 index 00000000..f71a6759 --- /dev/null +++ b/src/webapp/e2e/example.spec.ts @@ -0,0 +1,20 @@ +import { test, expect } from '@playwright/test'; + +test('has title', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Expect a title "to contain" a substring. + await expect(page).toHaveTitle(/Playwright/); +}); + +test('get started link', async ({ page }) => { + await page.goto('https://playwright.dev/'); + + // Click the get started link. + await page.getByRole('link', { name: 'Get started' }).click(); + + // Expects page to have a heading with the name of Installation. + await expect( + page.getByRole('heading', { name: 'Installation' }), + ).toBeVisible(); +}); diff --git a/src/webapp/next-env.d.ts b/src/webapp/next-env.d.ts index 9edff1c7..c4b7818f 100644 --- a/src/webapp/next-env.d.ts +++ b/src/webapp/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/webapp/package.json b/src/webapp/package.json index c0a2a750..63369623 100644 --- a/src/webapp/package.json +++ b/src/webapp/package.json @@ -55,6 +55,7 @@ "web-haptics": "^0.0.6" }, "devDependencies": { + "@playwright/test": "^1.59.1", "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", diff --git a/src/webapp/playwright.config.ts b/src/webapp/playwright.config.ts new file mode 100644 index 00000000..0275b42d --- /dev/null +++ b/src/webapp/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e', + /* 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: process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:4000/', + + /* 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://localhost:3000', + // reuseExistingServer: !process.env.CI, + // }, +});