diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e66e91c3..68d17aea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,7 @@ jobs: if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -93,7 +93,7 @@ jobs: if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: clippy @@ -120,7 +120,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 @@ -140,7 +140,7 @@ jobs: if: needs.changes.outputs.backend == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: rustsec/audit-check@v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo build --release diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 2c9c71ca..9e3dd8b7 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 7db0e2e0..c4fe6272 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -39,7 +39,7 @@ jobs: DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: # Build the exact tag behind the published release or manual dispatch. ref: ${{ github.event.inputs.version || github.event.release.tag_name || github.ref }} @@ -61,7 +61,7 @@ jobs: needs: test steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v4 with: # Build the exact tag behind the published release or manual dispatch. ref: ${{ github.event.inputs.version || github.event.release.tag_name || github.ref }} diff --git a/.github/workflows/playwright-update-snapshots.yml b/.github/workflows/playwright-update-snapshots.yml index 893ad201..aebdbfc3 100644 --- a/.github/workflows/playwright-update-snapshots.yml +++ b/.github/workflows/playwright-update-snapshots.yml @@ -26,11 +26,17 @@ jobs: - name: Install Node dependencies run: npm ci + - name: Build OxiCloud (release) + working-directory: . + run: cargo build --release + - name: Install Playwright browsers run: npx playwright install --with-deps - name: Update snapshots run: npm test -- --update-snapshots + env: + BUILD_TARGET: release - name: Commit updated snapshots uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/.gitignore b/.gitignore index 60266115..28ed45c8 100644 --- a/.gitignore +++ b/.gitignore @@ -94,7 +94,6 @@ charts/*/charts/* # Playwright tests/e2e/node_modules/ tests/e2e/test-results/ -tests/e2e/playwright-report/ tests/e2e/blob-report/ tests/e2e/playwright/.cache/ tests/e2e/playwright/.auth/ diff --git a/tests/e2e/package.json b/tests/e2e/package.json index eb7d0ff4..129c9902 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "pretest": "bash ../common/spawn-db.sh", - "test": "npx playwright test --reporter=line,github --trace=on-first-retry scenarios/01-home-and-login.spec.ts scenarios/02-folder-management.spec.ts", + "test": "FORCE_COLOR=true npx playwright test scenarios/01-home-and-login.spec.ts scenarios/02-folder-management.spec.ts", "posttest": "bash ../common/stop-db.sh" }, "keywords": [], diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index c93d3e44..b1486f14 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -27,9 +27,9 @@ export default defineConfig({ testDir: './scenarios', fullyParallel: false, forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, + retries: 0, workers: 1, - reporter: process.env.CI ? [['github'], ['html']] : 'html', + reporter: process.env.CI ? [['line'], ['github'], ['html']] : [ ['list'], ['html']], globalSetup: require.resolve('./global-setup'), globalTeardown: require.resolve('./global-teardown'), @@ -37,6 +37,9 @@ export default defineConfig({ use: { baseURL: 'http://localhost:8087', trace: 'on-first-retry', + headless: true, + // take a screenshot on failure + screenshot: 'only-on-failure', }, expect: { diff --git a/tests/e2e/scenarios/02-folder-management.spec.ts b/tests/e2e/scenarios/02-folder-management.spec.ts index 900ec01d..72dcba5e 100644 --- a/tests/e2e/scenarios/02-folder-management.spec.ts +++ b/tests/e2e/scenarios/02-folder-management.spec.ts @@ -73,7 +73,7 @@ test.describe('Folder management', () => { }); test('folder creation', async ({ page }) => { - const name = `Test folder ${Date.now()}`; + const name = `Test folder creation`; await submitNewFolder(page, name); @@ -92,7 +92,7 @@ test.describe('Folder management', () => { }); test('folder reject if already exists', async ({ page }) => { - const name = `Test folder ${Date.now()}`; + const name = `Test existing folder`; // Prerequisite: create the folder once successfully. await submitNewFolder(page, name); @@ -122,9 +122,8 @@ test.describe('Folder management', () => { }); test('folder rename', async ({ page }) => { - const ts = Date.now(); - const original = `Test folder ${ts}`; - const renamed = `Renamed folder ${ts}`; + const original = `Test folder`; + const renamed = `Renamed folders`; // Prerequisite: create the folder to rename. await submitNewFolder(page, original); diff --git a/tests/e2e/scenarios/02-folder-management.spec.ts-snapshots/folder-renamed-chromium-linux.png b/tests/e2e/scenarios/02-folder-management.spec.ts-snapshots/folder-renamed-chromium-linux.png index af16317d..aeeb002a 100644 Binary files a/tests/e2e/scenarios/02-folder-management.spec.ts-snapshots/folder-renamed-chromium-linux.png and b/tests/e2e/scenarios/02-folder-management.spec.ts-snapshots/folder-renamed-chromium-linux.png differ diff --git a/tests/e2e/scenarios/helpers.ts b/tests/e2e/scenarios/helpers.ts index b3e1cccf..369dbff6 100644 --- a/tests/e2e/scenarios/helpers.ts +++ b/tests/e2e/scenarios/helpers.ts @@ -7,7 +7,17 @@ export const TEST_ADMIN = { }; /** - * Log in as the test admin and wait until the main app is ready. + * Log in as the test admin and wait until the main app is fully initialized. + * + * We wait for two things after the login redirect: + * 1. `#sidebar` — confirms the main HTML has loaded. + * 2. `#user-avatar-btn .user-vignette` — confirms that `setupUserMenu()` has + * run and mounted the avatar vignette. This is the earliest reliable + * signal that the click-handler on the avatar button is attached, so any + * subsequent test that opens the user menu will not race against JS startup. + * + * Without (2), CI (Ubuntu + Xvfb) occasionally clicks the button before the + * event listener is registered because the JS runtime is slower than on macOS. */ export async function loginAsAdmin(page: Page) { await goToLoginPage(page); @@ -15,6 +25,8 @@ export async function loginAsAdmin(page: Page) { await page.locator('#login-password').fill(TEST_ADMIN.password); await page.locator('#login-panel button[type="submit"]').click(); await expect(page.locator('#sidebar')).toBeVisible({ timeout: 15_000 }); + // Wait for the JS app to initialise: avatar vignette present ⟹ click handler attached. + await expect(page.locator('#user-avatar-btn .user-vignette')).toBeAttached({ timeout: 10_000 }); } /**