mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix(studio): prevent redirect loops and restore TanStack E2E tests
This commit is contained in:
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()
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -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.
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in new issue
Block a user