fix(e2e): seed storage in CI instead of skipping tests

Tests that create folders need a storage record in the database.
Instead of silently skipping when storage is missing, seed a dummy
storage backend via the admin API before folder creation. This
ensures tests actually run and fail loudly if something is wrong.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
saltbo
2026-04-12 20:09:26 -04:00
co-authored by Claude Opus 4.6
parent a1621d620b
commit ab2a4c1288
4 changed files with 35 additions and 16 deletions
+27 -13
View File
@@ -1,4 +1,4 @@
import { expect, type Page, test } from '@playwright/test'
import { expect, type Page } from '@playwright/test'
/** Register a fresh user and land on /files. */
export async function signUpAndGoToFiles(page: Page) {
@@ -15,9 +15,8 @@ export async function signUpAndGoToFiles(page: Page) {
}
/**
* Create a folder via the UI. Returns true if successful, false if the
* server rejected it (e.g. no storage configured in CI).
* Skips the calling test when creation fails.
* Create a folder via the UI. Waits for the API response to confirm success.
* If the API returns an error the test fails with a descriptive message.
*/
export async function createFolder(page: Page, name: string): Promise<void> {
await page.getByRole('button', { name: /new folder|folder/i }).click()
@@ -29,14 +28,29 @@ export async function createFolder(page: Page, name: string): Promise<void> {
dialog.getByRole('button', { name: /create/i }).click(),
])
if (!apiResp.ok()) {
// Close the dialog if it's still open (server error shown as toast)
await dialog
.getByRole('button', { name: /cancel/i })
.click()
.catch(() => {})
test.skip(true, `folder creation failed (${apiResp.status()}) — likely no storage in CI`)
}
expect(apiResp.ok(), `folder creation failed (${apiResp.status()}) — ensure storage is configured`).toBe(true)
await expect(dialog).not.toBeVisible({ timeout: 10000 })
}
/**
* Seed a dummy storage backend via the admin API.
* The first registered user is admin, so this must be called
* after the first signUp in the test suite. The storage doesn't
* need real S3 credentials — folder creation only needs a DB record.
*/
export async function seedStorage(page: Page): Promise<void> {
const resp = await page.request.post('/api/admin/storages', {
data: {
title: 'E2E Test Storage',
mode: 'private',
bucket: 'e2e-test',
endpoint: 'https://localhost',
region: 'auto',
accessKey: 'fake-key',
secretKey: 'fake-secret',
},
})
// Ignore 401/403 (non-admin user) — storage may already exist from a prior test
if (resp.status() === 401 || resp.status() === 403) return
expect(resp.ok(), `seed storage failed (${resp.status()})`).toBe(true)
}
+3 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from '@playwright/test'
import { createFolder, signUpAndGoToFiles } from './helpers'
import { createFolder, seedStorage, signUpAndGoToFiles } from './helpers'
// ---------------------------------------------------------------------------
// Dialogs responsive behavior
@@ -46,6 +46,7 @@ test.describe('File dialogs responsive', () => {
test('mobile: rename dialog is usable', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'mobile', 'mobile only')
await signUpAndGoToFiles(page)
await seedStorage(page)
await createFolder(page, 'rename-me')
// Open row actions dropdown via the last button in the row
@@ -72,6 +73,7 @@ test.describe('File dialogs responsive', () => {
test('mobile: move dialog is usable', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'mobile', 'mobile only')
await signUpAndGoToFiles(page)
await seedStorage(page)
await createFolder(page, 'move-me')
// Open row actions dropdown via the last button in the row
+2 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from '@playwright/test'
import { createFolder, signUpAndGoToFiles } from './helpers'
import { createFolder, seedStorage, signUpAndGoToFiles } from './helpers'
// ---------------------------------------------------------------------------
// Preview dialog: mobile uses full-screen drawer, desktop uses centered dialog
@@ -8,6 +8,7 @@ test.describe('Preview responsive layout', () => {
test('mobile: preview opens as full-screen drawer (not centered dialog)', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'mobile', 'mobile only')
await signUpAndGoToFiles(page)
await seedStorage(page)
await createFolder(page, 'test-preview')
// We need a file to trigger preview — check if any files exist
+3 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from '@playwright/test'
import { createFolder, signUpAndGoToFiles } from './helpers'
import { createFolder, seedStorage, signUpAndGoToFiles } from './helpers'
// ---------------------------------------------------------------------------
// Sidebar behavior per device
@@ -95,6 +95,7 @@ test.describe('File table responsive columns', () => {
test('desktop: all columns visible (name, size, modified, actions)', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'desktop', 'desktop only')
await signUpAndGoToFiles(page)
await seedStorage(page)
await createFolder(page, 'test-folder')
await expect(page.getByRole('columnheader', { name: /size/i })).toBeVisible()
@@ -104,6 +105,7 @@ test.describe('File table responsive columns', () => {
test('mobile: size and modified columns are hidden', async ({ page }, testInfo) => {
test.skip(testInfo.project.name !== 'mobile', 'mobile only')
await signUpAndGoToFiles(page)
await seedStorage(page)
await createFolder(page, 'test-folder')
await expect(page.getByRole('columnheader', { name: /size/i })).not.toBeVisible()