fix(studio): prevent redirect loops and restore TanStack E2E tests

This commit is contained in:
Alaister Young committed 2026-10-01 16:46:00 -07:00
1 parent da2d0c46d7
commit a50ebee88c
5 files changed
+68 -38

No files matched your search

@@ -0,0 +1,62 @@
import {
createMemoryHistory,
createRootRoute,
createRoute,
createRouter,
Outlet,
RouterProvider,
} from '@tanstack/react-router'
import { act, render, screen } from '@testing-library/react'
import { useEffect } from 'react'
import { describe, expect, it } from 'vitest'
import { useRouter } from './router'
describe('next/router redirect effects', () => {
it('keeps the router object stable when only match loading state changes', async () => {
const seen: ReturnType<typeof useRouter>[] = []
const rootRoute = createRootRoute({ component: Outlet })
const dataRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/project/$ref/database/triggers/data',
component: function DataPage() {
const router = useRouter()
useEffect(() => {
seen.push(router)
}, [router])
return <div>Triggers loaded</div>
},
})
const router = createRouter({
routeTree: rootRoute.addChildren([dataRoute]),
history: createMemoryHistory({
initialEntries: ['/project/default/database/triggers/data?schema=public'],
}),
})
await router.load()
const view = render(<RouterProvider router={router} />)
try {
await screen.findByText('Triggers loaded')
const initial = seen.at(-1)
await act(async () => {
await router.invalidate()
})
expect(seen.at(-1)).toBe(initial)
expect(initial?.pathname).toBe('/project/[ref]/database/triggers/data')
expect(initial?.query).toEqual({ ref: 'default', schema: 'public' })
await act(async () => {
await router.navigate({
to: '/project/$ref/database/triggers/data',
params: { ref: 'other' },
search: { schema: 'realtime' },
})
})
expect(seen.at(-1)).not.toBe(initial)
expect(seen.at(-1)?.asPath).toBe('/project/other/database/triggers/data?schema=realtime')
expect(seen.at(-1)?.query).toEqual({ ref: 'other', schema: 'realtime' })
} finally {
view.unmount()
}
})
})
+6 -4
View File
@@ -252,13 +252,15 @@ type PrefetchOptions = {
export function useRouter() {
const router = useTanStackRouter()
const location = useLocation()
const matches = useMatches()
// Match objects change while a navigation loads. Only the leaf route ID
// affects Next's pathname; subscribing to all matches changes this router
// object and can restart effects that are already redirecting the page.
const leafRouteId = useMatches({ select: (matches) => matches[matches.length - 1]?.routeId })
const params = useParams({ strict: false })
const search = useSearch({ strict: false })
return useMemo(() => {
const leafRouteId = matches[matches.length - 1]?.routeId ?? location.pathname
const pathPattern = toNextPathPattern(leafRouteId)
const pathPattern = toNextPathPattern(leafRouteId ?? location.pathname)
// Both push and replace accept Next's (url, as?, options?) signature.
// `as` is the legacy alias path (mostly obsolete in modern Next; ignored
@@ -397,7 +399,7 @@ export function useRouter() {
// ---- events ----
events: getRouterEventsProxy(router),
}
}, [router, location.href, location.pathname, matches, params, search])
}, [router, location.href, location.pathname, leafRouteId, params, search])
}
// Normalise an optional-catch-all route's params across both frameworks.
-1
View File
@@ -22,7 +22,6 @@ export const env = {
API_URL: process.env.API_URL || 'http://127.0.0.1:54321',
IS_PLATFORM: toBoolean(process.env.IS_PLATFORM || 'false'),
STUDIO_FRAMEWORK: process.env.STUDIO_FRAMEWORK || 'next',
EMAIL: process.env.EMAIL,
PASSWORD: process.env.PASSWORD,
PROJECT_REF: process.env.PROJECT_REF || undefined,
@@ -1,6 +1,5 @@
import { expect, Page } from '@playwright/test'
import { env } from '../env.config.js'
import { dropTable, query } from '../utils/db/index.js'
import { dismissToastsIfAny } from '../utils/dismiss-toast.js'
import { openTableContextMenu } from '../utils/table-helpers.js'
@@ -200,14 +199,6 @@ test.describe('API Access Toggle', () => {
})
test('shows Manage access link when editing an existing table', async ({ page, ref }) => {
// TODO(tanstack): the entity-types pg-meta query that waitForTableToLoad
// waits on consistently times out (>30s) under the TanStack Start server
// but not under Next — see PR #51141. Re-enable once the root cause is found.
test.skip(
env.STUDIO_FRAMEWORK === 'tanstack',
'pg-meta entity-types query hangs under the TanStack Start server (#51141)'
)
const tableName = `${TABLE_NAME_PREFIX}_edit`
await using _ = await withSetupCleanup(
async () => {
@@ -266,14 +257,6 @@ test.describe('API Access Toggle', () => {
page,
ref,
}) => {
// TODO(tanstack): the entity-types pg-meta query that waitForTableToLoad
// waits on consistently times out (>30s) under the TanStack Start server
// but not under Next — see PR #51141. Re-enable once the root cause is found.
test.skip(
env.STUDIO_FRAMEWORK === 'tanstack',
'pg-meta entity-types query hangs under the TanStack Start server (#51141)'
)
const tableName = `${TABLE_NAME_PREFIX}_preserve_grants`
await using _ = await withSetupCleanup(
async () => {
-16
View File
@@ -540,14 +540,6 @@ test.describe('Database', () => {
test.describe('Triggers', () => {
test('actions works as expected', async ({ page, ref }) => {
// TODO(tanstack): triggers/entity-types pg-meta queries consistently
// time out (>30s) under the TanStack Start server but not under Next —
// see PR #51141. Re-enable once the root cause is found.
test.skip(
env.STUDIO_FRAMEWORK === 'tanstack',
'pg-meta triggers query hangs under the TanStack Start server (#51141)'
)
const triggersLoadWait = createApiResponseWaiter(page, 'pg-meta', ref, 'query?key=triggers')
await page.goto(toUrl(`/project/${env.PROJECT_REF}/database/triggers?schema=public`))
@@ -572,14 +564,6 @@ test.describe('Database', () => {
})
test('CRUD operations works as expected', async ({ page, ref }) => {
// TODO(tanstack): triggers/entity-types pg-meta queries consistently
// time out (>30s) under the TanStack Start server but not under Next —
// see PR #51141. Re-enable once the root cause is found.
test.skip(
env.STUDIO_FRAMEWORK === 'tanstack',
'pg-meta triggers query hangs under the TanStack Start server (#51141)'
)
const databaseTableName = 'pw_database_trigger_table'
const databaseColumnName = 'pw_database_column_trigger'
const databaseTriggerName = 'pw_database_trigger'