diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyEditorPanelHeader.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyEditorPanelHeader.tsx index 3a71fb68261..aa3c5dda329 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyEditorPanelHeader.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditorPanel/PolicyEditorPanelHeader.tsx @@ -1,18 +1,17 @@ import type { PostgresPolicy } from '@supabase/postgres-meta' import { ChevronDown, PanelLeftClose, PanelRightClose, X } from 'lucide-react' import { useState } from 'react' - import { + cn, + Collapsible_Shadcn_, CollapsibleContent_Shadcn_, CollapsibleTrigger_Shadcn_, - Collapsible_Shadcn_, SheetClose, SheetHeader, SheetTitle, Tooltip, TooltipContent, TooltipTrigger, - cn, } from 'ui' export const PolicyEditorPanelHeader = ({ @@ -119,6 +118,7 @@ export const PolicyEditorPanelHeader = ({ ) : ( )} + {showTools ? 'Hide' : 'Show'} tools {showTools ? 'Hide' : 'Show'} tools diff --git a/e2e/studio/features/api-access-toggle.spec.ts b/e2e/studio/features/api-access-toggle.spec.ts index a61d38463be..46bb1afc080 100644 --- a/e2e/studio/features/api-access-toggle.spec.ts +++ b/e2e/studio/features/api-access-toggle.spec.ts @@ -1,11 +1,11 @@ import { expect, Page } from '@playwright/test' -import { query } from '../utils/db/index.js' -import { test } from '../utils/test.js' +import { dropTable, query } from '../utils/db/index.js' +import { dismissToastsIfAny } from '../utils/dismiss-toast.js' +import { openTableContextMenu } from '../utils/table-helpers.js' +import { test, withSetupCleanup } from '../utils/test.js' import { toUrl } from '../utils/to-url.js' import { createApiResponseWaiter, waitForTableToLoad } from '../utils/wait-for-response.js' -import { dismissToastsIfAny } from '../utils/dismiss-toast.js' -import { openTableContextMenu, deleteTable } from '../utils/table-helpers.js' const TABLE_NAME_PREFIX = 'pw_api_access' @@ -87,7 +87,14 @@ test.describe('API Access Toggle', () => { test('API access is default on for a new table', async ({ page, ref }) => { const tableName = `${TABLE_NAME_PREFIX}_default_on` - + await using _ = await withSetupCleanup( + async () => { + // Nothing + }, + async () => { + await dropTable(tableName) + } + ) // Open new table dialog await page.getByRole('button', { name: 'New table', exact: true }).click() await expect(page.getByTestId('table-editor-side-panel')).toBeVisible() @@ -135,6 +142,14 @@ test.describe('API Access Toggle', () => { test('can toggle API access off for a new table', async ({ page, ref }) => { const tableName = `${TABLE_NAME_PREFIX}_toggle_off` + await using _ = await withSetupCleanup( + async () => { + // Nothing + }, + async () => { + await dropTable(tableName) + } + ) // Open new table dialog await page.getByRole('button', { name: 'New table', exact: true }).click() @@ -185,7 +200,14 @@ test.describe('API Access Toggle', () => { test('shows Manage access link when editing an existing table', async ({ page, ref }) => { const tableName = `${TABLE_NAME_PREFIX}_edit` - + await using _ = await withSetupCleanup( + async () => { + // Nothing + }, + async () => { + await dropTable(tableName) + } + ) // Create a table first await page.getByRole('button', { name: 'New table', exact: true }).click() await expect(page.getByTestId('table-editor-side-panel')).toBeVisible() @@ -236,7 +258,14 @@ test.describe('API Access Toggle', () => { ref, }) => { const tableName = `${TABLE_NAME_PREFIX}_preserve_grants` - + await using _ = await withSetupCleanup( + async () => { + // Nothing + }, + async () => { + await dropTable(tableName) + } + ) // Step 1: Create a table with API access on (default — full grants) await page.getByRole('button', { name: 'New table', exact: true }).click() await expect(page.getByTestId('table-editor-side-panel')).toBeVisible() @@ -297,12 +326,5 @@ test.describe('API Access Toggle', () => { anon: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], authenticated: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], }) - - // Clean up - loadPromise = waitForTableToLoad(page, ref) - await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) - await loadPromise - - await deleteTable(page, ref, tableName) }) }) diff --git a/e2e/studio/features/queue-table-operations.spec.ts b/e2e/studio/features/queue-table-operations.spec.ts index c3eacb6ba71..abe8c4ce167 100644 --- a/e2e/studio/features/queue-table-operations.spec.ts +++ b/e2e/studio/features/queue-table-operations.spec.ts @@ -1,8 +1,7 @@ import { expect, Page } from '@playwright/test' + import { createTable, dropTable } from '../utils/db/index.js' -import { releaseFileOnceCleanup, withFileOnceSetup } from '../utils/once-per-file.js' -import { deleteTable } from '../utils/table-helpers.js' -import { test } from '../utils/test.js' +import { test, withSetupCleanup } from '../utils/test.js' import { toUrl } from '../utils/to-url.js' import { waitForTableToLoad } from '../utils/wait-for-response.js' @@ -16,38 +15,6 @@ const enableQueueOperations = async (page: Page) => { } test.describe('Queue Table Operations', () => { - test.beforeAll(async ({ browser, ref }) => { - await withFileOnceSetup(import.meta.url, async () => { - const ctx = await browser.newContext() - const page = await ctx.newPage() - - const loadPromise = waitForTableToLoad(page, ref) - await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) - await loadPromise - - const viewButtons = page.getByRole('button', { name: /^View / }) - const names = await Promise.all( - (await viewButtons.all()).map(async (btn) => { - const ariaLabel = await btn.getAttribute('aria-label') - const name = ariaLabel ? ariaLabel.replace(/^View\s+/, '').trim() : '' - return name - }) - ) - const tablesToDelete = names.filter((tableName) => tableName.startsWith(tableNamePrefix)) - - for (const tableName of tablesToDelete) { - await deleteTable(page, ref, tableName) - await expect - .poll(async () => { - return await page.getByLabel(`View ${tableName}`, { exact: true }).count() - }) - .toBe(0) - } - - await ctx.close() - }) - }) - test.beforeEach(async ({ page, ref }) => { const loadPromise = waitForTableToLoad(page, ref) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) @@ -56,15 +23,18 @@ test.describe('Queue Table Operations', () => { await page.reload({ waitUntil: 'networkidle' }) }) - test.afterAll(async () => { - await releaseFileOnceCleanup(import.meta.url) - }) - test('cell edits are queued and can be saved', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_cell_edit` const columnName = 'name' - await createTable(tableName, columnName, [{ name: 'original value' }]) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName, [{ name: 'original value' }]) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -99,15 +69,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'edited value' })).toBeVisible() await expect(page.getByRole('gridcell', { name: 'original value' })).not.toBeVisible() - - await dropTable(tableName) }) test('cell edits can be cancelled', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_cell_cancel` const columnName = 'name' - await createTable(tableName, columnName, [{ name: 'keep this value' }]) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName, [{ name: 'keep this value' }]) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -134,15 +109,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'should be cancelled' })).not.toBeVisible() await expect(page.getByText('pending change')).not.toBeVisible() - - await dropTable(tableName) }) test('row inserts are queued and can be saved', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_row_insert` const columnName = 'name' - await createTable(tableName, columnName) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -172,16 +152,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByText('Changes saved successfully')).toBeVisible() await expect(page.getByRole('gridcell', { name: 'new row value' })).toBeVisible() - - await dropTable(tableName) }) test('multiple operations can be batched and saved together', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_batch_ops` const columnName = 'name' - await createTable(tableName, columnName) - + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) await page.reload() @@ -213,16 +197,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'row one' })).toBeVisible() await expect(page.getByRole('gridcell', { name: 'row two' })).toBeVisible() - - await dropTable(tableName) }) test('individual operations can be removed from the queue', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_remove_op` const columnName = 'name' - await createTable(tableName, columnName) - + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) await page.reload() @@ -256,16 +244,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'keep this row' })).toBeVisible() await expect(page.getByRole('gridcell', { name: 'remove this row' })).not.toBeVisible() - - await dropTable(tableName) }) test('keyboard shortcuts work for queue operations', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_shortcuts` const columnName = 'name' - await createTable(tableName, columnName) - + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) await page.reload() @@ -291,15 +283,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByText('Changes saved successfully')).toBeVisible() await expect(page.getByRole('gridcell', { name: 'shortcut test' })).toBeVisible() - - await dropTable(tableName) }) test('row deletes via context menu are queued', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_row_delete` const columnName = 'name' - await createTable(tableName, columnName, [{ name: 'row to delete' }]) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName, [{ name: 'row to delete' }]) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -330,15 +327,20 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'row to delete' })).not.toBeVisible() await expect(page.getByText('0 records')).toBeVisible() - - await deleteTable(page, ref, tableName) }) test('row deletes can be cancelled', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_delete_cancel` const columnName = 'name' - await createTable(tableName, columnName, [{ name: 'should not be deleted' }]) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName, [{ name: 'should not be deleted' }]) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -359,18 +361,22 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'should not be deleted' })).toBeVisible() await expect(page.getByText('pending change')).not.toBeVisible() - - await dropTable(tableName) }) test('mixed operations (add, edit, delete) can be batched', async ({ page, ref }) => { const tableName = `${tableNamePrefix}_mixed_ops` const columnName = 'name' - - await createTable(tableName, columnName, [ - { name: 'row to edit' }, - { name: 'row to delete' }, - ]) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName, columnName, [ + { name: 'row to edit' }, + { name: 'row to delete' }, + ]) + }, + async () => { + await dropTable(tableName) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -411,8 +417,6 @@ test.describe('Queue Table Operations', () => { await expect(page.getByRole('gridcell', { name: 'new row' })).toBeVisible() await expect(page.getByRole('gridcell', { name: 'row to delete' })).not.toBeVisible() await expect(page.getByRole('gridcell', { name: 'row to edit' })).not.toBeVisible() - - await dropTable(tableName) }) test('pending changes persist when switching between tables', async ({ page, ref }) => { @@ -420,8 +424,16 @@ test.describe('Queue Table Operations', () => { const tableName2 = `${tableNamePrefix}_persist2` const columnName = 'name' - await createTable(tableName1, columnName) - await createTable(tableName2, columnName) + await using _ = await withSetupCleanup( + async () => { + await createTable(tableName1, columnName) + await createTable(tableName2, columnName) + }, + async () => { + await dropTable(tableName1) + await dropTable(tableName2) + } + ) await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) await enableQueueOperations(page) @@ -459,8 +471,5 @@ test.describe('Queue Table Operations', () => { await page.getByRole('button', { name: `View ${tableName2}`, exact: true }).click() await expect(page.getByRole('gridcell', { name: 'pending in table 2' })).toBeVisible() - - await dropTable(tableName1) - await dropTable(tableName2) }) }) diff --git a/e2e/studio/features/realtime-inspector.spec.ts b/e2e/studio/features/realtime-inspector.spec.ts index e14ae749e19..e4f4a5d177a 100644 --- a/e2e/studio/features/realtime-inspector.spec.ts +++ b/e2e/studio/features/realtime-inspector.spec.ts @@ -12,8 +12,6 @@ import { } from '../utils/realtime-helpers.js' import { test } from '../utils/test.js' -const testChannelName = 'pw_realtime_test_channel' - test.describe('Realtime Inspector', () => { test.beforeEach(async ({ page, ref }) => { await navigateToRealtimeInspector(page, ref) @@ -41,6 +39,7 @@ test.describe('Realtime Inspector', () => { }) test('can join and leave a channel', async ({ page }) => { + const testChannelName = 'pw_realtime_test_channel_join_leave' await joinChannel(page, testChannelName) await expect(page.getByText('Listening', { exact: true })).toBeVisible({ timeout: 10000 }) @@ -52,6 +51,7 @@ test.describe('Realtime Inspector', () => { }) test('start/stop listening button works', async ({ page }) => { + const testChannelName = 'pw_realtime_test_channel_listening' await joinChannel(page, testChannelName) await expect(page.getByText('Listening', { exact: true })).toBeVisible({ timeout: 10000 }) @@ -72,6 +72,7 @@ test.describe('Realtime Inspector', () => { test.describe('Broadcast Messages', () => { test('broadcast messages appear in the UI when listening', async ({ page }) => { + const testChannelName = 'pw_realtime_test_channel_broadcast_ui' await joinChannel(page, testChannelName) await expect(page.getByText('Listening', { exact: true })).toBeVisible({ timeout: 10000 }) @@ -93,25 +94,26 @@ test.describe('Realtime Inspector', () => { }) test('clicking broadcast message shows detail panel', async ({ page }) => { + const testChannelName = 'pw_realtime_test_channel_broadcast_details' await joinChannel(page, testChannelName) await openBroadcastModal(page) await page.getByRole('button', { name: 'Confirm' }).click() - await expect(page.getByText('Successfully broadcasted message')).toBeVisible({ - timeout: 10000, - }) + await expect(page.getByText('Successfully broadcasted message')).toBeVisible() + await expect(page.getByText('Broadcast a message to all clients')).not.toBeVisible() await waitForRealtimeMessage(page, { timeout: 30000 }) const messageRow = page.getByRole('row').filter({ hasText: 'broadcast' }).first() - await expect(messageRow).toBeVisible({ timeout: 5000 }) + await expect(messageRow).toBeVisible() await messageRow.click() - await expect(page.getByText('Timestamp')).toBeVisible({ timeout: 5000 }) + await expect(page.getByText('Timestamp')).toBeVisible() await leaveChannel(page) }) test('broadcast modal validates JSON payload', async ({ page }) => { + const testChannelName = 'pw_realtime_test_channel_broadcast_json' await joinChannel(page, testChannelName) await openBroadcastModal(page) @@ -134,7 +136,7 @@ test.describe('Realtime Inspector', () => { test.describe('Message Display', () => { test('messages counter shows correct count', async ({ page }) => { - await joinChannel(page, `${testChannelName}_counter`) + await joinChannel(page, `pw_realtime_test_channel_counter`) const initialCount = await getMessageCount(page) diff --git a/e2e/studio/features/rls-policies.spec.ts b/e2e/studio/features/rls-policies.spec.ts index 495c4a41377..ac615c4a382 100644 --- a/e2e/studio/features/rls-policies.spec.ts +++ b/e2e/studio/features/rls-policies.spec.ts @@ -1,65 +1,9 @@ import { expect, Page } from '@playwright/test' -import { test } from '../utils/test.js' + +import { test, withSetupCleanup } from '../utils/test.js' import { toUrl } from '../utils/to-url.js' import { createApiResponseWaiter, waitForApiResponse } from '../utils/wait-for-response.js' - -const policyTableName = 'pw_rls_policy_test_table' -const policySelectName = 'pw_test_select_policy' -const policyInsertName = 'pw_test_insert_policy' -const policyUpdateName = 'pw_test_update_policy' -const policyDeleteName = 'pw_test_delete_policy' - -/** - * Helper function to create a test table for RLS policies - */ -const createTestTable = async (page: Page, ref: string) => { - await page.goto(toUrl(`/project/${ref}/editor`)) - await page.waitForTimeout(1000) - - // Check if table already exists - const tableExists = - (await page.getByRole('button', { name: `View ${policyTableName}` }).count()) > 0 - - if (!tableExists) { - await page.getByRole('button', { name: 'New table', exact: true }).click() - await page.getByTestId('table-name-input').fill(policyTableName) - await page.getByRole('button', { name: 'Save' }).click() - - await expect( - page.getByText(`Table ${policyTableName} is good to go!`), - 'Table creation confirmation should be visible' - ).toBeVisible({ timeout: 50000 }) - } -} - -/** - * Helper function to delete the test table - */ -const deleteTestTable = async (page: Page, ref: string) => { - await page.goto(toUrl(`/project/${ref}/editor`)) - await page.waitForTimeout(1000) - - const tableExists = - (await page.getByRole('button', { name: `View ${policyTableName}` }).count()) > 0 - - if (tableExists) { - await page.getByLabel(`View ${policyTableName}`).nth(0).click() - // Open the row actions menu (three dots) using the same selector pattern as table-editor.spec.ts. - // This avoids brittle index-based selection and ignores the Unrestricted badge button. - await page - .getByLabel(`View ${policyTableName}`) - .locator('button[aria-haspopup="menu"]') - .click({ force: true }) - await page.getByText('Delete table').click() - await page.getByRole('checkbox', { name: 'Drop table with cascade?' }).click() - await page.getByRole('button', { name: 'Delete' }).click() - - await expect( - page.getByText(`Successfully deleted table "${policyTableName}"`), - 'Table deletion confirmation should be visible' - ).toBeVisible({ timeout: 50000 }) - } -} +import { createTableWithRLS, dropTable } from '../utils/db/queries.js' /** * Helper function to navigate to policies page and wait for it to load @@ -104,27 +48,18 @@ const deletePolicyIfExists = async (page: Page, ref: string, policyNameToDelete: } } -test.describe.serial('RLS Policies', () => { - let page: Page - - test.beforeAll(async ({ browser, ref }) => { - page = await browser.newPage() - - // Create test table - await createTestTable(page, ref) - - // Navigate to policies page - await navigateToPoliciesPage(page, ref) - }) - - test.afterAll(async ({ ref }) => { - // Clean up: delete test table - await deleteTestTable(page, ref) - await page.close() - }) - +test.describe('RLS Policies', () => { test.describe('Policies Page', () => { - test('should display policies page correctly', async ({ ref }) => { + test('should display policies page correctly', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_test_table' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) // Check page elements @@ -143,7 +78,16 @@ test.describe.serial('RLS Policies', () => { await expect(page.getByText(policyTableName)).toBeVisible() }) - test('should filter tables and policies by search', async ({ ref }) => { + test('should filter tables and policies by search', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_filter_table' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) const searchInput = page.getByPlaceholder('Filter tables and policies') @@ -160,7 +104,7 @@ test.describe.serial('RLS Policies', () => { await page.waitForTimeout(500) }) - test('should switch between schemas', async ({ ref }) => { + test('should switch between schemas', async ({ page, ref }) => { await navigateToPoliciesPage(page, ref) // Click schema selector @@ -181,7 +125,19 @@ test.describe.serial('RLS Policies', () => { }) test.describe('Table editor RLS badge', () => { - test('shows Unrestricted badge when RLS is disabled for public table', async ({ ref }) => { + test('shows Unrestricted badge when RLS is disabled for public table', async ({ + page, + ref, + }) => { + const policyTableName = 'pw_rls_policy_unrestricted_table' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) // First, ensure RLS is disabled for the test table via the Policies page await navigateToPoliciesPage(page, ref) @@ -241,12 +197,19 @@ test.describe.serial('RLS Policies', () => { }) test.describe('Create RLS Policy', () => { - test('should create a SELECT policy successfully', async ({ ref }) => { + test('should create a SELECT policy successfully', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_select_table' + const policySelectName = 'pw_test_select_policy' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) - // Delete policy if it exists from previous run - await deletePolicyIfExists(page, ref, policySelectName) - // Find the test table and click "Create policy" await page.getByTestId(`${policyTableName}-create-policy`).click() @@ -256,6 +219,9 @@ test.describe.serial('RLS Policies', () => { 'Policy creation dialog should open' ).toBeVisible() + // Hide the sidebar tools + await page.getByText('Hide tools').click() + // Fill in policy name await page.getByRole('textbox', { name: 'Policy Name' }).fill(policySelectName) @@ -287,12 +253,19 @@ test.describe.serial('RLS Policies', () => { await expect(policyRow.locator('code').filter({ hasText: /^public$/ })).toBeVisible() }) - test('should create an INSERT policy with authenticated role', async ({ ref }) => { + test('should create an INSERT policy with authenticated role', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_insert_table' + const policyInsertName = 'pw_test_insert_policy' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) - // Delete policy if it exists - await deletePolicyIfExists(page, ref, policyInsertName) - // Open create policy dialog await page.getByTestId(`${policyTableName}-create-policy`).click() @@ -300,6 +273,9 @@ test.describe.serial('RLS Policies', () => { page.getByRole('heading', { name: 'Create a new Row Level Security policy' }) ).toBeVisible() + // Hide the sidebar tools + await page.getByText('Hide tools').click() + // Fill in policy name await page.getByRole('textbox', { name: 'Policy Name' }).fill(policyInsertName) @@ -332,12 +308,19 @@ test.describe.serial('RLS Policies', () => { await expect(policyRow.locator('code').filter({ hasText: /^authenticated$/ })).toBeVisible() }) - test('should create an UPDATE policy with custom condition', async ({ ref }) => { + test('should create an UPDATE policy with custom condition', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_update_table' + const policyUpdateName = 'pw_test_update_policy' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) - // Delete policy if it exists - await deletePolicyIfExists(page, ref, policyUpdateName) - // Open create policy dialog await page.getByTestId(`${policyTableName}-create-policy`).click() @@ -345,6 +328,9 @@ test.describe.serial('RLS Policies', () => { page.getByRole('heading', { name: 'Create a new Row Level Security policy' }) ).toBeVisible() + // Hide the sidebar tools + await page.getByText('Hide tools').click() + // Fill in policy name await page.getByRole('textbox', { name: 'Policy Name' }).fill(policyUpdateName) @@ -374,12 +360,19 @@ test.describe.serial('RLS Policies', () => { await expect(policyRow.locator('code').filter({ hasText: /^UPDATE$/ })).toBeVisible() }) - test('should create a DELETE policy', async ({ ref }) => { + test('should create a DELETE policy', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_delete_table' + const policyDeleteName = 'pw_test_delete_policy' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) - // Delete policy if it exists - await deletePolicyIfExists(page, ref, policyDeleteName) - // Open create policy dialog await page.getByTestId(`${policyTableName}-create-policy`).click() @@ -387,6 +380,9 @@ test.describe.serial('RLS Policies', () => { page.getByRole('heading', { name: 'Create a new Row Level Security policy' }) ).toBeVisible() + // Hide the sidebar tools + await page.getByText('Hide tools').click() + // Fill in policy name await page.getByRole('textbox', { name: 'Policy Name' }).fill(policyDeleteName) @@ -416,7 +412,16 @@ test.describe.serial('RLS Policies', () => { await expect(policyRow.locator('code').filter({ hasText: /^DELETE$/ })).toBeVisible() }) - test('should cancel policy creation', async ({ ref }) => { + test('should cancel policy creation', async ({ page, ref }) => { + const policyTableName = 'pw_rls_policy_cancel_table' + await using _ = await withSetupCleanup( + async () => { + await createTableWithRLS(policyTableName, 'test') + }, + async () => { + await dropTable(policyTableName) + } + ) await navigateToPoliciesPage(page, ref) // Open create policy dialog @@ -430,7 +435,7 @@ test.describe.serial('RLS Policies', () => { await page.getByRole('textbox', { name: 'Policy Name' }).fill('policy_to_cancel') // Click cancel - await page.getByRole('button', { name: 'Cancel' }).click() + await page.getByRole('button', { name: 'Cancel', exact: true }).click() // Dialog should close await expect(