chore: e2e tests reliability (#46496)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES/NO

## What kind of change does this PR introduce?

Bug fix, feature, docs update, ...

## What is the current behavior?

Please link any relevant issues here.

## What is the new behavior?

Feel free to include screenshots if it includes visual changes.

## Additional context

Add any other context or screenshots.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Accessibility**
* Improved screen-reader label for table row action menus so table
controls are clearer for assistive‑technology users.

* **Tests**
* Enhanced end-to-end test reliability: tightened selectors, added
dialog/toast visibility and API-wait synchronization, scoped lookup
fixes, removed redundant cleanup helper, and updated test setup to mark
a terms-of-service dismissal to reduce flakiness.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Gildas Garcia authored and GitHub committed 2026-06-01 10:18:07 +02:00
1 parent d691073f02
commit ac59de1f9e
6 files changed
+56 -50

No files matched your search

@@ -493,7 +493,12 @@ export const TableList = ({
{!isSchemaLocked && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type="default" className="px-1" icon={<MoreVertical />} />
<Button
type="default"
className="px-1"
icon={<MoreVertical />}
aria-label={`Table ${x.name} actions`}
/>
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" align="end" className="w-40">
<DropdownMenuItem
+7 -5
View File
@@ -400,8 +400,10 @@ test.describe('Cron Jobs', () => {
// The test job should still be visible in the grid (minimal mode shows jobs without last run)
await expect(page.getByRole('row', { name: new RegExp(testJobName) })).toBeVisible()
// The "Learn more" button should be visible
await expect(page.getByRole('button', { name: 'Learn more' })).toBeVisible()
// An alert about high query costs should be visible and contain a "Learn more" button
await expect(
page.getByRole('alert').getByRole('button', { name: 'Learn more' })
).toBeVisible()
// Remove the route mock for subsequent tests
await page.unroute('**/pg-meta/*/query**')
@@ -441,8 +443,8 @@ test.describe('Cron Jobs', () => {
timeout: 15000,
})
// Click the "Learn more" button to open the dialog
await page.getByRole('button', { name: 'Learn more' }).click()
// Click the "Learn more" button in the alert to open the dialog
await page.getByRole('alert').getByRole('button', { name: 'Learn more' }).click()
// The dialog should open with the explanation
await expect(
@@ -504,7 +506,7 @@ test.describe('Cron Jobs', () => {
).toBeVisible({
timeout: 15000,
})
await page.getByRole('button', { name: 'Learn more' }).click()
await page.getByRole('alert').getByRole('button', { name: 'Learn more' }).click()
// Wait for dialog to open
await expect(
+40 -10
View File
@@ -301,6 +301,7 @@ test.describe('Database', () => {
// create a new table
await page.getByRole('button', { name: 'New table' }).click()
await expect(page.getByRole('dialog')).toBeVisible()
await page.getByLabel('Name', { exact: true }).fill(databaseTableNameNew)
const createTableWait = createApiResponseWaiter(
page,
@@ -313,12 +314,23 @@ test.describe('Database', () => {
// validate table creation
await createTableWait
await waitForDatabaseToLoad(page, ref)
await expect(page.getByRole('dialog')).not.toBeVisible()
await expect(page.getByText(databaseTableNameNew, { exact: true })).toBeVisible()
await expect(page.getByText('Table pw_database_table_crud_new is good to go!')).toBeVisible()
await page.getByRole('button', { name: 'Close toast' }).click()
// edit a new table
await page.getByRole('row', { name: databaseTableNameNew }).getByRole('button').last().click()
await page
.getByRole('row', { name: databaseTableNameNew })
.getByRole('button', { name: `Table ${databaseTableNameNew} actions` })
.click()
await page.getByRole('menuitem', { name: 'Edit table' }).click()
await page.getByTestId('table-name-input').fill(databaseTableNameUpdated)
await expect(page.getByRole('dialog')).toBeVisible()
await expect(page.getByText(`Update table ${databaseTableNameNew}`)).toBeVisible()
// Ensure table data is loaded
await expect(page.getByLabel('Name', { exact: true })).toHaveValue(databaseTableNameNew)
await page.getByLabel('Name', { exact: true }).fill(databaseTableNameUpdated)
const updateTableWait = createApiResponseWaiter(
page,
'pg-meta',
@@ -331,14 +343,19 @@ test.describe('Database', () => {
await updateTableWait
await waitForDatabaseToLoad(page, ref)
await expect(page.getByText(databaseTableNameUpdated, { exact: true })).toBeVisible()
await expect(
page.getByText(`Successfully updated ${databaseTableNameUpdated}!`)
).toBeVisible()
await page.getByRole('button', { name: 'Close toast' }).click()
await expect(page.getByRole('dialog')).not.toBeVisible()
// duplicate table
await page
.getByRole('row', { name: databaseTableNameUpdated })
.getByRole('button')
.last()
.getByRole('button', { name: `Table ${databaseTableNameUpdated} actions` })
.click()
await page.getByRole('menuitem', { name: 'Duplicate Table' }).click()
await expect(page.getByRole('dialog')).toBeVisible()
await page.getByLabel('Name').fill(databaseTableNameDuplicate)
await page.getByLabel('Description').fill('')
const duplicateTableWait = createApiResponseWaiter(page, 'pg-meta', ref, 'query?key=')
@@ -348,14 +365,21 @@ test.describe('Database', () => {
await duplicateTableWait
await waitForDatabaseToLoad(page, ref)
await expect(page.getByText(databaseTableNameDuplicate, { exact: true })).toBeVisible()
await expect(
page.getByText(
`Table ${databaseTableNameUpdated} has been successfully duplicated into ${databaseTableNameDuplicate}!`
)
).toBeVisible()
await page.getByRole('button', { name: 'Close toast' }).click()
await expect(page.getByRole('dialog')).not.toBeVisible()
// delete tables
await page
.getByRole('row', { name: `${databaseTableNameDuplicate}` })
.getByRole('button')
.last()
.getByRole('row', { name: databaseTableNameUpdated })
.getByRole('button', { name: `Table ${databaseTableNameUpdated} actions` })
.click()
await page.getByRole('menuitem', { name: 'Delete table' }).click()
await expect(page.getByRole('dialog')).toBeVisible()
await page.getByRole('checkbox', { name: 'Drop table with cascade?' }).check()
const deleteDuplicateWait = createApiResponseWaiter(
page,
@@ -365,13 +389,14 @@ test.describe('Database', () => {
)
await page.getByRole('button', { name: 'Delete' }).click()
await deleteDuplicateWait
await expect(page.getByRole('dialog')).not.toBeVisible()
await page
.getByRole('row', { name: `${databaseTableNameUpdated}` })
.getByRole('button')
.last()
.getByRole('row', { name: databaseTableNameDuplicate })
.getByRole('button', { name: `Table ${databaseTableNameDuplicate} actions` })
.click()
await page.getByRole('menuitem', { name: 'Delete table' }).click()
await expect(page.getByRole('dialog')).toBeVisible()
await page.getByRole('checkbox', { name: 'Drop table with cascade?' }).check()
const deleteUpdatedWait = createApiResponseWaiter(
page,
@@ -381,6 +406,7 @@ test.describe('Database', () => {
)
await page.getByRole('button', { name: 'Delete' }).click()
await deleteUpdatedWait
await expect(page.getByRole('dialog')).not.toBeVisible()
// validate navigating to table editor from database table page
await page.getByRole('row', { name: databaseTableName }).getByRole('button').last().click()
@@ -449,12 +475,15 @@ test.describe('Database', () => {
// wait for response + validate
await columnCreateWait
await columnCreateRefreshWait
await expect(page.getByRole('dialog')).not.toBeVisible()
const columnDatabase2Row = page.getByRole('row', { name: databaseColumnName2 })
await expect(columnDatabase2Row).toContainText(databaseColumnName2)
await expect(columnDatabase2Row).toContainText('numeric')
// update table column
await columnDatabase2Row.getByRole('button', { name: 'Edit' }).click()
await expect(page.getByRole('dialog')).toBeVisible()
await page.getByLabel('name').fill(databaseColumnName3)
const columnUpdateWait = createApiResponseWaiter(
page,
@@ -473,6 +502,7 @@ test.describe('Database', () => {
// wait for response + validate
await columnUpdateWait
await columnUpdateRefreshWait
await expect(page.getByRole('dialog')).not.toBeVisible()
// delete table column
const columnDatabase3Row = page.getByRole('row', { name: databaseColumnName3 })
@@ -15,6 +15,7 @@ import { test } from '../utils/test.js'
test.describe('Realtime Inspector', () => {
test.beforeEach(async ({ page, ref }) => {
await navigateToRealtimeInspector(page, ref)
await page.waitForResponse(new RegExp(`/platform/projects/${ref}/settings`))
})
test.describe('Basic Inspector UI', () => {
+1 -34
View File
@@ -3,7 +3,7 @@ import { expect, Page } from '@playwright/test'
import { createTableWithRLS, dropTable } from '../utils/db/queries.js'
import { test, withSetupCleanup } from '../utils/test.js'
import { toUrl } from '../utils/to-url.js'
import { createApiResponseWaiter, waitForApiResponse } from '../utils/wait-for-response.js'
import { createApiResponseWaiter } from '../utils/wait-for-response.js'
/**
* Helper function to navigate to policies page and wait for it to load
@@ -15,39 +15,6 @@ const navigateToPoliciesPage = async (page: Page, ref: string) => {
await page.waitForTimeout(500)
}
/**
* Helper function to delete a policy if it exists
*/
const deletePolicyIfExists = async (page: Page, ref: string, policyNameToDelete: string) => {
// Look for the policy in the table
const policyButton = page.getByRole('button', { name: policyNameToDelete })
const policyExists = (await policyButton.count()) > 0
if (policyExists) {
// Click the policy row actions button
await page.getByTestId(`policy-${policyNameToDelete}-actions-button`).click()
await page.waitForTimeout(200)
// Click delete
await page.getByText('Delete', { exact: true }).click()
await page.waitForTimeout(200)
const waitForDeletion = waitForApiResponse(page, 'pg-meta', ref, 'query?key=')
// Confirm deletion
await page.getByRole('button', { name: 'Delete' }).click()
// Wait for deletion to complete
await waitForDeletion
await expect(
page.getByText('Successfully removed policy'),
'Policy deletion confirmation should be visible'
).toBeVisible({ timeout: 50000 })
await page.waitForTimeout(500)
}
}
test.describe('RLS Policies', () => {
test.describe('Policies Page', () => {
test('should display policies page correctly', async ({ page, ref }) => {
+1
View File
@@ -26,6 +26,7 @@ export const test = base.extend<TestOptions>({
`table-editor-queue-operations-banner-dismissed-${ref}`,
JSON.stringify(true)
)
localStorage.setItem(`terms-of-service-update-2026-06-06`, JSON.stringify(true))
}, ref)
await use(page)
},