From b50e5f6dc3cfb979149a42ffad7ee6be99b47f0f Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Sat, 29 Aug 2026 12:22:08 +0200 Subject: [PATCH] chore(test): Align playwright setup with other repos Signed-off-by: Louis Chmn --- .github/workflows/playwright.yml | 230 ++++++++++++++---- package-lock.json | 146 ++--------- package.json | 5 +- playwright.config.ts | 57 ++--- .../playwright}/e2e/admin-settings.spec.ts | 0 .../playwright}/e2e/app-page.spec.ts | 2 - tests/playwright/merge.config.ts | 11 + tests/playwright/start-nextcloud-server.js | 48 ++++ .../playwright}/start-nextcloud-server.mjs | 0 .../playwright}/support/fixtures.ts | 0 .../playwright}/support/helpers.ts | 0 .../playwright}/support/setup.ts | 0 12 files changed, 287 insertions(+), 212 deletions(-) rename {playwright => tests/playwright}/e2e/admin-settings.spec.ts (100%) rename {playwright => tests/playwright}/e2e/app-page.spec.ts (95%) create mode 100644 tests/playwright/merge.config.ts create mode 100644 tests/playwright/start-nextcloud-server.js rename {playwright => tests/playwright}/start-nextcloud-server.mjs (100%) rename {playwright => tests/playwright}/support/fixtures.ts (100%) rename {playwright => tests/playwright}/support/helpers.ts (100%) rename {playwright => tests/playwright}/support/setup.ts (100%) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 88771633a..02fbb79ed 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,67 +1,189 @@ # SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors # SPDX-License-Identifier: MIT + +# This workflow runs Playwright tests on pull requests to the master and stable branches. +# It expects the following npm scripts to be defined in package.json: +# - "playwright": runs the Playwright tests +# - "playwright:install-ci": installs the Playwright browsers for CI (optional) +# +# If you only use the "Desktop Chrome" browser with "channel: chrome" in your Playwright config, +# you can skip the "playwright:install-ci" script as the GitHub Actions runner already has Chrome Browser installed. +# +# For merging the reports, it expects a Playwright merge config file at tests/playwright/merge.config.ts. +# You can adjust the path in the "Merge into HTML Report" step if you have a different location for the merge config file. +# The default configuration would look like this: +# ```js +# export default { +# testDir: 'tests/playwright/e2e', // path to your Playwright tests +# reporter: [['html', { open: 'never' }]], +# } +# ``` + name: Playwright Tests on: pull_request: - branches: [master] + branches: + - master + - stable35 + - stable34 + - stable33 permissions: contents: read -concurrency: - group: playwright-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - jobs: - test: - timeout-minutes: 60 + playwright-setup: + timeout-minutes: 10 + name: Playwright setup + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Read package.json + uses: nextcloud-libraries/parse-package-engines-action@122ae05d4257008180a514e1ddeb0c1b9d094bdd # v0.1.0 + id: versions + - name: Set up node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: ${{ steps.versions.outputs.node-version }} + - name: Set up npm + run: npm i -g 'npm@${{ steps.versions.outputs.package-manager-version }}' + - name: Install dependencies and build + run: | + npm ci + npm run build --if-present + - name: Save context + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + key: playwright-context-${{ github.run_id }} + path: ./ + + playwright-tests: + needs: [playwright-setup] + timeout-minutes: 30 + name: Playwright tests ${{ matrix.shardIndex }} / ${{ matrix.shardTotal }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shardIndex: [1, 2] # adjust to your needs + shardTotal: [2] + outputs: + node-version: ${{ steps.versions.outputs.node-version }} + package-manager-version: ${{ steps.versions.outputs.package-manager-version }} + + steps: + - name: Restore context + id: cache + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + key: playwright-context-${{ github.run_id }} + path: ./ + + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + if: steps.cache.outputs.cache-hit != 'true' + with: + persist-credentials: false + + - name: Read package.json + uses: nextcloud-libraries/parse-package-engines-action@122ae05d4257008180a514e1ddeb0c1b9d094bdd # v0.1.0 + id: versions + + - name: Set up node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: ${{ steps.versions.outputs.node-version }} + + - name: Set up npm + run: npm i -g 'npm@${{ steps.versions.outputs.package-manager-version }}' + + - name: Install dependencies and build + if: steps.cache.outputs.cache-hit != 'true' + run: | + npm ci + npm run build --if-present + + - name: Install Playwright browsers + run: npm run playwright:install-ci --if-present + + - name: Run Playwright tests + run: npm run playwright -- --shard='${{ matrix.shardIndex }}/${{ matrix.shardTotal }}' + + - name: Upload blob report to GitHub Actions Artifacts + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: blob-report-${{ matrix.shardIndex }} + path: blob-report + retention-days: 1 + + merge-reports: + # Merge reports after playwright-tests, even if some shards have failed + if: ${{ !cancelled() }} + needs: [playwright-tests] + + runs-on: ubuntu-latest-low + steps: + - name: Restore context + id: cache + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + key: playwright-context-${{ github.run_id }} + path: ./ + + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + if: steps.cache.outputs.cache-hit != 'true' + with: + persist-credentials: false + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + if: steps.cache.outputs.cache-hit != 'true' + with: + node-version: ${{ needs.playwright-tests.outputs.node-version }} + + - name: Set up npm + if: steps.cache.outputs.cache-hit != 'true' + run: npm i -g 'npm@${{ needs.playwright-tests.outputs.package-manager-version }}' + + - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Download blob reports from GitHub Actions Artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: all-blob-reports + pattern: blob-report-* + merge-multiple: true + + - name: Merge into HTML Report + run: npx playwright merge-reports --config tests/playwright/merge.config.ts --reporter html,github ./all-blob-reports + + - name: Upload HTML report + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: html-report--attempt-${{ github.run_attempt }} + path: playwright-report + retention-days: 7 + + - name: How to show the logs + run: | + echo 'To view the report:' + echo ' 1. Extract the folder from the zip file' + echo ' 2. run "npx playwright show-report name-of-my-extracted-playwright-report"' + + summary: + permissions: + contents: none + runs-on: ubuntu-latest-low + needs: [playwright-tests] + + if: always() + + name: playwright-test-summary + steps: - - name: Checkout app - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - persist-credentials: false - - - name: Check composer.json - id: check_composer - uses: andstor/file-existence-action@558493d6c74bf472d87c84eab196434afc2fa029 # v2 - with: - files: 'composer.json' - - - name: Install composer dependencies - if: steps.check_composer.outputs.files_exists == 'true' - run: composer install --no-dev - - - name: Read package.json node and npm engines version - uses: skjnldsv/read-package-engines-version-actions@06d6baf7d8f41934ab630e97d9e6c0bc9c9ac5e4 # v3 - id: versions - with: - fallbackNode: '^22' - fallbackNpm: '^10' - - - name: Set up node ${{ steps.versions.outputs.nodeVersion }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version: ${{ steps.versions.outputs.nodeVersion }} - - - name: Set up npm ${{ steps.versions.outputs.npmVersion }} - run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}" - - - name: Install node dependencies & build app - run: | - npm ci - npm run build --if-present - - - name: Install Playwright Browsers - run: npx playwright install chromium --only-shell - - - name: Run Playwright tests - run: npx playwright test - - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - if: always() - with: - name: playwright-report - path: playwright-report/ - retention-days: 30 + - name: Summary status + run: if ${{ needs.playwright-tests.result != 'success' }}; then exit 1; fi \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4b3f27719..8bea13c68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@nextcloud/e2e-test-server": "^0.5.1", "@nextcloud/eslint-config": "^9.0.0", "@nextcloud/vite-config": "^2.5.2", - "@playwright/test": "^1.60.0", + "@playwright/test": "^1.62.1", "@vitejs/plugin-vue": "^6.0.7", "@vitest/coverage-v8": "^4.1.6", "@vue/test-utils": "^2.4.6", @@ -452,7 +452,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -469,7 +468,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -486,7 +484,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -503,7 +500,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -520,7 +516,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -537,7 +532,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -554,7 +548,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -571,7 +564,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -588,7 +580,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -605,7 +596,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -622,7 +612,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -639,7 +628,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -656,7 +644,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -673,7 +660,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -690,7 +676,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -707,7 +692,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -724,7 +708,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -741,7 +724,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -758,7 +740,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -775,7 +756,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -792,7 +772,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -809,7 +788,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -826,7 +804,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -843,7 +820,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -860,7 +836,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -877,7 +852,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2389,7 +2363,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -2430,7 +2403,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2452,7 +2424,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2474,7 +2445,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2496,7 +2466,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2518,7 +2487,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2540,7 +2508,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2562,7 +2529,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2584,7 +2550,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2606,7 +2571,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2628,7 +2592,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2650,7 +2613,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2672,7 +2634,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2694,7 +2655,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2721,19 +2681,19 @@ } }, "node_modules/@playwright/test": { - "version": "1.61.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", - "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.61.1" + "playwright": "1.62.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@protobufjs/aspromise": { @@ -2884,7 +2844,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -2897,7 +2856,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -2910,7 +2868,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -2923,7 +2880,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -2936,7 +2892,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -2949,7 +2904,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -2962,7 +2916,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -2975,7 +2928,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -2988,7 +2940,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3001,7 +2952,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3014,7 +2964,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3027,7 +2976,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3040,7 +2988,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3053,7 +3000,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3066,7 +3012,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3079,7 +3024,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3092,7 +3036,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3105,7 +3048,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3118,7 +3060,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -3131,7 +3072,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -3144,7 +3084,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openharmony" @@ -3157,7 +3096,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -3170,7 +3108,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -3183,7 +3120,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -3196,7 +3132,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -3507,7 +3442,7 @@ "version": "26.0.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.0.1.tgz", "integrity": "sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~8.3.0" @@ -4833,7 +4768,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "optional": true, "peer": true, @@ -5251,7 +5185,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -5860,7 +5794,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, "license": "Apache-2.0", "optional": true, "peer": true, @@ -6782,7 +6715,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "optional": true, "peer": true, @@ -6971,7 +6903,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -7429,7 +7360,7 @@ "version": "5.1.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", - "dev": true, + "devOptional": true, "peer": true }, "node_modules/import-lazy": { @@ -7574,7 +7505,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7613,7 +7544,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -7653,7 +7584,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "optional": true, "peer": true, @@ -8931,7 +8861,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "optional": true, "peer": true, @@ -8947,7 +8876,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, "optional": true, "peer": true, "engines": { @@ -9161,7 +9089,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "license": "MIT", "optional": true, "peer": true @@ -9815,35 +9742,35 @@ } }, "node_modules/playwright": { - "version": "1.61.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", - "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.61.1" + "playwright-core": "1.62.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.61.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", - "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/playwright/node_modules/fsevents": { @@ -10116,7 +10043,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "engines": { @@ -10498,7 +10425,7 @@ "version": "1.90.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -11388,7 +11315,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "optional": true, "peer": true, @@ -11605,7 +11531,7 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unified": { @@ -12092,7 +12018,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "aix" @@ -12108,7 +12033,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -12124,7 +12048,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -12140,7 +12063,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "android" @@ -12156,7 +12078,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -12172,7 +12093,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -12188,7 +12108,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -12204,7 +12123,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -12220,7 +12138,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12236,7 +12153,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12252,7 +12168,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12268,7 +12183,6 @@ "cpu": [ "loong64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12284,7 +12198,6 @@ "cpu": [ "mips64el" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12300,7 +12213,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12316,7 +12228,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12332,7 +12243,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12348,7 +12258,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -12364,7 +12273,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -12380,7 +12288,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -12396,7 +12303,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -12412,7 +12318,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -12428,7 +12333,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "openharmony" @@ -12444,7 +12348,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "sunos" @@ -12460,7 +12363,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -12476,7 +12378,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -12492,7 +12393,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" diff --git a/package.json b/package.json index 554bc37a9..ad2949e34 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,9 @@ "dev": "NODE_ENV=development vite --mode development build", "lint": "eslint", "lint:fix": "eslint --fix", - "start:nextcloud": "node playwright/start-nextcloud-server.mjs", + "playwright": "playwright test", "test": "LANG=C vitest", "test:coverage": "LANG=C vitest run --coverage", - "test:e2e": "playwright test", "ts:check": "vue-tsc --noEmit", "watch": "NODE_ENV=development vite --mode development build --watch" }, @@ -44,7 +43,7 @@ "@nextcloud/e2e-test-server": "^0.5.1", "@nextcloud/eslint-config": "^9.0.0", "@nextcloud/vite-config": "^2.5.2", - "@playwright/test": "^1.60.0", + "@playwright/test": "^1.62.1", "@vitejs/plugin-vue": "^6.0.7", "@vitest/coverage-v8": "^4.1.6", "@vue/test-utils": "^2.4.6", diff --git a/playwright.config.ts b/playwright.config.ts index fc9652213..9ac92cb6a 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,53 +1,50 @@ -/*! +/* * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ +/// import { defineConfig, devices } from '@playwright/test' -// See https://playwright.dev/docs/test-configuration export default defineConfig({ - testDir: './playwright/e2e', - - /* Run tests in files in parallel */ + testDir: './tests/playwright/e2e', 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. */ + retries: process.env.CI ? 1 : 0, workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: process.env.CI ? 'github' : 'html', - + timeout: process.env.CI ? 45_000 : undefined, // on CI allow 1.5x the default timeout to compensate for shared server resources + reporter: process.env.CI ? [['blob'], ['dot'], ['github']] : 'html', use: { - /* Base URL so tests can navigate with relative paths, e.g. page.goto('settings/admin/sharing') */ - baseURL: 'http://localhost:8089/index.php/', - /* Collect a trace when retrying a failed test. See https://playwright.dev/docs/trace-viewer */ + baseURL: 'http://localhost:8042/index.php/', trace: 'on-first-retry', }, - projects: [ - // One-off setup: enable circles and apply test config in the container. - { - name: 'setup', - testDir: './playwright/support', - testMatch: /setup\.ts$/, - }, { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - dependencies: ['setup'], + name: 'default', + use: { + ...devices['Desktop Chrome'], + channel: process.env.CI + ? 'chrome' // on CI use the chrome browser provided by the GitHub Actions runner + : 'chromium', // locally use the default playwright chromium browser + }, }, ], webServer: { - // Spins up a throwaway Nextcloud container with circles mounted (see start-nextcloud-server.mjs). - command: 'npm run start:nextcloud', - reuseExistingServer: !process.env.CI, - url: 'http://127.0.0.1:8089', + command: 'node tests/playwright/start-nextcloud-server.js', + env: { + NEXTCLOUD_PORT: '8042', + }, stderr: 'pipe', stdout: 'pipe', - timeout: 5 * 60 * 1000, // up to 5 minutes for first-run container creation + gracefulShutdown: { + signal: 'SIGTERM', + timeout: 10_000, + }, + reuseExistingServer: !process.env.CI, + timeout: 300_000, + wait: { + stdout: /Nextcloud container ready to run Playwright tests/, + }, }, }) diff --git a/playwright/e2e/admin-settings.spec.ts b/tests/playwright/e2e/admin-settings.spec.ts similarity index 100% rename from playwright/e2e/admin-settings.spec.ts rename to tests/playwright/e2e/admin-settings.spec.ts diff --git a/playwright/e2e/app-page.spec.ts b/tests/playwright/e2e/app-page.spec.ts similarity index 95% rename from playwright/e2e/app-page.spec.ts rename to tests/playwright/e2e/app-page.spec.ts index 99c996509..51ed3b3f6 100644 --- a/playwright/e2e/app-page.spec.ts +++ b/tests/playwright/e2e/app-page.spec.ts @@ -20,8 +20,6 @@ import { userTest as test } from '../support/fixtures.ts' // - never select by CSS class, especially third-party ones // - use waitForApiResponse() from ../support/helpers.ts before assertions on mutations test.describe('Teams app page', () => { - test.fixme(true, 'The in-app Teams page (circles#2561) is not merged yet') - test('loads the app for a regular user', async ({ page }) => { await page.goto('apps/circles/teams', { waitUntil: 'networkidle' }) await page.waitForURL(/apps\/circles\/teams/) diff --git a/tests/playwright/merge.config.ts b/tests/playwright/merge.config.ts new file mode 100644 index 000000000..6d99e6887 --- /dev/null +++ b/tests/playwright/merge.config.ts @@ -0,0 +1,11 @@ +/*! + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +// Needed to merge multiple Playwright reports +// when they are ran on self-hosted and github runners (different test directories are used) +export default { + testDir: 'tests/playwright/e2e', + reporter: [['html', { open: 'never' }]], +} diff --git a/tests/playwright/start-nextcloud-server.js b/tests/playwright/start-nextcloud-server.js new file mode 100644 index 000000000..70e41666f --- /dev/null +++ b/tests/playwright/start-nextcloud-server.js @@ -0,0 +1,48 @@ +/*! + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: MIT + */ + +import { configureNextcloud, runExec, startNextcloud, stopNextcloud, waitOnNextcloud } from '@nextcloud/e2e-test-server/docker' +import { readFileSync } from 'fs' +import { execSync } from 'node:child_process' + +async function start() { + const port = Number.parseInt(process.env.NEXTCLOUD_PORT ?? '8042', 10) + const appinfo = readFileSync('appinfo/info.xml').toString() + const maxVersion = appinfo.match(//)?.[1] + let branch = 'master' + if (maxVersion) { + const refs = execSync('git ls-remote --refs').toString('utf-8') + branch = refs.includes(`refs/heads/stable${maxVersion}`) ? `stable${maxVersion}` : branch + } + + const ip = await startNextcloud(branch, true, { + exposePort: port, + forceRecreate: true, + }) + + await waitOnNextcloud(ip) + await configureNextcloud(['circles']) + + process.stdout.write('\nApply custom configuration for Playwright tests\n') + await runExec(['php', '-r', '$db = new SQLite3("data/owncloud.db");$db->busyTimeout(5000);$db->exec("PRAGMA journal_mode = wal;");']) + process.stdout.write('├─ Enabled SQLite WAL mode for better performance\n') + + process.stdout.write('└─ Nextcloud container ready to run Playwright tests\n') +} + +async function stop() { + process.stderr.write('Stopping Nextcloud server…\n') + await stopNextcloud() + process.exit(0) +} + +process.on('SIGTERM', stop) +process.on('SIGINT', stop) + +await start() + +while (true) { + await new Promise((resolvePromise) => setTimeout(resolvePromise, 5000)) +} diff --git a/playwright/start-nextcloud-server.mjs b/tests/playwright/start-nextcloud-server.mjs similarity index 100% rename from playwright/start-nextcloud-server.mjs rename to tests/playwright/start-nextcloud-server.mjs diff --git a/playwright/support/fixtures.ts b/tests/playwright/support/fixtures.ts similarity index 100% rename from playwright/support/fixtures.ts rename to tests/playwright/support/fixtures.ts diff --git a/playwright/support/helpers.ts b/tests/playwright/support/helpers.ts similarity index 100% rename from playwright/support/helpers.ts rename to tests/playwright/support/helpers.ts diff --git a/playwright/support/setup.ts b/tests/playwright/support/setup.ts similarity index 100% rename from playwright/support/setup.ts rename to tests/playwright/support/setup.ts