From 4772861262ec15206739959191e402f3a47315b9 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 09:53:30 +0200 Subject: [PATCH 01/40] use postgres --- acceptance/docker-compose.yaml | 25 ++++++++++++++----------- acceptance/machinekey/.kitkeep | 0 acceptance/zitadel.yaml | 18 +++++++++++++++++- 3 files changed, 31 insertions(+), 12 deletions(-) delete mode 100644 acceptance/machinekey/.kitkeep diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index ac2fa512..b39a3a4f 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -1,5 +1,3 @@ -version: "3.8" - services: zitadel: user: "${ZITADEL_DEV_UID}" @@ -15,17 +13,22 @@ services: condition: "service_healthy" db: - image: "cockroachdb/cockroach:v22.2.2" - command: "start-single-node --insecure --http-addr :9090" + restart: 'always' + image: 'postgres:latest' + environment: + - POSTGRES_USER=zitadel + - PGUSER=zitadel + - POSTGRES_DB=zitadel + - POSTGRES_HOST_AUTH_METHOD=trust + command: postgres -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c shared_buffers=1GB -c work_mem=16MB -c effective_io_concurrency=100 -c wal_level=minimal -c archive_mode=off -c max_wal_senders=0 healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9090/health?ready=1"] - interval: "10s" - timeout: "30s" + test: ["CMD-SHELL", "pg_isready"] + interval: '10s' + timeout: '30s' retries: 5 - start_period: "20s" + start_period: '20s' ports: - - "26257:26257" - - "9090:9090" + - 5432:5432 wait_for_zitadel: image: curlimages/curl:8.00.1 @@ -33,7 +36,7 @@ services: [ "/bin/sh", "-c", - "i=0; while ! curl http://zitadel:8080/debug/ready && [ $$i -lt 30 ]; do sleep 1; i=$$((i+1)); done; [ $$i -eq 30 ] && exit 1 || exit 0", + "i=0; while ! curl http://zitadel:8080/debug/ready && [ $$i -lt 30 ]; do sleep 1; i=$$((i+1)); done; [ $$i -eq 120 ] && exit 1 || exit 0", ] depends_on: - zitadel diff --git a/acceptance/machinekey/.kitkeep b/acceptance/machinekey/.kitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/acceptance/zitadel.yaml b/acceptance/zitadel.yaml index 2b471db0..07a79bbb 100644 --- a/acceptance/zitadel.yaml +++ b/acceptance/zitadel.yaml @@ -9,8 +9,24 @@ FirstInstance: Type: 1 Database: - Cockroach: + EventPushConnRatio: 0.2 # 4 + ProjectionSpoolerConnRatio: 0.3 # 6 + postgres: Host: db + Port: 5432 + Database: zitadel + MaxOpenConns: 20 + MaxIdleConns: 20 + MaxConnLifetime: 1h + MaxConnIdleTime: 5m + User: + Username: zitadel + SSL: + Mode: disable + Admin: + Username: zitadel + SSL: + Mode: disable Logstore: Access: From 73a385c653bb91aa56272ef2f00629434fb6b4e4 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 12:23:38 +0200 Subject: [PATCH 02/40] setup playwright --- .github/workflows/playwright.yml | 27 ++ .gitignore | 4 + acceptance/setup.sh | 2 +- acceptance/tests/example.spec.ts | 7 + package.json | 4 +- playwright.config.ts | 79 +++++ pnpm-lock.yaml | 107 +++++-- tests-examples/demo-todo-app.spec.ts | 437 +++++++++++++++++++++++++++ 8 files changed, 636 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/playwright.yml create mode 100644 acceptance/tests/example.spec.ts create mode 100644 playwright.config.ts create mode 100644 tests-examples/demo-todo-app.spec.ts diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..81162484 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm install -g pnpm && pnpm install + - name: Install Playwright Browsers + run: pnpm exec playwright install --with-deps + - name: Run Playwright tests + run: pnpm exec playwright test + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index 978119f3..5cf3100a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,7 @@ packages/zitadel-server/src/app/proto .idea .vercel .env*.local +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/acceptance/setup.sh b/acceptance/setup.sh index d3db4f25..3d1295d5 100755 --- a/acceptance/setup.sh +++ b/acceptance/setup.sh @@ -11,7 +11,7 @@ echo "Using audience ${AUDIENCE} for which the key is used." SERVICE=${SERVICE:-$AUDIENCE} echo "Using the service ${SERVICE} to connect to ZITADEL. For example in docker compose this can differ from the audience." -WRITE_ENVIRONMENT_FILE=${WRITE_ENVIRONMENT_FILE:-$(dirname "$0")/../apps/login/.env.acceptance} +WRITE_ENVIRONMENT_FILE=${WRITE_ENVIRONMENT_FILE:-$(dirname "$0")/../apps/login/.env.local} echo "Writing environment file to ${WRITE_ENVIRONMENT_FILE} when done." AUDIENCE_HOST="$(echo $AUDIENCE | cut -d/ -f3)" diff --git a/acceptance/tests/example.spec.ts b/acceptance/tests/example.spec.ts new file mode 100644 index 00000000..b9baed2d --- /dev/null +++ b/acceptance/tests/example.spec.ts @@ -0,0 +1,7 @@ +import { test, expect } from '@playwright/test'; + +test('get started link', async ({ page }) => { + await page.goto('http://localhost:8080/'); + + await page.getByRole('heading', { name: 'Welcome back!' }).isVisible(); +}); diff --git a/package.json b/package.json index 4ec7f249..023717b8 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,12 @@ }, "devDependencies": { "@changesets/cli": "^2.27.8", + "@playwright/test": "^1.48.1", + "@types/node": "^22.7.5", "@vitejs/plugin-react": "^4.2.1", + "@zitadel/prettier-config": "workspace:*", "eslint": "8.57.1", "eslint-config-zitadel": "workspace:*", - "@zitadel/prettier-config": "workspace:*", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^4.0.0", "tsup": "^8.3.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000..7f5e846e --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,79 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './acceptance/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/pnpm-lock.yaml b/pnpm-lock.yaml index 1a2f4ff9..1ec76ca2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,15 @@ importers: '@changesets/cli': specifier: ^2.27.8 version: 2.27.8 + '@playwright/test': + specifier: ^1.48.1 + version: 1.48.1 + '@types/node': + specifier: ^22.7.5 + version: 22.7.5 '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.3.1(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1)) + version: 4.3.1(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) '@zitadel/prettier-config': specifier: workspace:* version: link:packages/zitadel-prettier-config @@ -43,10 +49,10 @@ importers: version: 5.6.2 vite-tsconfig-paths: specifier: ^5.0.1 - version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1)) + version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(sass@1.79.1) + version: 2.1.1(@types/node@22.7.5)(jsdom@25.0.0)(sass@1.79.1) apps/login: dependencies: @@ -61,7 +67,7 @@ importers: version: 0.5.7(tailwindcss@3.4.13) '@vercel/analytics': specifier: ^1.2.2 - version: 1.3.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1) + version: 1.3.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1) '@zitadel/client': specifier: workspace:* version: link:../../packages/zitadel-client @@ -85,13 +91,13 @@ importers: version: 2.30.1 next: specifier: 14.2.14 - version: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) + version: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) next-intl: specifier: ^3.20.0 - version: 3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1) + version: 3.20.0(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1) next-themes: specifier: ^0.2.1 - version: 0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 0.2.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nice-grpc: specifier: 2.0.1 version: 2.0.1 @@ -1036,6 +1042,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@playwright/test@1.48.1': + resolution: {integrity: sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==} + engines: {node: '>=18'} + hasBin: true + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -1270,6 +1281,9 @@ packages: '@types/node@22.5.5': resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2403,6 +2417,11 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3473,6 +3492,16 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + playwright-core@1.48.1: + resolution: {integrity: sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.48.1: + resolution: {integrity: sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==} + engines: {node: '>=18'} + hasBin: true + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -5375,6 +5404,10 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@playwright/test@1.48.1': + dependencies: + playwright: 1.48.1 + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -5589,6 +5622,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + '@types/normalize-package-data@2.4.4': {} '@types/prop-types@15.7.12': {} @@ -5659,23 +5696,23 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vercel/analytics@1.3.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)': + '@vercel/analytics@1.3.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1)': dependencies: server-only: 0.0.1 optionalDependencies: - next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) + next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) react: 18.3.1 '@vercel/git-hooks@1.0.0': {} - '@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))': + '@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) transitivePeerDependencies: - supports-color @@ -5686,13 +5723,13 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1))': + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1))': dependencies: '@vitest/spy': 2.1.1 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: - vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) '@vitest/pretty-format@2.1.1': dependencies: @@ -7007,6 +7044,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -7792,21 +7832,21 @@ snapshots: negotiator@0.6.3: {} - next-intl@3.20.0(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1): + next-intl@3.20.0(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react@18.3.1): dependencies: '@formatjs/intl-localematcher': 0.5.4 negotiator: 0.6.3 - next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) + next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) react: 18.3.1 use-intl: 3.20.0(react@18.3.1) - next-themes@0.2.1(next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-themes@0.2.1(next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - next: 14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) + next: 14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@14.2.14(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1): + next@14.2.14(@babel/core@7.25.2)(@playwright/test@1.48.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.79.1): dependencies: '@next/env': 14.2.14 '@swc/helpers': 0.5.5 @@ -7827,6 +7867,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.14 '@next/swc-win32-ia32-msvc': 14.2.14 '@next/swc-win32-x64-msvc': 14.2.14 + '@playwright/test': 1.48.1 sass: 1.79.1 transitivePeerDependencies: - '@babel/core' @@ -8065,6 +8106,14 @@ snapshots: pirates@4.0.6: {} + playwright-core@1.48.1: {} + + playwright@1.48.1: + dependencies: + playwright-core: 1.48.1 + optionalDependencies: + fsevents: 2.3.2 + possible-typed-array-names@1.0.0: {} postcss-import@15.1.0(postcss@8.4.47): @@ -9017,12 +9066,12 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite-node@2.1.1(@types/node@22.5.5)(sass@1.79.1): + vite-node@2.1.1(@types/node@22.7.5)(sass@1.79.1): dependencies: cac: 6.7.14 debug: 4.3.7(supports-color@5.5.0) pathe: 1.1.2 - vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) transitivePeerDependencies: - '@types/node' - less @@ -9034,31 +9083,31 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1)): + vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)): dependencies: debug: 4.3.6 globrex: 0.1.2 tsconfck: 3.1.1(typescript@5.6.2) optionalDependencies: - vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) transitivePeerDependencies: - supports-color - typescript - vite@5.4.6(@types/node@22.5.5)(sass@1.79.1): + vite@5.4.6(@types/node@22.7.5)(sass@1.79.1): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.21.3 optionalDependencies: - '@types/node': 22.5.5 + '@types/node': 22.7.5 fsevents: 2.3.3 sass: 1.79.1 - vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(sass@1.79.1): + vitest@2.1.1(@types/node@22.7.5)(jsdom@25.0.0)(sass@1.79.1): dependencies: '@vitest/expect': 2.1.1 - '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.5.5)(sass@1.79.1)) + '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) '@vitest/pretty-format': 2.1.1 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -9073,11 +9122,11 @@ snapshots: tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.6(@types/node@22.5.5)(sass@1.79.1) - vite-node: 2.1.1(@types/node@22.5.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) + vite-node: 2.1.1(@types/node@22.7.5)(sass@1.79.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.5.5 + '@types/node': 22.7.5 jsdom: 25.0.0 transitivePeerDependencies: - less diff --git a/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts new file mode 100644 index 00000000..8641cb5f --- /dev/null +++ b/tests-examples/demo-todo-app.spec.ts @@ -0,0 +1,437 @@ +import { test, expect, type Page } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('https://demo.playwright.dev/todomvc'); +}); + +const TODO_ITEMS = [ + 'buy some cheese', + 'feed the cat', + 'book a doctors appointment' +] as const; + +test.describe('New Todo', () => { + test('should allow me to add todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create 1st todo. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Make sure the list only has one todo item. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0] + ]); + + // Create 2nd todo. + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + + // Make sure the list now has two todo items. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[1] + ]); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); + + test('should clear text input field when an item is added', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create one todo item. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Check that input is empty. + await expect(newTodo).toBeEmpty(); + await checkNumberOfTodosInLocalStorage(page, 1); + }); + + test('should append new items to the bottom of the list', async ({ page }) => { + // Create 3 items. + await createDefaultTodos(page); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + // Check test using different methods. + await expect(page.getByText('3 items left')).toBeVisible(); + await expect(todoCount).toHaveText('3 items left'); + await expect(todoCount).toContainText('3'); + await expect(todoCount).toHaveText(/3/); + + // Check all items in one call. + await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); + await checkNumberOfTodosInLocalStorage(page, 3); + }); +}); + +test.describe('Mark all as completed', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test.afterEach(async ({ page }) => { + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should allow me to mark all items as completed', async ({ page }) => { + // Complete all todos. + await page.getByLabel('Mark all as complete').check(); + + // Ensure all todos have 'completed' class. + await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + }); + + test('should allow me to clear the complete state of all items', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + // Check and then immediately uncheck. + await toggleAll.check(); + await toggleAll.uncheck(); + + // Should be no completed classes. + await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); + }); + + test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + await toggleAll.check(); + await expect(toggleAll).toBeChecked(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Uncheck first todo. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').uncheck(); + + // Reuse toggleAll locator and make sure its not checked. + await expect(toggleAll).not.toBeChecked(); + + await firstTodo.getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Assert the toggle all is checked again. + await expect(toggleAll).toBeChecked(); + }); +}); + +test.describe('Item', () => { + + test('should allow me to mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + // Check first item. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').check(); + await expect(firstTodo).toHaveClass('completed'); + + // Check second item. + const secondTodo = page.getByTestId('todo-item').nth(1); + await expect(secondTodo).not.toHaveClass('completed'); + await secondTodo.getByRole('checkbox').check(); + + // Assert completed class. + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).toHaveClass('completed'); + }); + + test('should allow me to un-mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const firstTodo = page.getByTestId('todo-item').nth(0); + const secondTodo = page.getByTestId('todo-item').nth(1); + const firstTodoCheckbox = firstTodo.getByRole('checkbox'); + + await firstTodoCheckbox.check(); + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await firstTodoCheckbox.uncheck(); + await expect(firstTodo).not.toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 0); + }); + + test('should allow me to edit an item', async ({ page }) => { + await createDefaultTodos(page); + + const todoItems = page.getByTestId('todo-item'); + const secondTodo = todoItems.nth(1); + await secondTodo.dblclick(); + await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); + await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); + + // Explicitly assert the new text value. + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2] + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); +}); + +test.describe('Editing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should hide other controls when editing', async ({ page }) => { + const todoItem = page.getByTestId('todo-item').nth(1); + await todoItem.dblclick(); + await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); + await expect(todoItem.locator('label', { + hasText: TODO_ITEMS[1], + })).not.toBeVisible(); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should save edits on blur', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should trim entered text', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should remove the item if an empty text string was entered', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[2], + ]); + }); + + test('should cancel edits on escape', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); + await expect(todoItems).toHaveText(TODO_ITEMS); + }); +}); + +test.describe('Counter', () => { + test('should display the current number of todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + await expect(todoCount).toContainText('1'); + + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + await expect(todoCount).toContainText('2'); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); +}); + +test.describe('Clear completed button', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + }); + + test('should display the correct text', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); + }); + + test('should remove completed items when clicked', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).getByRole('checkbox').check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(todoItems).toHaveCount(2); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should be hidden when there are no items that are completed', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); + }); +}); + +test.describe('Persistence', () => { + test('should persist its data', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const todoItems = page.getByTestId('todo-item'); + const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); + await firstTodoCheck.check(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + + // Ensure there is 1 completed item. + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + // Now reload. + await page.reload(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + }); +}); + +test.describe('Routing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + // make sure the app had a chance to save updated todos in storage + // before navigating to a new view, otherwise the items can get lost :( + // in some frameworks like Durandal + await checkTodosInLocalStorage(page, TODO_ITEMS[0]); + }); + + test('should allow me to display active items', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await expect(todoItem).toHaveCount(2); + await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should respect the back button', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await test.step('Showing all items', async () => { + await page.getByRole('link', { name: 'All' }).click(); + await expect(todoItem).toHaveCount(3); + }); + + await test.step('Showing active items', async () => { + await page.getByRole('link', { name: 'Active' }).click(); + }); + + await test.step('Showing completed items', async () => { + await page.getByRole('link', { name: 'Completed' }).click(); + }); + + await expect(todoItem).toHaveCount(1); + await page.goBack(); + await expect(todoItem).toHaveCount(2); + await page.goBack(); + await expect(todoItem).toHaveCount(3); + }); + + test('should allow me to display completed items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Completed' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(1); + }); + + test('should allow me to display all items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await page.getByRole('link', { name: 'Completed' }).click(); + await page.getByRole('link', { name: 'All' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(3); + }); + + test('should highlight the currently applied filter', async ({ page }) => { + await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); + + //create locators for active and completed links + const activeLink = page.getByRole('link', { name: 'Active' }); + const completedLink = page.getByRole('link', { name: 'Completed' }); + await activeLink.click(); + + // Page change - active items. + await expect(activeLink).toHaveClass('selected'); + await completedLink.click(); + + // Page change - completed items. + await expect(completedLink).toHaveClass('selected'); + }); +}); + +async function createDefaultTodos(page: Page) { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } +} + +async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).length === e; + }, expected); +} + +async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; + }, expected); +} + +async function checkTodosInLocalStorage(page: Page, title: string) { + return await page.waitForFunction(t => { + return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); + }, title); +} From 8c6d957f4ad9547e9cffee76551ba03aeffc2ee3 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 12:24:29 +0200 Subject: [PATCH 03/40] pipeline --- .github/workflows/playwright.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 81162484..f6d7e713 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,9 +1,9 @@ name: Playwright Tests on: push: - branches: [ main, master ] + branches: [ main ] pull_request: - branches: [ main, master ] + branches: [ main ] jobs: test: timeout-minutes: 60 From fe289e32fa71e4465ff135b7c36f125a0ca4b8a2 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 12:34:53 +0200 Subject: [PATCH 04/40] build and test --- .github/workflows/playwright.yml | 8 ++++++-- acceptance/docker-compose.yaml | 2 +- package.json | 1 + playwright.config.ts | 12 ++++++------ turbo.json | 1 + 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index f6d7e713..77a1e4cd 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,15 +1,19 @@ -name: Playwright Tests +name: Acceptance Tests on: push: branches: [ main ] pull_request: branches: [ main ] jobs: - test: + acceptance-tests: timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Run docker-compose + uses: hoverkraft-tech/compose-action@v2.0.1 + with: + compose-file: "./acceptance/docker-compose.yaml" - uses: actions/setup-node@v4 with: node-version: lts/* diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index b39a3a4f..fa84b9d8 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -48,7 +48,7 @@ services: environment: KEY: /key/zitadel-admin-sa.json SERVICE: http://zitadel:8080 - WRITE_ENVIRONMENT_FILE: /apps/login/.env.acceptance + WRITE_ENVIRONMENT_FILE: /apps/login/.env.local volumes: - "./machinekey:/key" - "../apps/login:/apps/login" diff --git a/package.json b/package.json index 023717b8..3fc48054 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "generate": "turbo run generate", "build": "turbo run build", "test": "turbo run test", + "start": "turbo run start", "test:unit": "turbo run test:unit -- --passWithNoTests", "test:integration": "turbo run test:integration", "test:watch": "turbo run test:watch", diff --git a/playwright.config.ts b/playwright.config.ts index 7f5e846e..9e7492bf 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -70,10 +70,10 @@ export default defineConfig({ // }, ], - /* 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, - // }, + /* Run local dev server before starting the tests */ + webServer: { + command: 'pnpm start', + url: 'http://127.0.0.1:3000', + reuseExistingServer: !process.env.CI, + }, }); diff --git a/turbo.json b/turbo.json index 7d38ae4c..e2412dfe 100644 --- a/turbo.json +++ b/turbo.json @@ -21,6 +21,7 @@ }, "build": {}, "test": {}, + "start": {}, "test:unit": {}, "test:integration": {}, "test:watch": { From ac7cbe5460ff5a8ea0f58f303d9e40c540727e05 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 12:35:34 +0200 Subject: [PATCH 05/40] test on pr --- .github/workflows/playwright.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 77a1e4cd..943f6d87 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,9 +1,6 @@ name: Acceptance Tests on: - push: - branches: [ main ] pull_request: - branches: [ main ] jobs: acceptance-tests: timeout-minutes: 60 From 5be0ed45ae7262720351d01cf89729650a53a47b Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 12:37:41 +0200 Subject: [PATCH 06/40] rename pipeline workflows --- .../{playwright.yml => acceptance-tests.yml} | 3 +-- ...{test.yml => unit-and-integration-tests.yml} | 17 +---------------- 2 files changed, 2 insertions(+), 18 deletions(-) rename .github/workflows/{playwright.yml => acceptance-tests.yml} (97%) rename .github/workflows/{test.yml => unit-and-integration-tests.yml} (97%) diff --git a/.github/workflows/playwright.yml b/.github/workflows/acceptance-tests.yml similarity index 97% rename from .github/workflows/playwright.yml rename to .github/workflows/acceptance-tests.yml index 943f6d87..e0d635c9 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/acceptance-tests.yml @@ -1,6 +1,5 @@ name: Acceptance Tests -on: - pull_request: +on: pull_request jobs: acceptance-tests: timeout-minutes: 60 diff --git a/.github/workflows/test.yml b/.github/workflows/unit-and-integration-tests.yml similarity index 97% rename from .github/workflows/test.yml rename to .github/workflows/unit-and-integration-tests.yml index 91c78a4d..ecdc443f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/unit-and-integration-tests.yml @@ -1,18 +1,12 @@ -name: Quality - +name: Unit And Integration Tests on: pull_request - jobs: quality: name: Ensure Quality - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: contents: "read" - strategy: fail-fast: false matrix: @@ -21,31 +15,25 @@ jobs: - lint - test:unit - test:integration - steps: - name: Checkout Repo uses: actions/checkout@v4.1.6 - - name: Setup Node.js 20.x uses: actions/setup-node@v4.0.2 with: node-version: 20.x - - name: Setup pnpm uses: pnpm/action-setup@v4.0.0 - - uses: pnpm/action-setup@v4.0.0 name: Install pnpm id: pnpm-install with: run_install: false - - name: Get pnpm store directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v4.0.2 name: Setup pnpm cache with: @@ -53,7 +41,6 @@ jobs: key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - - uses: actions/cache@v4.0.2 name: Setup Cypress binary cache with: @@ -62,10 +49,8 @@ jobs: restore-keys: | ${{ runner.os }}-cypress-binary- if: ${{ matrix.command }} == "test:integration" - - name: Install Dependencies run: pnpm install - - name: Check id: check run: pnpm ${{ matrix.command }} From 2fa16d5f8fd40ad100923e629f6576b28e6de61f Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 15:10:49 +0200 Subject: [PATCH 07/40] generate --- .github/workflows/acceptance-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index e0d635c9..94836777 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -14,7 +14,7 @@ jobs: with: node-version: lts/* - name: Install dependencies - run: npm install -g pnpm && pnpm install + run: npm install -g pnpm && pnpm install && pnpm generate - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps - name: Run Playwright tests From 653b499668b60d486567b951396d348955e9fabe Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 15:21:26 +0200 Subject: [PATCH 08/40] timeout --- .../tests/{example.spec.ts => username-password.spec.ts} | 0 acceptance/tests/welcome.ts | 7 +++++++ playwright.config.ts | 1 + 3 files changed, 8 insertions(+) rename acceptance/tests/{example.spec.ts => username-password.spec.ts} (100%) create mode 100644 acceptance/tests/welcome.ts diff --git a/acceptance/tests/example.spec.ts b/acceptance/tests/username-password.spec.ts similarity index 100% rename from acceptance/tests/example.spec.ts rename to acceptance/tests/username-password.spec.ts diff --git a/acceptance/tests/welcome.ts b/acceptance/tests/welcome.ts new file mode 100644 index 00000000..b9baed2d --- /dev/null +++ b/acceptance/tests/welcome.ts @@ -0,0 +1,7 @@ +import { test, expect } from '@playwright/test'; + +test('get started link', async ({ page }) => { + await page.goto('http://localhost:8080/'); + + await page.getByRole('heading', { name: 'Welcome back!' }).isVisible(); +}); diff --git a/playwright.config.ts b/playwright.config.ts index 9e7492bf..5214aec6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -75,5 +75,6 @@ export default defineConfig({ command: 'pnpm start', url: 'http://127.0.0.1:3000', reuseExistingServer: !process.env.CI, + timeout: 5 * 60_000, }, }); From f1b756b7213716d32ed27818860bd74d5ec4b494 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 16:50:48 +0200 Subject: [PATCH 09/40] submit username and password --- acceptance/tests/username-password.spec.ts | 13 +++++++++---- acceptance/tests/welcome.ts | 7 +++---- playwright.config.ts | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/acceptance/tests/username-password.spec.ts b/acceptance/tests/username-password.spec.ts index b9baed2d..72f2d867 100644 --- a/acceptance/tests/username-password.spec.ts +++ b/acceptance/tests/username-password.spec.ts @@ -1,7 +1,12 @@ import { test, expect } from '@playwright/test'; -test('get started link', async ({ page }) => { - await page.goto('http://localhost:8080/'); - - await page.getByRole('heading', { name: 'Welcome back!' }).isVisible(); +test('username and password', async ({ page }) => { + await page.goto('/'); + const loginname = page.getByLabel('Loginname') + await loginname.pressSequentially("zitadel-admin@zitadel.localhost"); + await loginname.press( 'Enter'); + const password = page.getByLabel('Password') + await password.pressSequentially("Password1!"); + await password.press( 'Enter'); + await page.getByText('Skip').click(); }); diff --git a/acceptance/tests/welcome.ts b/acceptance/tests/welcome.ts index b9baed2d..22734b0c 100644 --- a/acceptance/tests/welcome.ts +++ b/acceptance/tests/welcome.ts @@ -1,7 +1,6 @@ -import { test, expect } from '@playwright/test'; - -test('get started link', async ({ page }) => { - await page.goto('http://localhost:8080/'); +import { test } from '@playwright/test'; +test('login is accessible', async ({ page }) => { + await page.goto('http://localhost:3000/'); await page.getByRole('heading', { name: 'Welcome back!' }).isVisible(); }); diff --git a/playwright.config.ts b/playwright.config.ts index 5214aec6..ccf7516d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -26,7 +26,7 @@ export default defineConfig({ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', + baseURL: 'http://127.0.0.1:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', From c5620e6acc8d2edc0d773023f8e234d9f8c2a4a1 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 17:11:51 +0200 Subject: [PATCH 10/40] concurrent setup --- .github/workflows/acceptance-tests.yml | 24 ++++++++++++++++-------- playwright.config.ts | 5 +++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 94836777..c20bed29 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -6,17 +6,25 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Run docker-compose - uses: hoverkraft-tech/compose-action@v2.0.1 - with: - compose-file: "./acceptance/docker-compose.yaml" - uses: actions/setup-node@v4 with: node-version: lts/* - - name: Install dependencies - run: npm install -g pnpm && pnpm install && pnpm generate - - name: Install Playwright Browsers - run: pnpm exec playwright install --with-deps + - name: Run Docker Compose and Install Dependencies in Parallel + run: | + echo "Start docker-compose in the background" + docker-compose -f ./acceptance/docker-compose.yaml up -d & + + echo "Install node_modules in the foreground" + npm install -g pnpm && pnpm install + + echo "Generate and create a production build in the background" + pnpm build & + + echo "Install Playwright with browsers in the background" + pnpm exec playwright install --with-deps & + + echo "Wait for all background processes to complete" + wait - name: Run Playwright tests run: pnpm exec playwright test - uses: actions/upload-artifact@v4 diff --git a/playwright.config.ts b/playwright.config.ts index ccf7516d..fed6afd5 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -43,11 +43,12 @@ export default defineConfig({ name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, - +/* TODO: webkit fails. Is this a bug? { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, +*/ /* Test against mobile viewports. */ // { @@ -74,7 +75,7 @@ export default defineConfig({ webServer: { command: 'pnpm start', url: 'http://127.0.0.1:3000', - reuseExistingServer: !process.env.CI, + reuseExistingServer: false, //!process.env.CI, timeout: 5 * 60_000, }, }); From 576cdcc76a3c80c92785b9a9524e8e9362c5b1ee Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 17:17:13 +0200 Subject: [PATCH 11/40] fail earlier --- .github/workflows/acceptance-tests.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index c20bed29..43699aaf 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -12,20 +12,34 @@ jobs: - name: Run Docker Compose and Install Dependencies in Parallel run: | echo "Start docker-compose in the background" - docker-compose -f ./acceptance/docker-compose.yaml up -d & - + docker compose -f ./acceptance/docker-compose.yaml up -d & + DOCKER_COMPOSE_PID=$! + echo "Install node_modules in the foreground" npm install -g pnpm && pnpm install echo "Generate and create a production build in the background" pnpm build & + GENERATE_BUILD_PID=$! echo "Install Playwright with browsers in the background" pnpm exec playwright install --with-deps & + PLAYWRIGHT_INSTALL_PID=$! echo "Wait for all background processes to complete" - wait - - name: Run Playwright tests + while true; do + wait -n $DOCKER_COMPOSE_PID $GENERATE_BUILD_PID $PLAYWRIGHT_INSTALL_PID + EXIT_STATUS=$? + if [ $EXIT_STATUS -ne 0 ]; then + echo "A background process failed with exit code $EXIT_STATUS." + exit $EXIT_STATUS + fi + # Exit the loop if all processes have finished + if ! kill -0 $DOCKER_COMPOSE_PID $GENERATE_BUILD_PID $PLAYWRIGHT_INSTALL_PID 2>/dev/null; then + break + fi + done + - name: Run Playwright Tests run: pnpm exec playwright test - uses: actions/upload-artifact@v4 if: ${{ !cancelled() }} From ca0e551dd5015d740246aeb3fa5097c43eb174fe Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 17:26:28 +0200 Subject: [PATCH 12/40] kill -0 --- .github/workflows/acceptance-tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 43699aaf..8e528e62 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -34,8 +34,10 @@ jobs: echo "A background process failed with exit code $EXIT_STATUS." exit $EXIT_STATUS fi - # Exit the loop if all processes have finished - if ! kill -0 $DOCKER_COMPOSE_PID $GENERATE_BUILD_PID $PLAYWRIGHT_INSTALL_PID 2>/dev/null; then + # Check if all processes have finished + if ! kill -0 $DOCKER_COMPOSE_PID 2>/dev/null && \ + ! kill -0 $GENERATE_BUILD_PID 2>/dev/null && \ + ! kill -0 $PLAYWRIGHT_INSTALL_PID 2>/dev/null; then break fi done From be84e9492696ddde6b807f459369bb20617e0969 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 18:22:55 +0200 Subject: [PATCH 13/40] build with env --- .github/workflows/acceptance-tests.yml | 32 +++++++++++++++----------- apps/login/package.json | 1 - packages/zitadel-client/turbo.json | 3 --- playwright.config.ts | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 8e528e62..2b990f99 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -12,23 +12,26 @@ jobs: - name: Run Docker Compose and Install Dependencies in Parallel run: | echo "Start docker-compose in the background" - docker compose -f ./acceptance/docker-compose.yaml up -d & + docker compose -f ./acceptance/docker-compose.yaml up -d DOCKER_COMPOSE_PID=$! - - echo "Install node_modules in the foreground" + echo "Docker Compose PID: $DOCKER_COMPOSE_PID" + + echo "Install app dependencies in the foreground" npm install -g pnpm && pnpm install - echo "Generate and create a production build in the background" - pnpm build & - GENERATE_BUILD_PID=$! - - echo "Install Playwright with browsers in the background" + echo "Install Test Browsers in the background" pnpm exec playwright install --with-deps & - PLAYWRIGHT_INSTALL_PID=$! + INSTALL_BROWSERS_PID=$! + echo "Install browsers PID: $INSTALL_BROWSERS_PID" + + echo "Generate gRPC stubs in the background" + pnpm generate & + GENERATE_PID=$! + echo "Generate stubs PID: $GENERATE_PID" - echo "Wait for all background processes to complete" + echo "Wait for all background processes to finish" while true; do - wait -n $DOCKER_COMPOSE_PID $GENERATE_BUILD_PID $PLAYWRIGHT_INSTALL_PID + wait -n $DOCKER_COMPOSE_PID $INSTALL_BROWSERS_PID $GENERATE_PID EXIT_STATUS=$? if [ $EXIT_STATUS -ne 0 ]; then echo "A background process failed with exit code $EXIT_STATUS." @@ -36,11 +39,14 @@ jobs: fi # Check if all processes have finished if ! kill -0 $DOCKER_COMPOSE_PID 2>/dev/null && \ - ! kill -0 $GENERATE_BUILD_PID 2>/dev/null && \ - ! kill -0 $PLAYWRIGHT_INSTALL_PID 2>/dev/null; then + ! kill -0 $INSTALL_BROWSERS_PID 2>/dev/null && \ + ! kill -0 GENERATE_PID 2>/dev/null; then break fi done + + echo "Generate and create a production build in the foreground" + pnpm build - name: Run Playwright Tests run: pnpm exec playwright test - uses: actions/upload-artifact@v4 diff --git a/apps/login/package.json b/apps/login/package.json index 9617300a..8863d361 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -22,7 +22,6 @@ "lint:fix": "prettier --write .", "lint-staged": "lint-staged", "build": "next build", - "prestart": "pnpm build", "start": "next start", "clean": "pnpm mock:destroy && rm -rf .turbo && rm -rf node_modules && rm -rf .next" }, diff --git a/packages/zitadel-client/turbo.json b/packages/zitadel-client/turbo.json index ea363690..52e8c763 100644 --- a/packages/zitadel-client/turbo.json +++ b/packages/zitadel-client/turbo.json @@ -6,9 +6,6 @@ "build": { "outputs": [ "dist/**" - ], - "dependsOn": [ - "@zitadel/proto#generate" ] } } diff --git a/playwright.config.ts b/playwright.config.ts index fed6afd5..9795c4ab 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -75,7 +75,7 @@ export default defineConfig({ webServer: { command: 'pnpm start', url: 'http://127.0.0.1:3000', - reuseExistingServer: false, //!process.env.CI, + reuseExistingServer: !process.env.CI, timeout: 5 * 60_000, }, }); From 17e516abcdb7b65cf6e1185d637748299e42debe Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 18:25:03 +0200 Subject: [PATCH 14/40] compose to background --- .github/workflows/acceptance-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 2b990f99..ad82736b 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -12,7 +12,7 @@ jobs: - name: Run Docker Compose and Install Dependencies in Parallel run: | echo "Start docker-compose in the background" - docker compose -f ./acceptance/docker-compose.yaml up -d + docker compose -f ./acceptance/docker-compose.yaml up -d & DOCKER_COMPOSE_PID=$! echo "Docker Compose PID: $DOCKER_COMPOSE_PID" From 3ff49c3affa3550007409a98381db8eb238ce0d7 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 18:37:56 +0200 Subject: [PATCH 15/40] wait individually --- .github/workflows/acceptance-tests.yml | 35 +++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index ad82736b..2ce8b5bf 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -29,21 +29,26 @@ jobs: GENERATE_PID=$! echo "Generate stubs PID: $GENERATE_PID" - echo "Wait for all background processes to finish" - while true; do - wait -n $DOCKER_COMPOSE_PID $INSTALL_BROWSERS_PID $GENERATE_PID - EXIT_STATUS=$? - if [ $EXIT_STATUS -ne 0 ]; then - echo "A background process failed with exit code $EXIT_STATUS." - exit $EXIT_STATUS - fi - # Check if all processes have finished - if ! kill -0 $DOCKER_COMPOSE_PID 2>/dev/null && \ - ! kill -0 $INSTALL_BROWSERS_PID 2>/dev/null && \ - ! kill -0 GENERATE_PID 2>/dev/null; then - break - fi - done + # Wait for docker-compose + wait $DOCKER_COMPOSE_PID + if [ $? -ne 0 ]; then + echo "Docker Compose failed" + exit 1 + fi + + # Wait for Playwright browser installation + wait $INSTALL_BROWSERS_PID + if [ $? -ne 0 ]; then + echo "Playwright browser installation failed" + exit 1 + fi + + # Wait for gRPC stubs generation + wait $GENERATE_PID + if [ $? -ne 0 ]; then + echo "gRPC stubs generation failed" + exit 1 + fi echo "Generate and create a production build in the foreground" pnpm build From c413805d6d31db07549ca05571ff22e215f8a30c Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 18:44:08 +0200 Subject: [PATCH 16/40] await setup --- .github/workflows/acceptance-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 2ce8b5bf..148de463 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -12,7 +12,7 @@ jobs: - name: Run Docker Compose and Install Dependencies in Parallel run: | echo "Start docker-compose in the background" - docker compose -f ./acceptance/docker-compose.yaml up -d & + docker compose -f ./acceptance/docker-compose.yaml run setup & DOCKER_COMPOSE_PID=$! echo "Docker Compose PID: $DOCKER_COMPOSE_PID" From b058b75f33ee65e997ef8a8f0a0bcf7bc76dd503 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 19:03:20 +0200 Subject: [PATCH 17/40] default uid --- acceptance/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index fa84b9d8..8a8ad797 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -1,6 +1,6 @@ services: zitadel: - user: "${ZITADEL_DEV_UID}" + user: "${ZITADEL_DEV_UID:-1000}" image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}" command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml' ports: @@ -42,7 +42,7 @@ services: - zitadel setup: - user: "${ZITADEL_DEV_UID}" + user: "${ZITADEL_DEV_UID:-1000}" container_name: setup build: . environment: From 77fb366044e8a60dec4ecd82362752527802158d Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 19:12:16 +0200 Subject: [PATCH 18/40] use current user --- acceptance/docker-compose.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index 8a8ad797..94a2be70 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -1,6 +1,6 @@ services: zitadel: - user: "${ZITADEL_DEV_UID:-1000}" + user: "${USER}" image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}" command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml' ports: @@ -42,7 +42,7 @@ services: - zitadel setup: - user: "${ZITADEL_DEV_UID:-1000}" + user: "${USER}" container_name: setup build: . environment: From 76430e16288c514b52d62d5bb2fa2275bc50a7b3 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 19:15:19 +0200 Subject: [PATCH 19/40] use root --- .github/workflows/acceptance-tests.yml | 4 ++++ acceptance/docker-compose.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 148de463..63c1e899 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -1,5 +1,7 @@ name: Acceptance Tests on: pull_request +env: + ZITADEL_DEV_UID: root jobs: acceptance-tests: timeout-minutes: 60 @@ -11,6 +13,8 @@ jobs: node-version: lts/* - name: Run Docker Compose and Install Dependencies in Parallel run: | + cat /etc/passwd + echo "Start docker-compose in the background" docker compose -f ./acceptance/docker-compose.yaml run setup & DOCKER_COMPOSE_PID=$! diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index 94a2be70..fa84b9d8 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -1,6 +1,6 @@ services: zitadel: - user: "${USER}" + user: "${ZITADEL_DEV_UID}" image: "${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}" command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml' ports: @@ -42,7 +42,7 @@ services: - zitadel setup: - user: "${USER}" + user: "${ZITADEL_DEV_UID}" container_name: setup build: . environment: From 5969b145e06a149398169f4de7407a7c9d1accf7 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 19:17:56 +0200 Subject: [PATCH 20/40] runneradmin --- .github/workflows/acceptance-tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 63c1e899..249a5187 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -1,7 +1,7 @@ name: Acceptance Tests on: pull_request env: - ZITADEL_DEV_UID: root + ZITADEL_DEV_UID: runneradmin jobs: acceptance-tests: timeout-minutes: 60 @@ -13,8 +13,6 @@ jobs: node-version: lts/* - name: Run Docker Compose and Install Dependencies in Parallel run: | - cat /etc/passwd - echo "Start docker-compose in the background" docker compose -f ./acceptance/docker-compose.yaml run setup & DOCKER_COMPOSE_PID=$! From 4cb17953b0e9994cc244977dd204ab2f3bcf9216 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 19:19:43 +0200 Subject: [PATCH 21/40] root --- .github/workflows/acceptance-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 249a5187..f0faa073 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -1,7 +1,5 @@ name: Acceptance Tests on: pull_request -env: - ZITADEL_DEV_UID: runneradmin jobs: acceptance-tests: timeout-minutes: 60 @@ -12,6 +10,8 @@ jobs: with: node-version: lts/* - name: Run Docker Compose and Install Dependencies in Parallel + env: + ZITADEL_DEV_UID: root run: | echo "Start docker-compose in the background" docker compose -f ./acceptance/docker-compose.yaml run setup & From cb8f0717293b7d0ee52f89aaf814201751607ba2 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Wed, 16 Oct 2024 20:55:37 +0200 Subject: [PATCH 22/40] simplify setup --- acceptance/Dockerfile | 1 - acceptance/docker-compose.yaml | 8 +- acceptance/{machinekey => pat}/.gitignore | 0 acceptance/{machinekey => pat}/.gitkeep | 0 acceptance/pat/zitadel-admin-sa.pat | 1 + acceptance/setup.sh | 141 ++++------------------ acceptance/zitadel.yaml | 13 +- 7 files changed, 40 insertions(+), 124 deletions(-) rename acceptance/{machinekey => pat}/.gitignore (100%) rename acceptance/{machinekey => pat}/.gitkeep (100%) create mode 100644 acceptance/pat/zitadel-admin-sa.pat diff --git a/acceptance/Dockerfile b/acceptance/Dockerfile index a2283d09..36f6ba8f 100644 --- a/acceptance/Dockerfile +++ b/acceptance/Dockerfile @@ -1,6 +1,5 @@ FROM golang:1.19-alpine RUN apk add curl jq -RUN go install github.com/zitadel/zitadel-tools@v0.4.0 COPY setup.sh /setup.sh RUN chmod +x /setup.sh ENTRYPOINT [ "/setup.sh" ] diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index fa84b9d8..afc6d4d6 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -6,7 +6,7 @@ services: ports: - "8080:8080" volumes: - - ./machinekey:/machinekey + - ./pat:/pat - ./zitadel.yaml:/zitadel.yaml depends_on: db: @@ -46,11 +46,11 @@ services: container_name: setup build: . environment: - KEY: /key/zitadel-admin-sa.json - SERVICE: http://zitadel:8080 + PAT_FILE: /pat/zitadel-admin-sa.pat + ZITADEL_API_INTERNAL_URL: http://zitadel:8080 WRITE_ENVIRONMENT_FILE: /apps/login/.env.local volumes: - - "./machinekey:/key" + - "./pat:/pat" - "../apps/login:/apps/login" depends_on: wait_for_zitadel: diff --git a/acceptance/machinekey/.gitignore b/acceptance/pat/.gitignore similarity index 100% rename from acceptance/machinekey/.gitignore rename to acceptance/pat/.gitignore diff --git a/acceptance/machinekey/.gitkeep b/acceptance/pat/.gitkeep similarity index 100% rename from acceptance/machinekey/.gitkeep rename to acceptance/pat/.gitkeep diff --git a/acceptance/pat/zitadel-admin-sa.pat b/acceptance/pat/zitadel-admin-sa.pat new file mode 100644 index 00000000..9ac8de64 --- /dev/null +++ b/acceptance/pat/zitadel-admin-sa.pat @@ -0,0 +1 @@ +fEJWwOJ3lFAn-COq0QxdXz_xCGrmp8Kj2l4i-xGWbh1UM2OtNwNz3_MblwOf_Lsd13B8ORk diff --git a/acceptance/setup.sh b/acceptance/setup.sh index 3d1295d5..5359659e 100755 --- a/acceptance/setup.sh +++ b/acceptance/setup.sh @@ -1,125 +1,34 @@ #!/bin/sh -set -e - -KEY=${KEY:-./machinekey/zitadel-admin-sa.json} -echo "Using key path ${KEY} to the instance admin service account." - -AUDIENCE=${AUDIENCE:-http://localhost:8080} -echo "Using audience ${AUDIENCE} for which the key is used." +set -ex + +PAT_FILE=${PAT_FILE:-./pat/zitadel-admin-sa.pat} +ZITADEL_API_PROTOCOL="${ZITADEL_API_PROTOCOL:-http}" +ZITADEL_API_DOMAIN="${ZITADEL_API_DOMAIN:-localhost}" +ZITADEL_API_PORT="${ZITADEL_API_PORT:-8080}" +ZITADEL_API_URL="${ZITADEL_API_URL:-${ZITADEL_API_PROTOCOL}://${ZITADEL_API_DOMAIN}:${ZITADEL_API_PORT}}" +ZITADEL_API_INTERNAL_URL="${ZITADEL_API_INTERNAL_URL:-${ZITADEL_API_URL}}" + +if [ -z "${PAT}" ]; then + echo "Reading PAT from file ${PAT_FILE}" + PAT=$(cat ${PAT_FILE}) +fi -SERVICE=${SERVICE:-$AUDIENCE} -echo "Using the service ${SERVICE} to connect to ZITADEL. For example in docker compose this can differ from the audience." +if [ -z "${ZITADEL_SERVICE_USER_ID}" ]; then + echo "Reading ZITADEL_SERVICE_USER_ID from userinfo endpoint" + USERINFO_RESPONSE=$(curl -s --request POST \ + --url "${ZITADEL_API_INTERNAL_URL}/oidc/v1/userinfo" \ + --header "Authorization: Bearer ${PAT}" \ + --header "Host: ${ZITADEL_API_DOMAIN}") + echo "Received userinfo response: ${USERINFO_RESPONSE}" + ZITADEL_SERVICE_USER_ID=$(echo "${USERINFO_RESPONSE}" | jq --raw-output '.sub') +fi WRITE_ENVIRONMENT_FILE=${WRITE_ENVIRONMENT_FILE:-$(dirname "$0")/../apps/login/.env.local} echo "Writing environment file to ${WRITE_ENVIRONMENT_FILE} when done." -AUDIENCE_HOST="$(echo $AUDIENCE | cut -d/ -f3)" -echo "Deferred the Host header ${AUDIENCE_HOST} which will be sent in requests that ZITADEL then maps to a virtual instance" - -JWT=$(zitadel-tools key2jwt --key ${KEY} --audience ${AUDIENCE}) -echo "Created JWT from Admin service account key ${JWT}" - -TOKEN_RESPONSE=$(curl -s --request POST \ - --url ${SERVICE}/oauth/v2/token \ - --header 'Content-Type: application/x-www-form-urlencoded' \ - --header "Host: ${AUDIENCE_HOST}" \ - --data grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \ - --data scope='openid profile email urn:zitadel:iam:org:project:id:zitadel:aud' \ - --data assertion="${JWT}") -echo "Got response from token endpoint:" -echo "${TOKEN_RESPONSE}" | jq - -TOKEN=$(echo -n ${TOKEN_RESPONSE} | jq --raw-output '.access_token') -echo "Extracted access token ${TOKEN}" - -ORG_RESPONSE=$(curl -s --request GET \ - --url ${SERVICE}/admin/v1/orgs/default \ - --header 'Accept: application/json' \ - --header "Authorization: Bearer ${TOKEN}" \ - --header "Host: ${AUDIENCE_HOST}") -echo "Got default org response:" -echo "${ORG_RESPONSE}" | jq - -ORG_ID=$(echo -n ${ORG_RESPONSE} | jq --raw-output '.org.id') -echo "Extracted default org id ${ORG_ID}" - -echo "ZITADEL_API_URL=${AUDIENCE} -ZITADEL_ORG_ID=${ORG_ID} -ZITADEL_SERVICE_USER_TOKEN=${TOKEN}" > ${WRITE_ENVIRONMENT_FILE} +echo "ZITADEL_API_URL=${ZITADEL_API_URL} +ZITADEL_SERVICE_USER_ID=${ZITADEL_SERVICE_USER_ID} +ZITADEL_SERVICE_USER_TOKEN=${PAT}" > ${WRITE_ENVIRONMENT_FILE} echo "Wrote environment file ${WRITE_ENVIRONMENT_FILE}" cat ${WRITE_ENVIRONMENT_FILE} - -if ! grep -q 'localhost' ${WRITE_ENVIRONMENT_FILE}; then - echo "Not developing against localhost, so creating a human user might not be necessary" - exit 0 -fi - -HUMAN_USER_USERNAME="zitadel-admin@zitadel.localhost" -HUMAN_USER_PASSWORD="Password1!" - -HUMAN_USER_PAYLOAD=$(cat << EOM -{ - "userName": "${HUMAN_USER_USERNAME}", - "profile": { - "firstName": "ZITADEL", - "lastName": "Admin", - "displayName": "ZITADEL Admin", - "preferredLanguage": "en" - }, - "email": { - "email": "zitadel-admin@zitadel.localhost", - "isEmailVerified": true - }, - "password": "${HUMAN_USER_PASSWORD}", - "passwordChangeRequired": false -} -EOM -) -echo "Creating human user" -echo "${HUMAN_USER_PAYLOAD}" | jq - -HUMAN_USER_RESPONSE=$(curl -s --request POST \ - --url ${SERVICE}/management/v1/users/human/_import \ - --header 'Content-Type: application/json' \ - --header 'Accept: application/json' \ - --header "Authorization: Bearer ${TOKEN}" \ - --header "Host: ${AUDIENCE_HOST}" \ - --data-raw "${HUMAN_USER_PAYLOAD}") -echo "Create human user response" -echo "${HUMAN_USER_RESPONSE}" | jq - -if [ "$(echo -n "${HUMAN_USER_RESPONSE}" | jq --raw-output '.code')" == "6" ]; then - echo "admin user already exists" - exit 0 -fi - -HUMAN_USER_ID=$(echo -n ${HUMAN_USER_RESPONSE} | jq --raw-output '.userId') -echo "Extracted human user id ${HUMAN_USER_ID}" - -HUMAN_ADMIN_PAYLOAD=$(cat << EOM -{ - "userId": "${HUMAN_USER_ID}", - "roles": [ - "IAM_OWNER" - ] -} -EOM -) -echo "Granting iam owner to human user" -echo "${HUMAN_ADMIN_PAYLOAD}" | jq - -HUMAN_ADMIN_RESPONSE=$(curl -s --request POST \ - --url ${SERVICE}/admin/v1/members \ - --header 'Content-Type: application/json' \ - --header 'Accept: application/json' \ - --header "Authorization: Bearer ${TOKEN}" \ - --header "Host: ${AUDIENCE_HOST}" \ - --data-raw "${HUMAN_ADMIN_PAYLOAD}") - -echo "Grant iam owner to human user response" -echo "${HUMAN_ADMIN_RESPONSE}" | jq - -echo "You can now log in at ${AUDIENCE}/ui/login" -echo "username: ${HUMAN_USER_USERNAME}" -echo "password: ${HUMAN_USER_PASSWORD}" \ No newline at end of file diff --git a/acceptance/zitadel.yaml b/acceptance/zitadel.yaml index 07a79bbb..1fe754dc 100644 --- a/acceptance/zitadel.yaml +++ b/acceptance/zitadel.yaml @@ -1,12 +1,19 @@ FirstInstance: - MachineKeyPath: /machinekey/zitadel-admin-sa.json + PatPath: /pat/zitadel-admin-sa.pat Org: + Human: + UserName: zitadel-admin + FirstName: ZITADEL + LastName: Admin + Password: Password1! + PasswordChangeRequired: true + PreferredLanguage: en Machine: Machine: Username: zitadel-admin-sa Name: Admin - MachineKey: - Type: 1 + Pat: + ExpirationDate: 2099-01-01T00:00:00Z Database: EventPushConnRatio: 0.2 # 4 From 1134b9c4b16892e6346653e18ea099103a5e9130 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Thu, 17 Oct 2024 16:42:49 +0200 Subject: [PATCH 23/40] develop against local zitadel --- README.md | 50 +++++++++++++++++++++-------- acceptance/pat/.gitignore | 2 +- acceptance/pat/.gitkeep | 0 acceptance/pat/zitadel-admin-sa.pat | 1 - acceptance/zitadel.yaml | 6 +--- package.json | 4 ++- 6 files changed, 42 insertions(+), 21 deletions(-) delete mode 100644 acceptance/pat/.gitkeep delete mode 100644 acceptance/pat/zitadel-admin-sa.pat diff --git a/README.md b/README.md index 6916ed2b..e5b0f1ed 100644 --- a/README.md +++ b/README.md @@ -175,32 +175,56 @@ To run the application make sure to install the dependencies with pnpm install ``` -then setup the environment for the login application which needs a `.env.local` in `/apps/login`. -Go to your instance and create a service user for the application having the `IAM_OWNER` manager role. -This user is required to have access to create users on your primary organization and reading policy data so it can be -restricted to your personal use case but we'll stick with `IAM_OWNER` for convenience. Create a PAT and copy the value to -paste it under the `ZITADEL_SERVICE_USER_TOKEN` key. -The file should look as follows: +then generate the GRPC stubs with -``` -ZITADEL_API_URL=[yourinstanceurl] -ZITADEL_ORG_ID=[yourprimaryorg] -ZITADEL_SERVICE_USER_TOKEN=[yourserviceuserpersonalaccesstoken] +```sh +pnpm generate ``` -then generate the GRPC stubs with +To run the application against a local ZITADEL instance, run the following command: ```sh -pnpm generate +pnpm run-zitadel ``` -and then run it with +This sets up ZITADEL using docker compose and writes the configuration to the file `apps/login/.env.local`. + +
+Alternatively, use another environment +You can develop against any ZITADEL instance in which you have sufficient rights to execute the following steps. +Just create or overwrite the file `apps/login/.env.local` yourself. +Add your instances base URL to the file at the key `ZITADEL_API_URL`. +Go to your instance and create a service user for the login application. +The login application creates users on your primary organization and reads policy data. +For the sake of simplicity, just make the service user an instance member with the role `IAM_OWNER`. +Create a PAT and copy it to the file `apps/login/.env.local` using the key `ZITADEL_SERVICE_USER_TOKEN`. +Also add the users ID to the file using the key `ZITADEL_SERVICE_USER_ID`. + +The file should look similar to this: + +``` +ZITADEL_API_URL=https://zitadel-tlx3du.us1.zitadel.cloud +ZITADEL_SERVICE_USER_ID=289106423158521850 +ZITADEL_SERVICE_USER_TOKEN=1S6w48thfWFI2klgfwkCnhXJLf9FQ457E-_3H74ePQxfO3Af0Tm4V5Xi-ji7urIl_xbn-Rk +``` +
+ +Start the login application in dev mode: ```sh pnpm dev ``` Open the login application with your favorite browser at `localhost:3000`. +Change the source code and see the changes live in your browser. + +Make sure the application still behaves as expected by running all tests + +```sh +pnpm test +``` + +To satisfy your unique workflow requirements, check out the package.json in the root directory for more detailed scripts. ### Deploy to Vercel diff --git a/acceptance/pat/.gitignore b/acceptance/pat/.gitignore index 7c9f54d0..f59ec20a 100644 --- a/acceptance/pat/.gitignore +++ b/acceptance/pat/.gitignore @@ -1 +1 @@ -zitadel-admin-sa.json +* \ No newline at end of file diff --git a/acceptance/pat/.gitkeep b/acceptance/pat/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/acceptance/pat/zitadel-admin-sa.pat b/acceptance/pat/zitadel-admin-sa.pat deleted file mode 100644 index 9ac8de64..00000000 --- a/acceptance/pat/zitadel-admin-sa.pat +++ /dev/null @@ -1 +0,0 @@ -fEJWwOJ3lFAn-COq0QxdXz_xCGrmp8Kj2l4i-xGWbh1UM2OtNwNz3_MblwOf_Lsd13B8ORk diff --git a/acceptance/zitadel.yaml b/acceptance/zitadel.yaml index 1fe754dc..407f424f 100644 --- a/acceptance/zitadel.yaml +++ b/acceptance/zitadel.yaml @@ -6,7 +6,7 @@ FirstInstance: FirstName: ZITADEL LastName: Admin Password: Password1! - PasswordChangeRequired: true + PasswordChangeRequired: false PreferredLanguage: en Machine: Machine: @@ -39,7 +39,3 @@ Logstore: Access: Stdout: Enabled: true - -DefaultInstance: - LoginPolicy: - MfaInitSkipLifetime: 0h \ No newline at end of file diff --git a/package.json b/package.json index 3fc48054..95a38ef5 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "start": "turbo run start", "test:unit": "turbo run test:unit -- --passWithNoTests", "test:integration": "turbo run test:integration", + "test:acceptance": "pnpm exec playwright test", "test:watch": "turbo run test:watch", "dev": "turbo run dev --no-cache --continue", "lint": "turbo run lint", @@ -17,7 +18,8 @@ "format": "prettier --check \"**/*.{ts,tsx,md}\"", "changeset": "changeset", "version-packages": "changeset version", - "release": "turbo run build --filter=login^... && changeset publish" + "release": "turbo run build --filter=login^... && changeset publish", + "run-zitadel": "docker compose -f ./acceptance/docker-compose.yaml run setup" }, "pnpm": { "overrides": { From 1ca16f9d9a064771d34db6864d0b725debed34ba Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:01:31 +0200 Subject: [PATCH 24/40] run acceptance --- .github/workflows/test.yml | 104 ++++++++++++++++++ .../workflows/unit-and-integration-tests.yml | 56 ---------- acceptance/docker-compose.yaml | 2 +- 3 files changed, 105 insertions(+), 57 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 .github/workflows/unit-and-integration-tests.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..786f990e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,104 @@ +name: Quality + +on: pull_request + +jobs: + quality: + env: + ZITADEL_IMAGE: ghcr.io/zitadel/zitadel:v2.63.4 + POSTGRES_IMAGE: postgres:17.0-alpine3.19 + + name: Ensure Quality + + runs-on: ubuntu-latest + + timeout-minutes: 30 + + permissions: + contents: "read" + + strategy: + fail-fast: false + matrix: + command: + - format --check + - lint + - test:unit + - test:integration + - test:acceptance + + steps: + - name: Checkout Repo + uses: actions/checkout@v4.1.6 + + - name: Setup Node.js 20.x + uses: actions/setup-node@v4.0.2 + with: + node-version: 20.x + + - name: Setup pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4.0.2 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install Dependencies + run: CYPRESS_INSTALL_BINARY=0 pnpm install + + # We build already here so we can fail fast if the build fails + - name: Run ZITADEL + run: pnpm build + if: ${{ matrix.command }} == "test:acceptance" + + - run: | + echo "CYPRESS_VERSION=$(pnpm list -r | grep cypress | cut -d ' ' -f 2)" >> $GITHUB_ENV + echo "PLAYWRIGHT_VERSION=$(npx playwright --version | cut -d ' ' -f 2)" >> $GITHUB_ENV + + - uses: actions/cache@v4.0.2 + name: Setup Cypress binary cache + with: + path: ~/.cache/Cypress + key: ${{ runner.os }}-cypress-binary-${{ env.CYPRESS_VERSION }} + restore-keys: | + ${{ runner.os }}-cypress-binary- + if: ${{ matrix.command }} == "test:integration" + + - name: Install Cypress Browsers + run: pnpm install + if: ${{ matrix.command }} == "test:integration" + + - uses: actions/cache@v4.0.2 + name: Setup Playwright binary cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-binary-${{ env.PLAYWRIGHT_VERSION }} + restore-keys: | + ${{ runner.os }}-playwright-binary- + if: ${{ matrix.command }} == "test:acceptance" + + - name: Install Playwright Browsers + run: sudo pnpm exec playwright install --with-deps + if: ${{ matrix.command }} == "test:acceptance" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + if: ${{ matrix.command }} == "test:acceptance" + + - name: Run ZITADEL + run: pnpm run-zitadel + if: ${{ matrix.command }} == "test:acceptance" + + - name: Check + id: check + run: pnpm ${{ matrix.command }} diff --git a/.github/workflows/unit-and-integration-tests.yml b/.github/workflows/unit-and-integration-tests.yml deleted file mode 100644 index ecdc443f..00000000 --- a/.github/workflows/unit-and-integration-tests.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Unit And Integration Tests -on: pull_request -jobs: - quality: - name: Ensure Quality - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - contents: "read" - strategy: - fail-fast: false - matrix: - command: - - format --check - - lint - - test:unit - - test:integration - steps: - - name: Checkout Repo - uses: actions/checkout@v4.1.6 - - name: Setup Node.js 20.x - uses: actions/setup-node@v4.0.2 - with: - node-version: 20.x - - name: Setup pnpm - uses: pnpm/action-setup@v4.0.0 - - uses: pnpm/action-setup@v4.0.0 - name: Install pnpm - id: pnpm-install - with: - run_install: false - - name: Get pnpm store directory - id: pnpm-cache - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v4.0.2 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - uses: actions/cache@v4.0.2 - name: Setup Cypress binary cache - with: - path: ~/.cache/Cypress - key: ${{ runner.os }}-cypress-binary-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-cypress-binary- - if: ${{ matrix.command }} == "test:integration" - - name: Install Dependencies - run: pnpm install - - name: Check - id: check - run: pnpm ${{ matrix.command }} diff --git a/acceptance/docker-compose.yaml b/acceptance/docker-compose.yaml index afc6d4d6..59839e00 100644 --- a/acceptance/docker-compose.yaml +++ b/acceptance/docker-compose.yaml @@ -14,7 +14,7 @@ services: db: restart: 'always' - image: 'postgres:latest' + image: "${POSTGRES_IMAGE:-postgres:latest}" environment: - POSTGRES_USER=zitadel - PGUSER=zitadel From 7b43cac249ea0f872841b5d7c5bf246b8365251f Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:06:19 +0200 Subject: [PATCH 25/40] remove gh workflow --- .github/workflows/acceptance-tests.yml | 64 -------------------------- 1 file changed, 64 deletions(-) delete mode 100644 .github/workflows/acceptance-tests.yml diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml deleted file mode 100644 index f0faa073..00000000 --- a/.github/workflows/acceptance-tests.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Acceptance Tests -on: pull_request -jobs: - acceptance-tests: - timeout-minutes: 60 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - name: Run Docker Compose and Install Dependencies in Parallel - env: - ZITADEL_DEV_UID: root - run: | - echo "Start docker-compose in the background" - docker compose -f ./acceptance/docker-compose.yaml run setup & - DOCKER_COMPOSE_PID=$! - echo "Docker Compose PID: $DOCKER_COMPOSE_PID" - - echo "Install app dependencies in the foreground" - npm install -g pnpm && pnpm install - - echo "Install Test Browsers in the background" - pnpm exec playwright install --with-deps & - INSTALL_BROWSERS_PID=$! - echo "Install browsers PID: $INSTALL_BROWSERS_PID" - - echo "Generate gRPC stubs in the background" - pnpm generate & - GENERATE_PID=$! - echo "Generate stubs PID: $GENERATE_PID" - - # Wait for docker-compose - wait $DOCKER_COMPOSE_PID - if [ $? -ne 0 ]; then - echo "Docker Compose failed" - exit 1 - fi - - # Wait for Playwright browser installation - wait $INSTALL_BROWSERS_PID - if [ $? -ne 0 ]; then - echo "Playwright browser installation failed" - exit 1 - fi - - # Wait for gRPC stubs generation - wait $GENERATE_PID - if [ $? -ne 0 ]; then - echo "gRPC stubs generation failed" - exit 1 - fi - - echo "Generate and create a production build in the foreground" - pnpm build - - name: Run Playwright Tests - run: pnpm exec playwright test - - uses: actions/upload-artifact@v4 - if: ${{ !cancelled() }} - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 From e58e8c55b4585352ec3323ff78b963d71c172ba3 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:07:31 +0200 Subject: [PATCH 26/40] generate before build --- packages/zitadel-client/turbo.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/zitadel-client/turbo.json b/packages/zitadel-client/turbo.json index 52e8c763..ea363690 100644 --- a/packages/zitadel-client/turbo.json +++ b/packages/zitadel-client/turbo.json @@ -6,6 +6,9 @@ "build": { "outputs": [ "dist/**" + ], + "dependsOn": [ + "@zitadel/proto#generate" ] } } From 087e81547222175106409802e75fe05240cb5542 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:16:22 +0200 Subject: [PATCH 27/40] fix conditions --- .github/workflows/test.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 786f990e..6e1a7a10 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,9 +57,9 @@ jobs: run: CYPRESS_INSTALL_BINARY=0 pnpm install # We build already here so we can fail fast if the build fails - - name: Run ZITADEL + - name: Build Production run: pnpm build - if: ${{ matrix.command }} == "test:acceptance" + if: ${{ matrix.command == 'test:acceptance' }} - run: | echo "CYPRESS_VERSION=$(pnpm list -r | grep cypress | cut -d ' ' -f 2)" >> $GITHUB_ENV @@ -72,11 +72,11 @@ jobs: key: ${{ runner.os }}-cypress-binary-${{ env.CYPRESS_VERSION }} restore-keys: | ${{ runner.os }}-cypress-binary- - if: ${{ matrix.command }} == "test:integration" + if: ${{ matrix.command == 'test:integration' }} - name: Install Cypress Browsers run: pnpm install - if: ${{ matrix.command }} == "test:integration" + if: ${{ matrix.command == 'test:integration' }} - uses: actions/cache@v4.0.2 name: Setup Playwright binary cache @@ -85,19 +85,19 @@ jobs: key: ${{ runner.os }}-playwright-binary-${{ env.PLAYWRIGHT_VERSION }} restore-keys: | ${{ runner.os }}-playwright-binary- - if: ${{ matrix.command }} == "test:acceptance" + if: ${{ matrix.command == 'test:acceptance' }} - name: Install Playwright Browsers run: sudo pnpm exec playwright install --with-deps - if: ${{ matrix.command }} == "test:acceptance" + if: ${{ matrix.command == 'test:acceptance' }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - if: ${{ matrix.command }} == "test:acceptance" + if: ${{ matrix.command == 'test:acceptance' }} - name: Run ZITADEL run: pnpm run-zitadel - if: ${{ matrix.command }} == "test:acceptance" + if: ${{ matrix.command == 'test:acceptance' }} - name: Check id: check From 90f13b210e29fd4644b25fb0e1773d7b7e2e2784 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:23:08 +0200 Subject: [PATCH 28/40] build before start --- .github/workflows/test.yml | 13 +++++------- apps/login/package.json | 41 +++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e1a7a10..456f4917 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,14 +56,8 @@ jobs: - name: Install Dependencies run: CYPRESS_INSTALL_BINARY=0 pnpm install - # We build already here so we can fail fast if the build fails - - name: Build Production - run: pnpm build - if: ${{ matrix.command == 'test:acceptance' }} - - - run: | - echo "CYPRESS_VERSION=$(pnpm list -r | grep cypress | cut -d ' ' -f 2)" >> $GITHUB_ENV - echo "PLAYWRIGHT_VERSION=$(npx playwright --version | cut -d ' ' -f 2)" >> $GITHUB_ENV + - run: echo "CYPRESS_VERSION=$(pnpm list -r | grep cypress | cut -d ' ' -f 2)" >> $GITHUB_ENV + if: ${{ matrix.command == 'test:integration' }} - uses: actions/cache@v4.0.2 name: Setup Cypress binary cache @@ -78,6 +72,9 @@ jobs: run: pnpm install if: ${{ matrix.command == 'test:integration' }} + - run: echo "PLAYWRIGHT_VERSION=$(npx playwright --version | cut -d ' ' -f 2)" >> $GITHUB_ENV + if: ${{ matrix.command == 'test:acceptance' }} + - uses: actions/cache@v4.0.2 name: Setup Playwright binary cache with: diff --git a/apps/login/package.json b/apps/login/package.json index 8863d361..83991432 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -1,7 +1,6 @@ { "name": "@zitadel/login", "private": true, - "type": "module", "scripts": { "dev": "next dev", "test": "concurrently --timings --kill-others-on-fail 'npm:test:unit' 'npm:test:integration'", @@ -22,6 +21,7 @@ "lint:fix": "prettier --write .", "lint-staged": "lint-staged", "build": "next build", + "prestart": "pnpm build", "start": "next start", "clean": "pnpm mock:destroy && rm -rf .turbo && rm -rf node_modules && rm -rf .next" }, @@ -32,19 +32,19 @@ "*": "prettier --write --ignore-unknown" }, "dependencies": { - "@headlessui/react": "^2.1.9", + "@headlessui/react": "^1.7.18", "@heroicons/react": "2.1.3", "@tailwindcss/forms": "0.5.7", "@vercel/analytics": "^1.2.2", "@zitadel/client": "workspace:*", + "@zitadel/next": "workspace:*", "@zitadel/node": "workspace:*", "@zitadel/proto": "workspace:*", + "@zitadel/react": "workspace:*", "clsx": "1.2.1", "copy-to-clipboard": "^3.3.3", - "deepmerge": "^4.3.1", "moment": "^2.29.4", - "next": "14.2.14", - "next-intl": "^3.20.0", + "next": "14.2.5", "next-themes": "^0.2.1", "nice-grpc": "2.0.1", "qrcode.react": "^3.1.0", @@ -55,12 +55,12 @@ "tinycolor2": "1.4.2" }, "devDependencies": { - "@bufbuild/buf": "^1.41.0", + "@bufbuild/buf": "^1.36.0", "@testing-library/jest-dom": "^6.4.5", - "@testing-library/react": "^16.0.1", + "@testing-library/react": "^16.0.0", "@types/ms": "0.7.34", - "@types/node": "22.5.5", - "@types/react": "18.3.7", + "@types/node": "22.1.0", + "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "@types/tinycolor2": "1.4.3", "@types/uuid": "^10.0.0", @@ -68,23 +68,22 @@ "@zitadel/prettier-config": "workspace:*", "@zitadel/tsconfig": "workspace:*", "autoprefixer": "10.4.20", - "concurrently": "^9.0.1", - "cypress": "^13.14.2", + "concurrently": "^8.1.0", + "cypress": "^13.13.2", "del-cli": "5.1.0", "env-cmd": "^10.1.0", "eslint-config-zitadel": "workspace:*", "grpc-tools": "1.12.4", - "jsdom": "^25.0.0", - "lint-staged": "15.2.10", + "lint-staged": "15.2.8", "make-dir-cli": "4.0.0", - "nodemon": "^3.1.5", - "postcss": "8.4.47", - "prettier-plugin-tailwindcss": "0.6.6", - "sass": "^1.79.1", - "start-server-and-test": "^2.0.8", - "tailwindcss": "3.4.13", - "ts-proto": "^2.2.0", - "typescript": "^5.6.2", + "nodemon": "^3.1.4", + "postcss": "8.4.41", + "prettier-plugin-tailwindcss": "0.6.5", + "sass": "^1.77.1", + "start-server-and-test": "^2.0.0", + "tailwindcss": "3.4.9", + "ts-proto": "^1.139.0", + "typescript": "^5.4.5", "zitadel-tailwind-config": "workspace:*" } } From 46fb2ea259e106e2b3a31d938021be7c66723719 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 18 Oct 2024 23:44:32 +0200 Subject: [PATCH 29/40] remove workspace packages --- apps/login/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/login/package.json b/apps/login/package.json index 83991432..16479b64 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -37,10 +37,8 @@ "@tailwindcss/forms": "0.5.7", "@vercel/analytics": "^1.2.2", "@zitadel/client": "workspace:*", - "@zitadel/next": "workspace:*", "@zitadel/node": "workspace:*", "@zitadel/proto": "workspace:*", - "@zitadel/react": "workspace:*", "clsx": "1.2.1", "copy-to-clipboard": "^3.3.3", "moment": "^2.29.4", From 083bf5a0a565b6fb1a6e62310fff0e96e8634a30 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:09:29 +0200 Subject: [PATCH 30/40] clean dependencies --- apps/login/package.json | 38 +-- pnpm-lock.yaml | 48 +-- tests-examples/demo-todo-app.spec.ts | 437 --------------------------- 3 files changed, 45 insertions(+), 478 deletions(-) delete mode 100644 tests-examples/demo-todo-app.spec.ts diff --git a/apps/login/package.json b/apps/login/package.json index 16479b64..9617300a 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -1,6 +1,7 @@ { "name": "@zitadel/login", "private": true, + "type": "module", "scripts": { "dev": "next dev", "test": "concurrently --timings --kill-others-on-fail 'npm:test:unit' 'npm:test:integration'", @@ -32,7 +33,7 @@ "*": "prettier --write --ignore-unknown" }, "dependencies": { - "@headlessui/react": "^1.7.18", + "@headlessui/react": "^2.1.9", "@heroicons/react": "2.1.3", "@tailwindcss/forms": "0.5.7", "@vercel/analytics": "^1.2.2", @@ -41,8 +42,10 @@ "@zitadel/proto": "workspace:*", "clsx": "1.2.1", "copy-to-clipboard": "^3.3.3", + "deepmerge": "^4.3.1", "moment": "^2.29.4", - "next": "14.2.5", + "next": "14.2.14", + "next-intl": "^3.20.0", "next-themes": "^0.2.1", "nice-grpc": "2.0.1", "qrcode.react": "^3.1.0", @@ -53,12 +56,12 @@ "tinycolor2": "1.4.2" }, "devDependencies": { - "@bufbuild/buf": "^1.36.0", + "@bufbuild/buf": "^1.41.0", "@testing-library/jest-dom": "^6.4.5", - "@testing-library/react": "^16.0.0", + "@testing-library/react": "^16.0.1", "@types/ms": "0.7.34", - "@types/node": "22.1.0", - "@types/react": "18.3.3", + "@types/node": "22.5.5", + "@types/react": "18.3.7", "@types/react-dom": "18.3.0", "@types/tinycolor2": "1.4.3", "@types/uuid": "^10.0.0", @@ -66,22 +69,23 @@ "@zitadel/prettier-config": "workspace:*", "@zitadel/tsconfig": "workspace:*", "autoprefixer": "10.4.20", - "concurrently": "^8.1.0", - "cypress": "^13.13.2", + "concurrently": "^9.0.1", + "cypress": "^13.14.2", "del-cli": "5.1.0", "env-cmd": "^10.1.0", "eslint-config-zitadel": "workspace:*", "grpc-tools": "1.12.4", - "lint-staged": "15.2.8", + "jsdom": "^25.0.0", + "lint-staged": "15.2.10", "make-dir-cli": "4.0.0", - "nodemon": "^3.1.4", - "postcss": "8.4.41", - "prettier-plugin-tailwindcss": "0.6.5", - "sass": "^1.77.1", - "start-server-and-test": "^2.0.0", - "tailwindcss": "3.4.9", - "ts-proto": "^1.139.0", - "typescript": "^5.4.5", + "nodemon": "^3.1.5", + "postcss": "8.4.47", + "prettier-plugin-tailwindcss": "0.6.6", + "sass": "^1.79.1", + "start-server-and-test": "^2.0.8", + "tailwindcss": "3.4.13", + "ts-proto": "^2.2.0", + "typescript": "^5.6.2", "zitadel-tailwind-config": "workspace:*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ec76ca2..8afc1642 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ importers: version: 1.48.1 '@types/node': specifier: ^22.7.5 - version: 22.7.5 + version: 22.7.6 '@vitejs/plugin-react': specifier: ^4.2.1 - version: 4.3.1(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) + version: 4.3.1(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1)) '@zitadel/prettier-config': specifier: workspace:* version: link:packages/zitadel-prettier-config @@ -49,10 +49,10 @@ importers: version: 5.6.2 vite-tsconfig-paths: specifier: ^5.0.1 - version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) + version: 5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1)) vitest: specifier: ^2.1.1 - version: 2.1.1(@types/node@22.7.5)(jsdom@25.0.0)(sass@1.79.1) + version: 2.1.1(@types/node@22.7.6)(jsdom@25.0.0)(sass@1.79.1) apps/login: dependencies: @@ -1281,8 +1281,8 @@ packages: '@types/node@22.5.5': resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} - '@types/node@22.7.5': - resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@22.7.6': + resolution: {integrity: sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -5622,7 +5622,7 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@22.7.5': + '@types/node@22.7.6': dependencies: undici-types: 6.19.8 @@ -5651,7 +5651,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 22.5.5 + '@types/node': 22.7.6 optional: true '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.6.2)': @@ -5705,14 +5705,14 @@ snapshots: '@vercel/git-hooks@1.0.0': {} - '@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1))': + '@vitejs/plugin-react@4.3.1(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))': dependencies: '@babel/core': 7.25.2 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1) transitivePeerDependencies: - supports-color @@ -5723,13 +5723,13 @@ snapshots: chai: 5.1.1 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1))': + '@vitest/mocker@2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1))': dependencies: '@vitest/spy': 2.1.1 estree-walker: 3.0.3 magic-string: 0.30.11 optionalDependencies: - vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1) '@vitest/pretty-format@2.1.1': dependencies: @@ -8212,7 +8212,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.5.5 + '@types/node': 22.7.6 long: 5.2.3 proxy-from-env@1.0.0: {} @@ -9066,12 +9066,12 @@ snapshots: core-util-is: 1.0.2 extsprintf: 1.3.0 - vite-node@2.1.1(@types/node@22.7.5)(sass@1.79.1): + vite-node@2.1.1(@types/node@22.7.6)(sass@1.79.1): dependencies: cac: 6.7.14 debug: 4.3.7(supports-color@5.5.0) pathe: 1.1.2 - vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1) transitivePeerDependencies: - '@types/node' - less @@ -9083,31 +9083,31 @@ snapshots: - supports-color - terser - vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)): + vite-tsconfig-paths@5.0.1(typescript@5.6.2)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1)): dependencies: debug: 4.3.6 globrex: 0.1.2 tsconfck: 3.1.1(typescript@5.6.2) optionalDependencies: - vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1) transitivePeerDependencies: - supports-color - typescript - vite@5.4.6(@types/node@22.7.5)(sass@1.79.1): + vite@5.4.6(@types/node@22.7.6)(sass@1.79.1): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.21.3 optionalDependencies: - '@types/node': 22.7.5 + '@types/node': 22.7.6 fsevents: 2.3.3 sass: 1.79.1 - vitest@2.1.1(@types/node@22.7.5)(jsdom@25.0.0)(sass@1.79.1): + vitest@2.1.1(@types/node@22.7.6)(jsdom@25.0.0)(sass@1.79.1): dependencies: '@vitest/expect': 2.1.1 - '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.5)(sass@1.79.1)) + '@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.6(@types/node@22.7.6)(sass@1.79.1)) '@vitest/pretty-format': 2.1.1 '@vitest/runner': 2.1.1 '@vitest/snapshot': 2.1.1 @@ -9122,11 +9122,11 @@ snapshots: tinyexec: 0.3.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.6(@types/node@22.7.5)(sass@1.79.1) - vite-node: 2.1.1(@types/node@22.7.5)(sass@1.79.1) + vite: 5.4.6(@types/node@22.7.6)(sass@1.79.1) + vite-node: 2.1.1(@types/node@22.7.6)(sass@1.79.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.7.5 + '@types/node': 22.7.6 jsdom: 25.0.0 transitivePeerDependencies: - less diff --git a/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts deleted file mode 100644 index 8641cb5f..00000000 --- a/tests-examples/demo-todo-app.spec.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { test, expect, type Page } from '@playwright/test'; - -test.beforeEach(async ({ page }) => { - await page.goto('https://demo.playwright.dev/todomvc'); -}); - -const TODO_ITEMS = [ - 'buy some cheese', - 'feed the cat', - 'book a doctors appointment' -] as const; - -test.describe('New Todo', () => { - test('should allow me to add todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create 1st todo. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Make sure the list only has one todo item. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0] - ]); - - // Create 2nd todo. - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - - // Make sure the list now has two todo items. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[1] - ]); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); - - test('should clear text input field when an item is added', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create one todo item. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Check that input is empty. - await expect(newTodo).toBeEmpty(); - await checkNumberOfTodosInLocalStorage(page, 1); - }); - - test('should append new items to the bottom of the list', async ({ page }) => { - // Create 3 items. - await createDefaultTodos(page); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - // Check test using different methods. - await expect(page.getByText('3 items left')).toBeVisible(); - await expect(todoCount).toHaveText('3 items left'); - await expect(todoCount).toContainText('3'); - await expect(todoCount).toHaveText(/3/); - - // Check all items in one call. - await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); - await checkNumberOfTodosInLocalStorage(page, 3); - }); -}); - -test.describe('Mark all as completed', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test.afterEach(async ({ page }) => { - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should allow me to mark all items as completed', async ({ page }) => { - // Complete all todos. - await page.getByLabel('Mark all as complete').check(); - - // Ensure all todos have 'completed' class. - await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - }); - - test('should allow me to clear the complete state of all items', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - // Check and then immediately uncheck. - await toggleAll.check(); - await toggleAll.uncheck(); - - // Should be no completed classes. - await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); - }); - - test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - await toggleAll.check(); - await expect(toggleAll).toBeChecked(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Uncheck first todo. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').uncheck(); - - // Reuse toggleAll locator and make sure its not checked. - await expect(toggleAll).not.toBeChecked(); - - await firstTodo.getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Assert the toggle all is checked again. - await expect(toggleAll).toBeChecked(); - }); -}); - -test.describe('Item', () => { - - test('should allow me to mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - // Check first item. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').check(); - await expect(firstTodo).toHaveClass('completed'); - - // Check second item. - const secondTodo = page.getByTestId('todo-item').nth(1); - await expect(secondTodo).not.toHaveClass('completed'); - await secondTodo.getByRole('checkbox').check(); - - // Assert completed class. - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).toHaveClass('completed'); - }); - - test('should allow me to un-mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const firstTodo = page.getByTestId('todo-item').nth(0); - const secondTodo = page.getByTestId('todo-item').nth(1); - const firstTodoCheckbox = firstTodo.getByRole('checkbox'); - - await firstTodoCheckbox.check(); - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await firstTodoCheckbox.uncheck(); - await expect(firstTodo).not.toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 0); - }); - - test('should allow me to edit an item', async ({ page }) => { - await createDefaultTodos(page); - - const todoItems = page.getByTestId('todo-item'); - const secondTodo = todoItems.nth(1); - await secondTodo.dblclick(); - await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); - await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); - - // Explicitly assert the new text value. - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2] - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); -}); - -test.describe('Editing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should hide other controls when editing', async ({ page }) => { - const todoItem = page.getByTestId('todo-item').nth(1); - await todoItem.dblclick(); - await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); - await expect(todoItem.locator('label', { - hasText: TODO_ITEMS[1], - })).not.toBeVisible(); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should save edits on blur', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should trim entered text', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should remove the item if an empty text string was entered', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[2], - ]); - }); - - test('should cancel edits on escape', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); - await expect(todoItems).toHaveText(TODO_ITEMS); - }); -}); - -test.describe('Counter', () => { - test('should display the current number of todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - await expect(todoCount).toContainText('1'); - - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - await expect(todoCount).toContainText('2'); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); -}); - -test.describe('Clear completed button', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - }); - - test('should display the correct text', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); - }); - - test('should remove completed items when clicked', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).getByRole('checkbox').check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(todoItems).toHaveCount(2); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should be hidden when there are no items that are completed', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); - }); -}); - -test.describe('Persistence', () => { - test('should persist its data', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const todoItems = page.getByTestId('todo-item'); - const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); - await firstTodoCheck.check(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - - // Ensure there is 1 completed item. - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - // Now reload. - await page.reload(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - }); -}); - -test.describe('Routing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - // make sure the app had a chance to save updated todos in storage - // before navigating to a new view, otherwise the items can get lost :( - // in some frameworks like Durandal - await checkTodosInLocalStorage(page, TODO_ITEMS[0]); - }); - - test('should allow me to display active items', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await expect(todoItem).toHaveCount(2); - await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should respect the back button', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await test.step('Showing all items', async () => { - await page.getByRole('link', { name: 'All' }).click(); - await expect(todoItem).toHaveCount(3); - }); - - await test.step('Showing active items', async () => { - await page.getByRole('link', { name: 'Active' }).click(); - }); - - await test.step('Showing completed items', async () => { - await page.getByRole('link', { name: 'Completed' }).click(); - }); - - await expect(todoItem).toHaveCount(1); - await page.goBack(); - await expect(todoItem).toHaveCount(2); - await page.goBack(); - await expect(todoItem).toHaveCount(3); - }); - - test('should allow me to display completed items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Completed' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(1); - }); - - test('should allow me to display all items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await page.getByRole('link', { name: 'Completed' }).click(); - await page.getByRole('link', { name: 'All' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(3); - }); - - test('should highlight the currently applied filter', async ({ page }) => { - await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); - - //create locators for active and completed links - const activeLink = page.getByRole('link', { name: 'Active' }); - const completedLink = page.getByRole('link', { name: 'Completed' }); - await activeLink.click(); - - // Page change - active items. - await expect(activeLink).toHaveClass('selected'); - await completedLink.click(); - - // Page change - completed items. - await expect(completedLink).toHaveClass('selected'); - }); -}); - -async function createDefaultTodos(page: Page) { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } -} - -async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).length === e; - }, expected); -} - -async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; - }, expected); -} - -async function checkTodosInLocalStorage(page: Page, title: string) { - return await page.waitForFunction(t => { - return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); - }, title); -} From 8290a6bae38659c5e5349950b4e8c32c466b48ae Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:11:42 +0200 Subject: [PATCH 31/40] no sudo --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 456f4917..a1868847 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -85,7 +85,7 @@ jobs: if: ${{ matrix.command == 'test:acceptance' }} - name: Install Playwright Browsers - run: sudo pnpm exec playwright install --with-deps + run: pnpm exec playwright install --with-deps if: ${{ matrix.command == 'test:acceptance' }} - name: Set up Docker Buildx From 3fc6118609296ef6ed5bf647f11922c0bb6fa46d Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:24:28 +0200 Subject: [PATCH 32/40] keep dir --- acceptance/pat/.gitignore | 3 ++- acceptance/pat/.gitkeep | 0 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 acceptance/pat/.gitkeep diff --git a/acceptance/pat/.gitignore b/acceptance/pat/.gitignore index f59ec20a..f0fa09f5 100644 --- a/acceptance/pat/.gitignore +++ b/acceptance/pat/.gitignore @@ -1 +1,2 @@ -* \ No newline at end of file +* +!.gitkeep \ No newline at end of file diff --git a/acceptance/pat/.gitkeep b/acceptance/pat/.gitkeep new file mode 100644 index 00000000..e69de29b From 7cde73f8795485e6baa452d84f28cc68739d28f9 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:27:39 +0200 Subject: [PATCH 33/40] fmt --- README.md | 1 + acceptance/tests/username-password.spec.ts | 16 +++++------ acceptance/tests/welcome.ts | 8 +++--- package.json | 1 + playwright.config.ts | 32 +++++++++++----------- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 9d6b6354..f1f8a930 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ ZITADEL_API_URL=https://zitadel-tlx3du.us1.zitadel.cloud ZITADEL_SERVICE_USER_ID=289106423158521850 ZITADEL_SERVICE_USER_TOKEN=1S6w48thfWFI2klgfwkCnhXJLf9FQ457E-_3H74ePQxfO3Af0Tm4V5Xi-ji7urIl_xbn-Rk ``` + Start the login application in dev mode: diff --git a/acceptance/tests/username-password.spec.ts b/acceptance/tests/username-password.spec.ts index 72f2d867..276a0390 100644 --- a/acceptance/tests/username-password.spec.ts +++ b/acceptance/tests/username-password.spec.ts @@ -1,12 +1,12 @@ -import { test, expect } from '@playwright/test'; +import { test } from "@playwright/test"; -test('username and password', async ({ page }) => { - await page.goto('/'); - const loginname = page.getByLabel('Loginname') +test("username and password", async ({ page }) => { + await page.goto("/"); + const loginname = page.getByLabel("Loginname"); await loginname.pressSequentially("zitadel-admin@zitadel.localhost"); - await loginname.press( 'Enter'); - const password = page.getByLabel('Password') + await loginname.press("Enter"); + const password = page.getByLabel("Password"); await password.pressSequentially("Password1!"); - await password.press( 'Enter'); - await page.getByText('Skip').click(); + await password.press("Enter"); + await page.getByText("Skip").click(); }); diff --git a/acceptance/tests/welcome.ts b/acceptance/tests/welcome.ts index 22734b0c..7ff6b7d1 100644 --- a/acceptance/tests/welcome.ts +++ b/acceptance/tests/welcome.ts @@ -1,6 +1,6 @@ -import { test } from '@playwright/test'; +import { test } from "@playwright/test"; -test('login is accessible', async ({ page }) => { - await page.goto('http://localhost:3000/'); - await page.getByRole('heading', { name: 'Welcome back!' }).isVisible(); +test("login is accessible", async ({ page }) => { + await page.goto("http://localhost:3000/"); + await page.getByRole("heading", { name: "Welcome back!" }).isVisible(); }); diff --git a/package.json b/package.json index 95a38ef5..774a7612 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "lint": "turbo run lint", "lint:fix": "turbo run lint:fix", "clean": "turbo run clean && rm -rf node_modules", + "format:fix": "prettier --write \"**/*.{ts,tsx,md}\"", "format": "prettier --check \"**/*.{ts,tsx,md}\"", "changeset": "changeset", "version-packages": "changeset version", diff --git a/playwright.config.ts b/playwright.config.ts index 9795c4ab..8bddf819 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from "@playwright/test"; /** * Read environment variables from file. @@ -12,7 +12,7 @@ import { defineConfig, devices } from '@playwright/test'; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - testDir: './acceptance/tests', + testDir: "./acceptance/tests", /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ @@ -22,28 +22,28 @@ export default defineConfig({ /* 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', + 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', + 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', + trace: "on-first-retry", }, /* Configure projects for major browsers */ projects: [ { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + name: "chromium", + use: { ...devices["Desktop Chrome"] }, }, { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, + name: "firefox", + use: { ...devices["Desktop Firefox"] }, }, -/* TODO: webkit fails. Is this a bug? + /* TODO: webkit fails. Is this a bug? { name: 'webkit', use: { ...devices['Desktop Safari'] }, @@ -72,10 +72,10 @@ export default defineConfig({ ], /* Run local dev server before starting the tests */ - webServer: { - command: 'pnpm start', - url: 'http://127.0.0.1:3000', - reuseExistingServer: !process.env.CI, - timeout: 5 * 60_000, - }, + webServer: { + command: "pnpm start", + url: "http://127.0.0.1:3000", + reuseExistingServer: !process.env.CI, + timeout: 5 * 60_000, + }, }); From 614bb5ddb17f1f066f9376d04bf8c90617c3bba6 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:35:29 +0200 Subject: [PATCH 34/40] debug path --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1868847..42d280b7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,6 +31,8 @@ jobs: - name: Checkout Repo uses: actions/checkout@v4.1.6 + - run : ls -la acceptance/pat + - name: Setup Node.js 20.x uses: actions/setup-node@v4.0.2 with: From edffb9929611793f63961432f78c614a42278466 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:36:58 +0200 Subject: [PATCH 35/40] run zitadel as root --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42d280b7..72296472 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,8 +31,6 @@ jobs: - name: Checkout Repo uses: actions/checkout@v4.1.6 - - run : ls -la acceptance/pat - - name: Setup Node.js 20.x uses: actions/setup-node@v4.0.2 with: @@ -95,7 +93,7 @@ jobs: if: ${{ matrix.command == 'test:acceptance' }} - name: Run ZITADEL - run: pnpm run-zitadel + run: ZITADEL_DEV_UID=root pnpm run-zitadel if: ${{ matrix.command == 'test:acceptance' }} - name: Check From 0459bea8dd8fb632d28b805d65bcf7f7b5768d3c Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 00:44:10 +0200 Subject: [PATCH 36/40] build --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72296472..8be38dee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -96,6 +96,10 @@ jobs: run: ZITADEL_DEV_UID=root pnpm run-zitadel if: ${{ matrix.command == 'test:acceptance' }} + - name: Install Playwright Browsers + run: pnpm build + if: ${{ matrix.command == 'test:acceptance' }} + - name: Check id: check run: pnpm ${{ matrix.command }} From bdfbd9466144a440142a366bee83f8ed58b1f0be Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 01:13:04 +0200 Subject: [PATCH 37/40] no prestart --- apps/login/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/login/package.json b/apps/login/package.json index 9617300a..8863d361 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -22,7 +22,6 @@ "lint:fix": "prettier --write .", "lint-staged": "lint-staged", "build": "next build", - "prestart": "pnpm build", "start": "next start", "clean": "pnpm mock:destroy && rm -rf .turbo && rm -rf node_modules && rm -rf .next" }, From 3ce170305599f50edffff3959aa8915db435e69e Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 01:16:59 +0200 Subject: [PATCH 38/40] start already built --- apps/login/package.json | 2 ++ package.json | 1 + playwright.config.ts | 2 +- turbo.json | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/login/package.json b/apps/login/package.json index 8863d361..54176632 100644 --- a/apps/login/package.json +++ b/apps/login/package.json @@ -22,7 +22,9 @@ "lint:fix": "prettier --write .", "lint-staged": "lint-staged", "build": "next build", + "prestart": "pnpm build", "start": "next start", + "start:built": "next start", "clean": "pnpm mock:destroy && rm -rf .turbo && rm -rf node_modules && rm -rf .next" }, "git": { diff --git a/package.json b/package.json index 774a7612..6b5e27cc 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "build": "turbo run build", "test": "turbo run test", "start": "turbo run start", + "start:built": "turbo run start:built", "test:unit": "turbo run test:unit -- --passWithNoTests", "test:integration": "turbo run test:integration", "test:acceptance": "pnpm exec playwright test", diff --git a/playwright.config.ts b/playwright.config.ts index 8bddf819..bf73cb21 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -73,7 +73,7 @@ export default defineConfig({ /* Run local dev server before starting the tests */ webServer: { - command: "pnpm start", + command: "pnpm start:built", url: "http://127.0.0.1:3000", reuseExistingServer: !process.env.CI, timeout: 5 * 60_000, diff --git a/turbo.json b/turbo.json index e2412dfe..a98ff872 100644 --- a/turbo.json +++ b/turbo.json @@ -22,6 +22,7 @@ "build": {}, "test": {}, "start": {}, + "start:built": {}, "test:unit": {}, "test:integration": {}, "test:watch": { From cc53c44c2089f43b07ae3906c9dc2b8df6be4ad3 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 01:27:25 +0200 Subject: [PATCH 39/40] update test --- acceptance/tests/username-password.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/tests/username-password.spec.ts b/acceptance/tests/username-password.spec.ts index 276a0390..23b22f4b 100644 --- a/acceptance/tests/username-password.spec.ts +++ b/acceptance/tests/username-password.spec.ts @@ -8,5 +8,5 @@ test("username and password", async ({ page }) => { const password = page.getByLabel("Password"); await password.pressSequentially("Password1!"); await password.press("Enter"); - await page.getByText("Skip").click(); + await page.getByRole("heading", {name: "Welcome ZITADEL Admin!"}).click(); }); From bfd8a7c9e1697b2aa21feed4968c4a0fa56daf60 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Sat, 19 Oct 2024 01:30:20 +0200 Subject: [PATCH 40/40] fmt --- acceptance/tests/username-password.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/tests/username-password.spec.ts b/acceptance/tests/username-password.spec.ts index 23b22f4b..31d16535 100644 --- a/acceptance/tests/username-password.spec.ts +++ b/acceptance/tests/username-password.spec.ts @@ -8,5 +8,5 @@ test("username and password", async ({ page }) => { const password = page.getByLabel("Password"); await password.pressSequentially("Password1!"); await password.press("Enter"); - await page.getByRole("heading", {name: "Welcome ZITADEL Admin!"}).click(); + await page.getByRole("heading", { name: "Welcome ZITADEL Admin!" }).click(); });