From d7cbe2f54393dd17fbcf925c75bc3a81fed68ae5 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 18:06:16 +0000 Subject: [PATCH 1/7] initial commit --- integration_tests/.gitignore | 5 ++ integration_tests/package-lock.json | 97 +++++++++++++++++++++++++ integration_tests/package.json | 14 ++++ integration_tests/playwright.config.ts | 79 ++++++++++++++++++++ integration_tests/tests/example.spec.ts | 18 +++++ 5 files changed, 213 insertions(+) create mode 100644 integration_tests/.gitignore create mode 100644 integration_tests/package-lock.json create mode 100644 integration_tests/package.json create mode 100644 integration_tests/playwright.config.ts create mode 100644 integration_tests/tests/example.spec.ts diff --git a/integration_tests/.gitignore b/integration_tests/.gitignore new file mode 100644 index 000000000..68c5d18f0 --- /dev/null +++ b/integration_tests/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/integration_tests/package-lock.json b/integration_tests/package-lock.json new file mode 100644 index 000000000..7832efe82 --- /dev/null +++ b/integration_tests/package-lock.json @@ -0,0 +1,97 @@ +{ + "name": "integration_tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "integration_tests", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.8.3" + } + }, + "node_modules/@playwright/test": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.2.tgz", + "integrity": "sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "22.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.3.tgz", + "integrity": "sha512-ZlijaZM38In/raEdZoNKKfIVJEA+4NTsvhGQTgQt4y2/Zgokyz4NUvOch108O3Q1q5lJ170h1hShfPfRPW7BwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.2.tgz", + "integrity": "sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.48.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.48.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.2.tgz", + "integrity": "sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/integration_tests/package.json b/integration_tests/package.json new file mode 100644 index 000000000..2fbbcdaf3 --- /dev/null +++ b/integration_tests/package.json @@ -0,0 +1,14 @@ +{ + "name": "integration_tests", + "version": "1.0.0", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "@playwright/test": "^1.48.2", + "@types/node": "^22.8.3" + } +} diff --git a/integration_tests/playwright.config.ts b/integration_tests/playwright.config.ts new file mode 100644 index 000000000..a05d8b5a1 --- /dev/null +++ b/integration_tests/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: './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, + // }, +}); diff --git a/integration_tests/tests/example.spec.ts b/integration_tests/tests/example.spec.ts new file mode 100644 index 000000000..54a906a4e --- /dev/null +++ b/integration_tests/tests/example.spec.ts @@ -0,0 +1,18 @@ +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(); +}); From 786bf7f0e7a87640367cd6739995a664a13a4ac4 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 22:04:35 +0000 Subject: [PATCH 2/7] initial 2 --- .github/workflows/integration-tests.yml | 114 ++++++++++++++++++ deploy.py | 1 + .../.gitignore | 0 .../package-lock.json | 25 +++- .../package.json | 4 +- .../playwright.config.ts | 0 integration-tests/run.sh | 5 + integration-tests/tests/config/test.config.ts | 13 ++ .../tests/fixtures/auth.fixture.ts | 40 ++++++ integration-tests/tests/pages/auth.page.ts | 57 +++++++++ .../tests/specs/auth/login.spec.ts | 20 +++ .../tests/specs/auth/registration.spec.ts | 16 +++ .../specs/features/authenticated.spec.ts | 8 ++ integration-tests/tests/types/auth.types.ts | 8 ++ integration-tests/tests/utils/test-helpers.ts | 13 ++ integration_tests/tests/example.spec.ts | 18 --- 16 files changed, 322 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/integration-tests.yml rename {integration_tests => integration-tests}/.gitignore (100%) rename {integration_tests => integration-tests}/package-lock.json (77%) rename {integration_tests => integration-tests}/package.json (73%) rename {integration_tests => integration-tests}/playwright.config.ts (100%) create mode 100644 integration-tests/run.sh create mode 100644 integration-tests/tests/config/test.config.ts create mode 100644 integration-tests/tests/fixtures/auth.fixture.ts create mode 100644 integration-tests/tests/pages/auth.page.ts create mode 100644 integration-tests/tests/specs/auth/login.spec.ts create mode 100644 integration-tests/tests/specs/auth/registration.spec.ts create mode 100644 integration-tests/tests/specs/features/authenticated.spec.ts create mode 100644 integration-tests/tests/types/auth.types.ts create mode 100644 integration-tests/tests/utils/test-helpers.ts delete mode 100644 integration_tests/tests/example.spec.ts diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 000000000..5923d58b8 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,114 @@ +name: E2E test (on kubernetes) +on: + workflow_dispatch: + pull_request: + paths: + - "backend/**" + - "keycloak/**" + - "kubernetes/**" + - "website/**" + - "deploy.py" + - "integration-tests/**" + - ".github/scripts/**" + - ".github/workflows/**" + push: + branches: + - main +jobs: + integration-tests: + permissions: + packages: read + contents: read + checks: read + actions: read # Required by workflow-telemetry-action + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + sha: ${{ github.event.pull_request.head.sha || github.sha }} + steps: + - name: Shorten sha + run: echo "sha=${sha::7}" >> $GITHUB_ENV + - name: Collect Workflow Telemetry + uses: catchpoint/workflow-telemetry-action@v2 + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install k3d + run: | + curl -s https://raw.githubusercontent.com/rancher/k3d/main/install.sh | bash + k3d version + - uses: azure/setup-helm@v4 + - name: Create k3d cluster + run: | + ./deploy.py --verbose cluster + - name: Deploy with helm + run: | + ./deploy.py --verbose helm --branch ${{ github.ref_name }} --sha ${{ env.sha }} --for-e2e + - uses: actions/setup-node@v4 + with: + node-version-file: ./website/.nvmrc + - name: Cache .npm + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('integration-tests/**/package-lock.json') }} + - name: Install dependencies + run: cd integration-tests && npm i + - name: Get Installed Playwright Version + id: playwright-version + run: cd integration-tests && echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').packages['node_modules/@playwright/test'].version)")" >> $GITHUB_ENV + - name: Cache Playwright Browsers + uses: actions/cache@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + - name: Install Playwright Browsers and System Dependencies + run: cd integration-tests && npx playwright install --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' + - name: Install only System Dependencies + run: cd website && npx playwright install-deps + if: steps.playwright-cache.outputs.cache-hit == 'true' + - name: Wait for the pods to be ready + run: ./.github/scripts/wait_for_pods_to_be_ready.py --timeout ${{ env.wait_timeout }} + - name: Sleep for 10 secs + run: sleep 10 + - name: Run E2E test + run: | + set -o pipefail + cd website && npx playwright test 2>&1 | tee output.txt + EXIT_CODE=$? + echo '```' >> $GITHUB_STEP_SUMMARY + sed -n '/Running [0-9]\+ tests/,$p' output.txt >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + exit $EXIT_CODE + - uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: playwright-report + path: website/playwright-report/ + retention-days: 30 + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: website/test-results/ + retention-days: 30 + - name: List running pods + if: ${{ !cancelled() }} + run: kubectl get pods --all-namespaces + - name: Describe pods + if: ${{ !cancelled() }} + run: kubectl describe pods -l app=loculus + - name: Show events + if: ${{ !cancelled() }} + run: kubectl get events + - name: Save logs from all containers to file + if: ${{ !cancelled() }} + run: ./.github/scripts/collect_kubernetes_logs.sh + - name: Upload Kubernetes logs + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: kubernetes-logs + path: kubernetes_logs/ diff --git a/deploy.py b/deploy.py index 2cb83330b..ad981135e 100755 --- a/deploy.py +++ b/deploy.py @@ -217,6 +217,7 @@ def handle_helm(): if args.for_e2e or args.dev: parameters += ["-f", HELM_CHART_DIR / "values_e2e_and_dev.yaml"] + parameters += ["--set", "auth.verifyEmail=false"] if args.sha: parameters += ["--set", f"sha={args.sha[:7]}"] diff --git a/integration_tests/.gitignore b/integration-tests/.gitignore similarity index 100% rename from integration_tests/.gitignore rename to integration-tests/.gitignore diff --git a/integration_tests/package-lock.json b/integration-tests/package-lock.json similarity index 77% rename from integration_tests/package-lock.json rename to integration-tests/package-lock.json index 7832efe82..acf204194 100644 --- a/integration_tests/package-lock.json +++ b/integration-tests/package-lock.json @@ -10,7 +10,9 @@ "license": "ISC", "devDependencies": { "@playwright/test": "^1.48.2", - "@types/node": "^22.8.3" + "@types/node": "^22.8.3", + "@types/uuid": "^10.0.0", + "uuid": "^11.0.2" } }, "node_modules/@playwright/test": { @@ -39,6 +41,13 @@ "undici-types": "~6.19.8" } }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -92,6 +101,20 @@ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" + }, + "node_modules/uuid": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } } } } diff --git a/integration_tests/package.json b/integration-tests/package.json similarity index 73% rename from integration_tests/package.json rename to integration-tests/package.json index 2fbbcdaf3..024eacd8e 100644 --- a/integration_tests/package.json +++ b/integration-tests/package.json @@ -9,6 +9,8 @@ "description": "", "devDependencies": { "@playwright/test": "^1.48.2", - "@types/node": "^22.8.3" + "@types/node": "^22.8.3", + "@types/uuid": "^10.0.0", + "uuid": "^11.0.2" } } diff --git a/integration_tests/playwright.config.ts b/integration-tests/playwright.config.ts similarity index 100% rename from integration_tests/playwright.config.ts rename to integration-tests/playwright.config.ts diff --git a/integration-tests/run.sh b/integration-tests/run.sh new file mode 100644 index 000000000..6140538f6 --- /dev/null +++ b/integration-tests/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash + ../deploy.py cluster --delete + ../deploy.py cluster + ../deploy.py helm --for-e2e + python ../.github/scripts/wait_for_pods_to_be_ready.py \ No newline at end of file diff --git a/integration-tests/tests/config/test.config.ts b/integration-tests/tests/config/test.config.ts new file mode 100644 index 000000000..0ac303c59 --- /dev/null +++ b/integration-tests/tests/config/test.config.ts @@ -0,0 +1,13 @@ +import { PlaywrightTestConfig } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + testDir: '../specs', + use: { + baseURL: 'http://localhost:3000', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + }, + reporter: [['html'], ['list']], +}; + +export default config; diff --git a/integration-tests/tests/fixtures/auth.fixture.ts b/integration-tests/tests/fixtures/auth.fixture.ts new file mode 100644 index 000000000..f86d76d56 --- /dev/null +++ b/integration-tests/tests/fixtures/auth.fixture.ts @@ -0,0 +1,40 @@ +import { test as base, Page } from '@playwright/test'; +import { v4 as uuidv4 } from 'uuid'; +import { AuthPage } from '../pages/auth.page'; +import { TestAccount } from '../types/auth.types'; + +type TestFixtures = { + authenticatedPage: Page; + testAccount: TestAccount; +}; + +export const test = base.extend({ + authenticatedPage: async ({ page }, use) => { + const authPage = new AuthPage(page); + + const testAccount = { + username: `test_user_${uuidv4().slice(0, 8)}`, + password: 'password', + email: `test_${uuidv4().slice(0, 8)}@test.com`, + firstName: 'Test', + lastName: 'User', + organization: 'Test University' + }; + + await authPage.createAccount(testAccount); + await use(page); + await authPage.logout(); + }, + + testAccount: async ({}, use) => { + const testAccount = { + username: `test_user_${uuidv4().slice(0, 8)}`, + password: 'password', + email: `test_${uuidv4().slice(0, 8)}@test.com`, + firstName: 'Test', + lastName: 'User', + organization: 'Test University' + }; + await use(testAccount); + }, +}); diff --git a/integration-tests/tests/pages/auth.page.ts b/integration-tests/tests/pages/auth.page.ts new file mode 100644 index 000000000..a78e2c333 --- /dev/null +++ b/integration-tests/tests/pages/auth.page.ts @@ -0,0 +1,57 @@ +import { Page } from '@playwright/test'; +import { TestAccount } from '../types/auth.types'; + +export class AuthPage { + constructor(private page: Page) {} + + async navigateToRegister() { + await this.page.goto('http://localhost:3000/'); + await this.page.getByRole('link', { name: 'Login' }).click(); + await this.page.getByRole('link', { name: 'Register' }).click(); + } + + async createAccount(account: TestAccount) { + await this.navigateToRegister(); + + await this.page.getByLabel('Username').click(); + await this.page.getByLabel('Username').fill(account.username); + await this.page.getByLabel('Username').press('Tab'); + + await this.page.getByLabel('Password', { exact: true }).fill(account.password); + await this.page.getByLabel('Password', { exact: true }).press('Tab'); + + await this.page.getByLabel('Confirm password').fill(account.password); + await this.page.getByLabel('Confirm password').press('Tab'); + + await this.page.getByLabel('Email').fill(account.email); + await this.page.getByLabel('Email').press('Tab'); + + await this.page.getByLabel('First name').fill(account.firstName); + await this.page.getByLabel('First name').press('Tab'); + + await this.page.getByLabel('Last name').fill(account.lastName); + await this.page.getByLabel('Last name').press('Tab'); + + await this.page.getByLabel('University / Organisation').fill(account.organization); + + await this.page.getByLabel('I agree').check(); + await this.page.getByRole('button', { name: 'Register' }).click(); + } + + async login(username: string, password: string) { + await this.page.goto('http://localhost:3000/'); + await this.page.getByRole('link', { name: 'Login' }).click(); + await this.page.getByLabel('Username').fill(username); + await this.page.getByLabel('Password', { exact: true }).fill(password); + await this.page.getByRole('button', { name: 'Sign in' }).click(); + await this.page.waitForSelector('text=Welcome to Loculus', { state: 'attached' }); + } + + async logout() { + await this.page.goto('http://localhost:3000/'); + await this.page.getByRole('link', { name: 'My account' }).click(); + await this.page.getByRole('link', { name: 'Logout' }).click(); + await this.page.getByRole('button', { name: 'Logout' }).click(); + + } +} diff --git a/integration-tests/tests/specs/auth/login.spec.ts b/integration-tests/tests/specs/auth/login.spec.ts new file mode 100644 index 000000000..a6ed40539 --- /dev/null +++ b/integration-tests/tests/specs/auth/login.spec.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; +import { test } from '../../fixtures/auth.fixture'; +import { AuthPage } from '../../pages/auth.page'; + +test.describe('Login Flow', () => { + let authPage: AuthPage; + + test.beforeEach(async ({ page }) => { + authPage = new AuthPage(page); + }); + + test('should login with valid credentials', async ({ page, testAccount }) => { + await authPage.createAccount(testAccount); + await page.waitForTimeout(1000); + await authPage.logout(); + await page.waitForTimeout(1000); + await authPage.login(testAccount.username, testAccount.password); + + }); +}); diff --git a/integration-tests/tests/specs/auth/registration.spec.ts b/integration-tests/tests/specs/auth/registration.spec.ts new file mode 100644 index 000000000..d78db7c2a --- /dev/null +++ b/integration-tests/tests/specs/auth/registration.spec.ts @@ -0,0 +1,16 @@ +import { expect } from '@playwright/test'; +import { test } from '../../fixtures/auth.fixture'; +import { AuthPage } from '../../pages/auth.page'; + +test.describe('Registration Flow', () => { + let authPage: AuthPage; + + test.beforeEach(async ({ page }) => { + authPage = new AuthPage(page); + }); + + test('should successfully register a new user', async ({ page, testAccount }) => { + await authPage.createAccount(testAccount); + // Add your assertions here + }); +}); diff --git a/integration-tests/tests/specs/features/authenticated.spec.ts b/integration-tests/tests/specs/features/authenticated.spec.ts new file mode 100644 index 000000000..54570f158 --- /dev/null +++ b/integration-tests/tests/specs/features/authenticated.spec.ts @@ -0,0 +1,8 @@ +import { expect } from '@playwright/test'; +import { test } from '../../fixtures/auth.fixture'; + +test.describe('Authenticated Features', () => { + test('authenticated user can access protected features', async ({ authenticatedPage }) => { + + }); +}); diff --git a/integration-tests/tests/types/auth.types.ts b/integration-tests/tests/types/auth.types.ts new file mode 100644 index 000000000..14174d7b3 --- /dev/null +++ b/integration-tests/tests/types/auth.types.ts @@ -0,0 +1,8 @@ +export type TestAccount = { + username: string; + password: string; + email: string; + firstName: string; + lastName: string; + organization: string; +}; diff --git a/integration-tests/tests/utils/test-helpers.ts b/integration-tests/tests/utils/test-helpers.ts new file mode 100644 index 000000000..90524f7c5 --- /dev/null +++ b/integration-tests/tests/utils/test-helpers.ts @@ -0,0 +1,13 @@ +import { v4 as uuidv4 } from 'uuid'; +import { TestAccount } from '../types/auth.types'; + +export function generateTestAccount(prefix = 'test'): TestAccount { + return { + username: `${prefix}_user_${uuidv4().slice(0, 8)}`, + password: 'password', + email: `${prefix}_${uuidv4().slice(0, 8)}@test.com`, + firstName: `${prefix.charAt(0).toUpperCase()}${prefix.slice(1)}`, + lastName: 'User', + organization: 'Test University' + }; +} diff --git a/integration_tests/tests/example.spec.ts b/integration_tests/tests/example.spec.ts deleted file mode 100644 index 54a906a4e..000000000 --- a/integration_tests/tests/example.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -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(); -}); From 8771ddf4593e6722241548ee1d2a2cca6fd76341 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 22:19:00 +0000 Subject: [PATCH 3/7] Update integration-tests.yml --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 5923d58b8..e4044d753 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1,4 +1,4 @@ -name: E2E test (on kubernetes) +name: Integration tests on: workflow_dispatch: pull_request: From 8cddffe26e8ac78b8872be365ff5307102bcf756 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 22:26:11 +0000 Subject: [PATCH 4/7] Update integration-tests.yml --- .github/workflows/integration-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index e4044d753..d91f1a4f8 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -69,7 +69,7 @@ jobs: run: cd website && npx playwright install-deps if: steps.playwright-cache.outputs.cache-hit == 'true' - name: Wait for the pods to be ready - run: ./.github/scripts/wait_for_pods_to_be_ready.py --timeout ${{ env.wait_timeout }} + run: ./.github/scripts/wait_for_pods_to_be_ready.py --timeout 120 - name: Sleep for 10 secs run: sleep 10 - name: Run E2E test From 9b3c79dc4323d43aecd331b09e47e3f03922dea3 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 22:49:36 +0000 Subject: [PATCH 5/7] update --- .github/workflows/integration-tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d91f1a4f8..92e9f1520 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -72,10 +72,10 @@ jobs: run: ./.github/scripts/wait_for_pods_to_be_ready.py --timeout 120 - name: Sleep for 10 secs run: sleep 10 - - name: Run E2E test + - name: Run Integration test run: | set -o pipefail - cd website && npx playwright test 2>&1 | tee output.txt + cd integration-tests && npx playwright test 2>&1 | tee output.txt EXIT_CODE=$? echo '```' >> $GITHUB_STEP_SUMMARY sed -n '/Running [0-9]\+ tests/,$p' output.txt >> $GITHUB_STEP_SUMMARY @@ -85,14 +85,14 @@ jobs: if: ${{ failure() }} with: name: playwright-report - path: website/playwright-report/ + path: integration-tests/playwright-report/ retention-days: 30 - name: Upload Test Results if: always() uses: actions/upload-artifact@v4 with: name: test-results - path: website/test-results/ + path: integration-tests/test-results/ retention-days: 30 - name: List running pods if: ${{ !cancelled() }} From 0b1df84637ce1bd1ec6163f30b95617bd90fbc9c Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Tue, 29 Oct 2024 23:14:59 +0000 Subject: [PATCH 6/7] disable webkit for now --- integration-tests/playwright.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration-tests/playwright.config.ts b/integration-tests/playwright.config.ts index a05d8b5a1..126be09d5 100644 --- a/integration-tests/playwright.config.ts +++ b/integration-tests/playwright.config.ts @@ -43,11 +43,12 @@ export default defineConfig({ name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, - +/* { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, + */ /* Test against mobile viewports. */ // { From 435030933ad001dc03bab7fc647eed01e36ae076 Mon Sep 17 00:00:00 2001 From: Theo Sanderson Date: Wed, 30 Oct 2024 14:21:00 +0000 Subject: [PATCH 7/7] add principles --- integration-tests/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 integration-tests/README.md diff --git a/integration-tests/README.md b/integration-tests/README.md new file mode 100644 index 000000000..0abfad7c8 --- /dev/null +++ b/integration-tests/README.md @@ -0,0 +1,9 @@ +# Integration tests + +These are tests of the full Loculus system, following sequences through submission to preprocessing to release. + +## Principles + +Here are some current guiding principles for these tests: +- Only use facilities users could use (primarily browser interaction), rather than setting things up with backend calls. This makes it easy for others to understand the tests because they can follow them in the browser. +- All tests should be able to run in parallel. Mostly this can be carried out by creating a separate user/group for each test. \ No newline at end of file