From 1c5780fa08f1d33b43acf80bea83aa2afe487637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:09:39 +0100 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=94=A7=20Add=20mailcatcher=20to=20f?= =?UTF-8?q?rontend=20.env?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.env | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/.env b/frontend/.env index 5934e2e7d2..27fcbfe8c8 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1 +1,2 @@ VITE_API_URL=http://localhost:8000 +MAILCATCHER_HOST=http://localhost:1080 From cd040a1d4d4b0d072063914b5d7a749322a1cb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:10:49 +0100 Subject: [PATCH 02/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Use=20env=20vars=20f?= =?UTF-8?q?or=20Playwright=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/playwright.config.ts | 2 +- frontend/tests/reset-password.spec.ts | 4 ++-- frontend/tests/utils/mailcatcher.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index dcdd6fec81..9d4a9823ec 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -1,11 +1,11 @@ import { defineConfig, devices } from '@playwright/test'; +import 'dotenv/config' /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ -// require('dotenv').config(); /** * See https://playwright.dev/docs/test-configuration. diff --git a/frontend/tests/reset-password.spec.ts b/frontend/tests/reset-password.spec.ts index 88ec798791..47613d983b 100644 --- a/frontend/tests/reset-password.spec.ts +++ b/frontend/tests/reset-password.spec.ts @@ -50,7 +50,7 @@ test("User can reset password successfully using the link", async ({ timeout: 5000, }) - await page.goto(`http://localhost:1080/messages/${emailData.id}.html`) + await page.goto(`${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`) const selector = 'a[href*="/reset-password?token="]' @@ -103,7 +103,7 @@ test("Weak new password validation", async ({ page, request }) => { timeout: 5000, }) - await page.goto(`http://localhost:1080/messages/${emailData.id}.html`) + await page.goto(`${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`) const selector = 'a[href*="/reset-password?token="]' let url = await page.getAttribute(selector, "href") diff --git a/frontend/tests/utils/mailcatcher.ts b/frontend/tests/utils/mailcatcher.ts index 601ce434fb..049792d0c8 100644 --- a/frontend/tests/utils/mailcatcher.ts +++ b/frontend/tests/utils/mailcatcher.ts @@ -10,7 +10,7 @@ async function findEmail({ request, filter, }: { request: APIRequestContext; filter?: (email: Email) => boolean }) { - const response = await request.get("http://localhost:1080/messages") + const response = await request.get(`${process.env.MAILCATCHER_HOST}/messages`) let emails = await response.json() From bbdf2ff5242588eb4002fcc49cc7d84d2d050e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:12:11 +0100 Subject: [PATCH 03/15] =?UTF-8?q?=F0=9F=94=A7=20Update=20tsconfig=20with?= =?UTF-8?q?=20Playwright=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index baadbb9fb1..355a2a920b 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src", "*.ts", "**/*.ts"], + "include": ["src/**/*.ts", "tests/**/*.ts", "playwright.config.ts"], "references": [{ "path": "./tsconfig.node.json" }] } From c9ab658bfcea8edd9d64fbfa7c9183799fae58c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:13:50 +0100 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=8E=A8=20Format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/tests/reset-password.spec.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/tests/reset-password.spec.ts b/frontend/tests/reset-password.spec.ts index 47613d983b..94671b84fe 100644 --- a/frontend/tests/reset-password.spec.ts +++ b/frontend/tests/reset-password.spec.ts @@ -50,7 +50,9 @@ test("User can reset password successfully using the link", async ({ timeout: 5000, }) - await page.goto(`${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`) + await page.goto( + `${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`, + ) const selector = 'a[href*="/reset-password?token="]' @@ -103,7 +105,9 @@ test("Weak new password validation", async ({ page, request }) => { timeout: 5000, }) - await page.goto(`${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`) + await page.goto( + `${process.env.MAILCATCHER_HOST}/messages/${emailData.id}.html`, + ) const selector = 'a[href*="/reset-password?token="]' let url = await page.getAttribute(selector, "href") From 340d603bdcf9a63199f2140d0bcac49d2f671fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:43:38 +0100 Subject: [PATCH 05/15] =?UTF-8?q?=F0=9F=8E=A8=20Fix=20type=20annotations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/routes/_layout/admin.tsx | 2 +- frontend/src/routes/_layout/items.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/_layout/admin.tsx b/frontend/src/routes/_layout/admin.tsx index b96fbc3799..dde6247896 100644 --- a/frontend/src/routes/_layout/admin.tsx +++ b/frontend/src/routes/_layout/admin.tsx @@ -49,7 +49,7 @@ function UsersTable() { const { page } = Route.useSearch() const navigate = useNavigate({ from: Route.fullPath }) const setPage = (page: number) => - navigate({ search: (prev) => ({ ...prev, page }) }) + navigate({ search: (prev: {[key: string]: string}) => ({ ...prev, page }) }) const { data: users, diff --git a/frontend/src/routes/_layout/items.tsx b/frontend/src/routes/_layout/items.tsx index 9216d3cbb4..93f7ad5048 100644 --- a/frontend/src/routes/_layout/items.tsx +++ b/frontend/src/routes/_layout/items.tsx @@ -45,7 +45,7 @@ function ItemsTable() { const { page } = Route.useSearch() const navigate = useNavigate({ from: Route.fullPath }) const setPage = (page: number) => - navigate({ search: (prev) => ({ ...prev, page }) }) + navigate({ search: (prev: {[key: string]: string}) => ({ ...prev, page }) }) const { data: items, From ad37492e631d2e43a5726129b52cf30944660243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:48:39 +0100 Subject: [PATCH 06/15] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Config=20playwright?= =?UTF-8?q?=20to=20output=20blob=20reports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/playwright.config.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 9d4a9823ec..b9d5a51246 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -1,7 +1,6 @@ import { defineConfig, devices } from '@playwright/test'; import 'dotenv/config' - /** * Read environment variables from file. * https://github.com/motdotla/dotenv @@ -21,7 +20,7 @@ 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: process.env.CI ? 'blob' : '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('/')`. */ From d0ea5256a5243ada9367ff881ee9bb30df61fe56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:49:19 +0100 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=94=A7=20Add=20Dockerfile=20for=20P?= =?UTF-8?q?laywright?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/Dockerfile.playwright | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 frontend/Dockerfile.playwright diff --git a/frontend/Dockerfile.playwright b/frontend/Dockerfile.playwright new file mode 100644 index 0000000000..e76ac15f65 --- /dev/null +++ b/frontend/Dockerfile.playwright @@ -0,0 +1,13 @@ +FROM node:20 + +WORKDIR /app + +COPY package*.json /app/ + +RUN npm install + +RUN npx -y playwright install --with-deps + +COPY ./ /app/ + +ARG VITE_API_URL=${VITE_API_URL} From 27d1362bcf457c9be118a20ad62469d0c6a825a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:49:45 +0100 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=94=A7=20Update=20Docker=20Compose,?= =?UTF-8?q?=20include=20Playwright?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.override.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 3792f1f026..f7116667de 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -102,6 +102,26 @@ services: - VITE_API_URL=http://localhost:8000 - NODE_ENV=development + playwright: + build: + context: ./frontend + dockerfile: Dockerfile.playwright + args: + - VITE_API_URL=http://backend:8000 + - NODE_ENV=production + ipc: host + environment: + - VITE_API_URL=http://backend:8000 + - MAILCATCHER_HOST=http://mailcatcher:1080 + # For the reports when run locally + - PLAYWRIGHT_HTML_HOST=0.0.0.0 + - CI=${CI} + volumes: + - ./frontend/blob-report:/app/blob-report + - ./frontend/test-results:/app/test-results + ports: + - 9323:9323 + networks: traefik-public: # For local dev, don't expect an external Traefik network From 0ffc45202c0a49634c299b23172a03cea384b9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:50:07 +0100 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=91=B7=20Update=20Docker=20Compose?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-docker-compose.yml b/.github/workflows/test-docker-compose.yml index d8a392342a..0f4fa5f8f3 100644 --- a/.github/workflows/test-docker-compose.yml +++ b/.github/workflows/test-docker-compose.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - run: docker compose build - run: docker compose down -v --remove-orphans - - run: docker compose up -d --wait + - run: docker compose up -d --wait backend frontend builder adminer - name: Test backend is up run: curl http://localhost:8000/api/v1/utils/health-check - name: Test frontend is up From 5440b3aef8ba145001626b8e00afc243b2dda608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:51:22 +0100 Subject: [PATCH 10/15] =?UTF-8?q?=F0=9F=91=B7=20Update=20Playwright=20work?= =?UTF-8?q?flow=20to=20use=20Docker=20Compose=20and=20shards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/playwright.yml | 85 ++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 16 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index a884800227..3114106fb2 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -16,10 +16,36 @@ on: default: 'false' jobs: + changes: + runs-on: ubuntu-latest + # Set job outputs to values from filter step + outputs: + changed: ${{ steps.filter.outputs.changed }} + steps: + - uses: actions/checkout@v4 + # For pull requests it's not necessary to checkout the code but for the main branch it is + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + changed: + - backend/** + - frontend/** + - .env + - docker-compose*.yml + - .github/workflows/playwright.yml - test: + test-playwright: + needs: + - changes + if: ${{ needs.changes.outputs.changed == 'true' }} timeout-minutes: 60 runs-on: ubuntu-latest + strategy: + matrix: + shardIndex: [1, 2, 3, 4] + shardTotal: [4] + fail-fast: false steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -33,35 +59,62 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - - name: Install dependencies - run: npm ci - working-directory: frontend - - name: Install Playwright Browsers - run: npx playwright install --with-deps - working-directory: frontend - run: docker compose build - run: docker compose down -v --remove-orphans - - run: docker compose up -d --wait backend mailcatcher + - run: docker compose up -d --wait backend - name: Run Playwright tests - run: npx playwright test --fail-on-flaky-tests --trace=retain-on-failure - working-directory: frontend + run: docker compose run --rm playwright npx playwright test --fail-on-flaky-tests --trace=retain-on-failure --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - run: docker compose down -v --remove-orphans - - uses: actions/upload-artifact@v4 - if: always() + - name: Upload blob report to GitHub Actions Artifacts + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: blob-report-${{ matrix.shardIndex }} + path: frontend/blob-report + include-hidden-files: true + retention-days: 1 + + merge-playwright-reports: + needs: + - test-playwright + - changes + # Merge reports after playwright-tests, even if some shards have failed + if: ${{ !cancelled() && needs.changes.outputs.changed == 'true' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Install dependencies + run: npm ci + working-directory: frontend + - name: Download blob reports from GitHub Actions Artifacts + uses: actions/download-artifact@v4 + with: + path: frontend/all-blob-reports + pattern: blob-report-* + merge-multiple: true + - name: Merge into HTML Report + run: npx playwright merge-reports --reporter html ./all-blob-reports + working-directory: frontend + - name: Upload HTML report + uses: actions/upload-artifact@v4 with: - name: playwright-report - path: frontend/playwright-report/ + name: html-report--attempt-${{ github.run_attempt }} + path: frontend/playwright-report retention-days: 30 include-hidden-files: true # https://github.com/marketplace/actions/alls-green#why - e2e-alls-green: # This job does nothing and is only used for the branch protection + alls-green-playwright: # This job does nothing and is only used for the branch protection if: always() needs: - - test + - test-playwright runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} + allowed-skips: test-playwright From 3dc9c4fb64047cd8dc450fdf3aab7aa5de6ea269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:54:05 +0100 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=94=A7=20Update=20test=20Docker=20C?= =?UTF-8?q?ompose?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-docker-compose.yml b/.github/workflows/test-docker-compose.yml index 0f4fa5f8f3..17792ede50 100644 --- a/.github/workflows/test-docker-compose.yml +++ b/.github/workflows/test-docker-compose.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - run: docker compose build - run: docker compose down -v --remove-orphans - - run: docker compose up -d --wait backend frontend builder adminer + - run: docker compose up -d --wait backend frontend adminer - name: Test backend is up run: curl http://localhost:8000/api/v1/utils/health-check - name: Test frontend is up From 9a59df439fa26f326502c4a7eb1d412f8bd6f285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 21:56:23 +0100 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=94=A7=20Add=20.env=20file=20to=20P?= =?UTF-8?q?laywright?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.override.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index f7116667de..9c75687b2d 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -110,6 +110,8 @@ services: - VITE_API_URL=http://backend:8000 - NODE_ENV=production ipc: host + env_file: + - .env environment: - VITE_API_URL=http://backend:8000 - MAILCATCHER_HOST=http://mailcatcher:1080 From 625d08d6cb4cde9b66a63746592aceb3c6c8e8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 22:33:35 +0100 Subject: [PATCH 13/15] =?UTF-8?q?=F0=9F=94=A7=20Update=20Docker=20Compose?= =?UTF-8?q?=20for=20Playwright=20to=20depend=20on=20backend=20and=20mailca?= =?UTF-8?q?tcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.override.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 9c75687b2d..0751abe901 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -110,6 +110,9 @@ services: - VITE_API_URL=http://backend:8000 - NODE_ENV=production ipc: host + depends_on: + - backend + - mailcatcher env_file: - .env environment: From 053e6383c6cba39f515a2a377f8c404711d77bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 22:34:32 +0100 Subject: [PATCH 14/15] =?UTF-8?q?=F0=9F=91=B7=20Update=20Playwright=20CI?= =?UTF-8?q?=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/playwright.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 3114106fb2..4e951aac7f 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -61,7 +61,7 @@ jobs: limit-access-to-actor: true - run: docker compose build - run: docker compose down -v --remove-orphans - - run: docker compose up -d --wait backend + # - run: docker compose up -d --wait backend - name: Run Playwright tests run: docker compose run --rm playwright npx playwright test --fail-on-flaky-tests --trace=retain-on-failure --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - run: docker compose down -v --remove-orphans From be999a86347d19f0ef830cba17b58b9960208de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 25 Oct 2024 22:51:25 +0100 Subject: [PATCH 15/15] =?UTF-8?q?=F0=9F=94=A5=20Remove=20unneeded=20Docker?= =?UTF-8?q?=20Compose=20run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/playwright.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 4e951aac7f..8c741221f7 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -61,7 +61,6 @@ jobs: limit-access-to-actor: true - run: docker compose build - run: docker compose down -v --remove-orphans - # - run: docker compose up -d --wait backend - name: Run Playwright tests run: docker compose run --rm playwright npx playwright test --fail-on-flaky-tests --trace=retain-on-failure --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - run: docker compose down -v --remove-orphans