From ffff017ce66b4cd66aecb262d5488226973f1a78 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 2 Apr 2026 00:34:35 +0800 Subject: [PATCH] Add e2e tests --- .../interfaces/ConnectSheet/ConnectSheet.tsx | 2 +- e2e/studio/features/connect.spec.ts | 130 ++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx b/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx index 88b24341142..d01013598f1 100644 --- a/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx +++ b/apps/studio/components/interfaces/ConnectSheet/ConnectSheet.tsx @@ -69,7 +69,7 @@ export const ConnectSheet = () => { setMode(mappedMode) } - if (mappedMode === 'framework' || connectTab === 'frameworks' || connectTab === 'mobiles') { + if (mappedMode === 'framework') { if (queryFramework) { updateField('framework', queryFramework) if (queryUsing) updateField('frameworkVariant', queryUsing) diff --git a/e2e/studio/features/connect.spec.ts b/e2e/studio/features/connect.spec.ts index 893657634fb..0cb908f7740 100644 --- a/e2e/studio/features/connect.spec.ts +++ b/e2e/studio/features/connect.spec.ts @@ -54,3 +54,133 @@ test.describe('Connect', async () => { await expect(page).toHaveURL(/showConnect=true/) }) }) + +test.describe('Connect Sheet deep linking', async () => { + test('pre-selects framework and variant from URL params', async ({ page, ref }) => { + await page.goto( + toUrl( + `/project/${ref}?showConnect=true&connectTab=framework&framework=nextjs&using=pages` + ) + ) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open from deep link' + ).toBeVisible({ timeout: 30000 }) + + await expect( + page.getByRole('combobox').filter({ hasText: 'Next.js' }), + 'Framework select should show Next.js' + ).toBeVisible() + + await expect( + page.getByRole('combobox').filter({ hasText: 'Pages Router' }), + 'Variant select should show Pages Router' + ).toBeVisible() + }) + + test('supports legacy frameworks tab alias', async ({ page, ref }) => { + await page.goto( + toUrl(`/project/${ref}?showConnect=true&connectTab=frameworks&framework=nextjs`) + ) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open with legacy tab alias' + ).toBeVisible({ timeout: 30000 }) + + await expect( + page.getByRole('combobox').filter({ hasText: 'Next.js' }), + 'Framework select should show Next.js via legacy connectTab alias' + ).toBeVisible() + }) + + test('pre-selects ORM from URL params', async ({ page, ref }) => { + // Use drizzle (non-default) to verify the param takes effect + await page.goto(toUrl(`/project/${ref}?showConnect=true&connectTab=orm&framework=drizzle`)) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open from deep link' + ).toBeVisible({ timeout: 30000 }) + + await expect( + page.locator('[data-state="checked"]').filter({ hasText: 'Drizzle' }), + 'Drizzle radio should be selected' + ).toBeVisible() + }) + + test('pre-selects MCP client from URL params', async ({ page, ref }) => { + await page.goto(toUrl(`/project/${ref}?showConnect=true&connectTab=mcp&mcpClient=goose`)) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open from deep link' + ).toBeVisible({ timeout: 30000 }) + + await expect( + page.getByRole('combobox').filter({ hasText: 'Goose' }), + 'MCP client select should show Goose' + ).toBeVisible() + }) + + test('pre-selects direct connection method from URL params', async ({ page, ref }) => { + await page.goto( + toUrl(`/project/${ref}?showConnect=true&connectTab=direct&method=transaction`) + ) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open from deep link' + ).toBeVisible({ timeout: 30000 }) + + await expect( + page.locator('[data-state="checked"]').filter({ hasText: 'Transaction pooler' }), + 'Transaction pooler radio should be selected' + ).toBeVisible() + }) + + test('closing the sheet clears all deep-link params from URL', async ({ page, ref }) => { + await page.goto( + toUrl( + `/project/${ref}?showConnect=true&connectTab=framework&framework=nextjs&using=pages` + ) + ) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open' + ).toBeVisible({ timeout: 30000 }) + + await page.keyboard.press('Escape') + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should close' + ).not.toBeVisible({ timeout: 10000 }) + + await expect(page, 'connectTab param should be removed').not.toHaveURL(/connectTab/) + await expect(page, 'framework param should be removed').not.toHaveURL(/[?&]framework=/) + await expect(page, 'using param should be removed').not.toHaveURL(/using=/) + }) + + test('changing mode clears previous mode params from URL', async ({ page, ref }) => { + await page.goto( + toUrl(`/project/${ref}?showConnect=true&connectTab=framework&framework=nextjs`) + ) + + await expect( + page.getByRole('heading', { name: 'Connect to your project' }), + 'ConnectSheet should open' + ).toBeVisible({ timeout: 30000 }) + + await expect(page, 'framework param should be in URL initially').toHaveURL(/framework=nextjs/) + + await page.getByRole('button', { name: /ORM/ }).click() + + await expect(page, 'framework param should be cleared after mode change').not.toHaveURL( + /framework=nextjs/ + ) + await expect(page, 'connectTab should update to orm').toHaveURL(/connectTab=orm/) + }) +})