mirror of
https://github.com/supabase/supabase.git
synced 2026-09-09 03:19:36 +08:00
Backports a batch of e2e test stabilization fixes — each commit is
scoped to a single failure class and only touches `e2e/studio/` files.
**Changed:**
- **`_global.setup` — playwright-locks cleanup was dead code**: the
lock-cleanup block was at the bottom of `Global Setup`, but every branch
above it returns early — so it never ran. Tests that use
`withFileOnceSetup` (cron-jobs) would see a stale `setup.done.json`
marker from the previous run and silently skip their setup, leaving e.g.
`pg_cron` uninstalled and all 11 cron-jobs specs failing. Moved the
cleanup to before any early return.
- **filter-bar — Home key**: macOS Chromium doesn't honor a standalone
`Home` keypress inside text inputs (macOS routes "go to line start" via
`Cmd+ArrowLeft` / `Fn+ArrowLeft`). Tests that expected the cursor to
jump to position 0 silently kept the previous selection. Replaced with
`el.setSelectionRange(0, 0)` so the assertion runs against a known
cursor position on every OS.
- **filter-bar — date filters**: tests inserted rows with `CURRENT_DATE`
/ `NOW()` (postgres session TZ = UTC) and asserted with JS-local dates
from `getDateValue()`. Near midnight the two diverged and the filter
returned 0 rows. Switched the inserts to explicit `getDateValue()`
strings so insert and assert use the same calendar day.
- **queue-table-operations — `networkidle`**: Studio holds long-poll /
SSE connections (PostHog, realtime), so `page.reload({ waitUntil:
'networkidle' })` never resolves and timed out. Replaced with a targeted
`waitForTableToLoad` API waiter.
- **sql-editor — RLS smoke test**: a hard-coded table name
(`pw_rls_smoke_test`) collided across 3 parallel workers running against
the same db. Suffixed with `test.info().parallelIndex`.
- **table-editor — FK spec timeout**: `waitForApiResponseWithTimeout`
for `query?key=table-update` returns `null` on timeout (silent), then
the panel-close assertion fails. Bumped 15s → 30s to absorb
parallel-load latency.
- **table-editor / storage-helpers — URL encoding & redirect race**:
post-action URL assertions were over-specific (`%20` vs `+` encoding)
and the bucket-delete redirect could race other history updates. Relaxed
the regex to accept both encodings; asserting the row removal directly
is a more stable signal than the redirect URL.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Improved end-to-end determinism with explicit dates/timestamps and
stable cursor positioning
* Prevented parallel-test collisions by using unique identifiers for
resources
* Made page reloads and API waits more robust for long-lived connections
and increased timeouts
* Strengthened assertions to rely on stable UI signals instead of
transient navigation/network state
* Ensured test setup reliably cleans up temporary locks before any setup
steps run
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46039?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
135 lines
3.4 KiB
TypeScript
135 lines
3.4 KiB
TypeScript
import fs from 'node:fs/promises'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
import { test as setup } from '@playwright/test'
|
|
import dotenv from 'dotenv'
|
|
|
|
import { env } from '../env.config.js'
|
|
import { loginWithEmail } from '../scripts/login/email.js'
|
|
import { loginWithGithubWithRetry } from '../scripts/login/github.js'
|
|
import { setupProjectForTests } from '../scripts/setup-platform-tests.js'
|
|
|
|
/**
|
|
* Run any setup tasks for the tests.
|
|
* Catch errors and show useful messages.
|
|
*/
|
|
|
|
dotenv.config({
|
|
path: path.resolve(import.meta.dirname, '..', '.env.local'),
|
|
override: true,
|
|
})
|
|
|
|
const IS_PLATFORM = process.env.IS_PLATFORM
|
|
const doAuthentication = env.AUTHENTICATION
|
|
|
|
setup('Global Setup', async ({ page }) => {
|
|
console.log(`\n 🧪 Setting up test environment.
|
|
- Studio URL: ${env.STUDIO_URL}
|
|
- API URL: ${env.API_URL}
|
|
- Auth: ${doAuthentication ? 'enabled' : 'disabled'}
|
|
- Is Platform: ${IS_PLATFORM}
|
|
`)
|
|
|
|
// Cleanup once-per-file locks before any of the early returns below —
|
|
// tests using `withFileOnceSetup` rely on this running unconditionally.
|
|
const locksDirPath = path.join(os.tmpdir(), 'playwright-locks')
|
|
try {
|
|
await fs.access(locksDirPath)
|
|
await fs.rm(locksDirPath, { recursive: true, force: true })
|
|
} catch {
|
|
// Silently catch, no directory
|
|
}
|
|
|
|
/**
|
|
* Studio Check
|
|
*/
|
|
|
|
const studioUrl = env.STUDIO_URL
|
|
const apiUrl = env.API_URL
|
|
|
|
await page.goto(studioUrl).catch((err) => {
|
|
console.error(
|
|
`\n 🚨 Setup Error
|
|
Studio is not available at: ${studioUrl}
|
|
|
|
Please ensure:
|
|
1. Studio is running in the expected URL
|
|
2. You have proper network access
|
|
`
|
|
)
|
|
throw err
|
|
})
|
|
|
|
console.log(`\n ✅ Studio is running at ${studioUrl}`)
|
|
|
|
/**
|
|
* API Check
|
|
*/
|
|
|
|
await fetch(apiUrl).catch((err) => {
|
|
console.error(`\n 🚨 Setup Error
|
|
API is not available at: ${apiUrl}
|
|
|
|
Please ensure:
|
|
1. API is running in the expected URL
|
|
2. You have proper network access
|
|
|
|
To start API locally, run:
|
|
npm run dev:api`)
|
|
throw new Error('API is not available')
|
|
})
|
|
|
|
console.log(`\n ✅ API is running at ${apiUrl}`)
|
|
|
|
/**
|
|
* Setup Project for tests
|
|
*/
|
|
const projectRef = await setupProjectForTests()
|
|
process.env.PROJECT_REF = projectRef
|
|
env.PROJECT_REF = projectRef
|
|
|
|
/**
|
|
* Only run authentication if the environment requires it
|
|
*/
|
|
if (!doAuthentication) {
|
|
console.log(`\n 🔑 Skipping authentication for ${env.STUDIO_URL}`)
|
|
return
|
|
}
|
|
|
|
const { EMAIL, PASSWORD } = env
|
|
if (EMAIL && PASSWORD) {
|
|
console.log(`\n 🔑 Authenticating user with email and password`)
|
|
|
|
try {
|
|
await loginWithEmail(page, studioUrl, {
|
|
email: EMAIL,
|
|
password: PASSWORD,
|
|
})
|
|
console.log(`\n ✅ Successfully authenticated with email`)
|
|
return
|
|
} catch (err) {
|
|
console.error(`\n 🚨 Authentication failed with email/password`)
|
|
throw err
|
|
}
|
|
}
|
|
|
|
const { GITHUB_USER, GITHUB_PASS, GITHUB_TOTP } = env
|
|
if (GITHUB_USER && GITHUB_PASS && GITHUB_TOTP) {
|
|
console.log(`\n 🔑 Authenticating user with GitHub`)
|
|
try {
|
|
await loginWithGithubWithRetry({
|
|
page,
|
|
githubTotp: GITHUB_TOTP,
|
|
githubUser: GITHUB_USER,
|
|
githubPass: GITHUB_PASS,
|
|
supaDashboard: studioUrl,
|
|
})
|
|
console.log(`\n ✅ Successfully authenticated with GitHub`)
|
|
return
|
|
} catch (err) {
|
|
console.error(`\n 🚨 Authentication failed with GitHub`)
|
|
throw err
|
|
}
|
|
}
|
|
})
|