From 8bb82bb3a5aee631e8e6e6e0c8a5f6e97fb8f898 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Tue, 20 Jan 2026 19:17:26 +0200 Subject: [PATCH] chore: Add test for creating and removing foreign keys (#41262) Add test for creating and removing foreign keys. --- e2e/studio/features/table-editor.spec.ts | 140 +++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/e2e/studio/features/table-editor.spec.ts b/e2e/studio/features/table-editor.spec.ts index ec66e4b8a8e..af65d8c52b3 100644 --- a/e2e/studio/features/table-editor.spec.ts +++ b/e2e/studio/features/table-editor.spec.ts @@ -1032,4 +1032,144 @@ testRunner('table editor', () => { // Cleanup await deleteTable(page, ref, tableName) }) + + test('can create and remove foreign key with column selection', async ({ page, ref }) => { + const sourceTableName = 'pw_table_fk_source' + const targetTableName = 'pw_table_fk_target' + + if (!page.url().includes('/editor')) { + await page.goto(toUrl(`/project/${ref}/editor?schema=public`)) + await waitForTableToLoad(page, ref) + } + + await dismissToastsIfAny(page) + + // Create target table first (will be referenced) + await createTable(page, ref, targetTableName) + + // Create source table (will have the foreign key) + await createTable(page, ref, sourceTableName) + await page.getByRole('button', { name: `View ${sourceTableName}`, exact: true }).click() + await page.waitForURL(/\/editor\/\d+\?schema=public$/) + + // Open edit table dialog + await page + .getByRole('button', { name: `View ${sourceTableName}`, exact: true }) + .locator('button[aria-haspopup="menu"]') + .click() + await page.getByRole('menuitem', { name: 'Edit table' }).click() + + // Open foreign key selector + await page.getByRole('button', { name: 'Add foreign key relation' }).click() + + // Select schema (should default to public) + await expect(page.getByRole('button', { name: 'Select a schema' })).toContainText('public') + + // Select target table + const tableQueryPromise = waitForApiResponseWithTimeout(page, (response) => + response.url().includes(`table-public-${targetTableName}`) + ) + + await page.getByRole('button', { name: 'Select a table to reference to' }).click() + await page.getByRole('menuitem', { name: `public ${targetTableName}` }).click() + + // Wait for table columns to load + await tableQueryPromise + + // Verify column selection UI appears + await expect( + page.getByText(`Select columns from public.${targetTableName} to reference to`) + ).toBeVisible() + + // Select source column (id from source table) + await page.getByRole('button', { name: '---' }).first().click() + await page.getByRole('menuitem', { name: 'id int8' }).click() + + // Wait for the first dropdown to update - there should only be one '---' button left now + await expect(page.getByRole('button', { name: '---' })).toHaveCount(1) + + // Select target column (id from target table) + await page.getByRole('button', { name: '---' }).first().click() + await page.getByRole('menuitem', { name: 'id int8' }).click() + + // Verify cascade action options are visible + await expect(page.getByText('Action if referenced row is updated')).toBeVisible() + await expect(page.getByText('Action if referenced row is removed')).toBeVisible() + + // Verify save button is now enabled + const saveButton = page.getByRole('button', { name: 'Save' }).last() + await expect(saveButton).toBeEnabled() + + // Save the foreign key + const fkCreatePromise = waitForApiResponseWithTimeout(page, (response) => + response.url().includes('query?key=') + ) + await saveButton.click() + await fkCreatePromise + + // Verify foreign key selector closed + await expect( + page.getByRole('banner', { name: `Add foreign key relationship to ${sourceTableName}` }) + ).not.toBeVisible() + + // Save table changes + const saveTablePromise = waitForApiResponseWithTimeout( + page, + (response) => response.url().includes('query?key=table-update'), + 15000 + ) + await page.getByRole('button', { name: 'Save' }).first().click() + await saveTablePromise + + // Wait for table editor side panel to close + await expect(page.getByTestId('table-editor-side-panel')).not.toBeVisible() + + // Verify foreign key was created by opening edit table dialog again + await page + .getByRole('button', { name: `View ${sourceTableName}`, exact: true }) + .locator('button[aria-haspopup="menu"]') + .click() + await page.getByRole('menuitem', { name: 'Edit table' }).click() + + // Scroll down to see foreign key relations section + await page.getByRole('heading', { name: 'Foreign keys' }).scrollIntoViewIfNeeded() + + // Verify foreign key relation exists + await expect(page.getByRole('link', { name: 'public.pw_table_fk_target' })).toBeVisible() + + // Remove the foreign key relation + await page.getByRole('button', { name: 'Remove' }).click() + + // Save the table changes after removing foreign key + const removeFkPromise = waitForApiResponseWithTimeout( + page, + (response) => response.url().includes('query?key=table-update'), + 15000 + ) + await page.getByRole('button', { name: 'Save' }).first().click() + await removeFkPromise + + // Wait for table editor side panel to close + await expect(page.getByTestId('table-editor-side-panel')).not.toBeVisible() + + // Verify foreign key was removed by opening edit table dialog again + await page + .getByRole('button', { name: `View ${sourceTableName}`, exact: true }) + .locator('button[aria-haspopup="menu"]') + .click() + await page.getByRole('menuitem', { name: 'Edit table' }).click() + + // Scroll down to see foreign key relations section + await page.getByRole('heading', { name: 'Foreign keys' }).scrollIntoViewIfNeeded() + // Verify foreign key relation no longer exists + await expect(page.getByText(`public.${targetTableName}`, { exact: false })).not.toBeVisible() + + // Close the edit table dialog + await page.getByRole('button', { name: 'Cancel' }).click() + await expect(page.getByTestId('table-editor-side-panel')).not.toBeVisible() + + // Clean up + await deleteTable(page, ref, sourceTableName) + await deleteTable(page, ref, targetTableName) + }) })