diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index d8ded08d..5c2b13ab 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -10,12 +10,13 @@ jobs: strategy: matrix: server_version: [stable29, stable30, stable31, stable32, master] + shard: [1, 2, 3] fail-fast: false timeout-minutes: 60 runs-on: ubuntu-latest env: SERVER_VERSION: ${{ matrix.server_version }} - name: Playwright Tests on Nextcloud ${{ matrix.server_version }} + name: Playwright Tests on Nextcloud ${{ matrix.server_version }} (${{ matrix.shard }}/3) steps: - name: Checkout app uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -57,11 +58,11 @@ jobs: - name: Run Playwright tests run: | - npx playwright test + npx playwright test --reporter=line,html --shard=${{ matrix.shard }}/3 - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 if: always() with: - name: playwright-report-${{ matrix.server_version }} + name: playwright-report-${{ matrix.server_version }}-shard-${{ matrix.shard }} path: playwright-report/ retention-days: 30 diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 41ef16ec..62dc4720 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -52,11 +52,11 @@ jobs: composer remove nextcloud/ocp --dev --no-scripts composer i - - name: Check for vulnerable PHP dependencies - run: composer require --dev roave/security-advisories:dev-latest - - name: Install nextcloud/ocp run: composer require --dev nextcloud/ocp:dev-${{ steps.versions.outputs.branches-max }} --ignore-platform-reqs --with-dependencies + - name: Audit PHP dependency advisories + run: composer audit --locked --format=summary + - name: Run coding standards check run: composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github diff --git a/composer.json b/composer.json index 8ec7ce9f..ac61ddec 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,11 @@ "name": "nextcloud/whiteboard", "config": { "autoloader-suffix": "Whiteboard", + "audit": { + "ignore": { + "PKSA-y2cr-5h3j-g3ys": "Temporary CI exception until firebase/php-jwt can be upgraded without changing existing shared-secret requirements." + } + }, "optimize-autoloader": true, "platform": { "php": "8.4" diff --git a/playwright.config.ts b/playwright.config.ts index 3d1d6e7d..e4403028 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -33,10 +33,10 @@ export default defineConfig({ baseURL: 'http://localhost:8089/index.php/', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on', + trace: process.env.CI ? 'on-first-retry' : 'on', - /* Capture video of test runs - only keep videos for failed tests */ - video: 'on', + /* Record videos only when CI retries a failing test to keep the suite lighter. */ + video: process.env.CI ? 'on-first-retry' : 'on', }, projects: [ diff --git a/tests/integration/multinode-redis.spec.mjs b/tests/integration/multinode-redis.spec.mjs index ada882aa..d098707c 100644 --- a/tests/integration/multinode-redis.spec.mjs +++ b/tests/integration/multinode-redis.spec.mjs @@ -67,14 +67,14 @@ const Config = ConfigModule vi.setConfig({ testTimeout: 30000 }) -const waitFor = (socket, event) => { +const waitFor = (socket, event, timeoutMs = 5000) => { return new Promise((resolve, reject) => { const timer = setTimeout(() => { const lastError = event === 'connect' && socket?.lastConnectError ? `: ${socket.lastConnectError.message || socket.lastConnectError}` : '' reject(new Error(`Timeout waiting for ${event}${lastError}`)) - }, 5000) + }, timeoutMs) socket.once(event, (data) => { clearTimeout(timer) resolve(data) @@ -463,7 +463,7 @@ describe('Multi node websocket cluster with redis streams', () => { const followerDesignation = await waitFor(followerSocket, 'sync-designate') expect(followerDesignation.isSyncer).toBe(false) - const newSyncerNotice = waitFor(followerSocket, 'sync-designate') + const newSyncerNotice = waitFor(followerSocket, 'sync-designate', 10000) await serverA.gracefulShutdown() serverA = null