Files
supabase/apps/studio/hooks/misc/useDashboardHistory.test.tsx
Joshen Lim ad30c04e0e Persist last visited explorer tab (#50557)
## Context

Saves the last visited explorer tab via `useDashboardHistory`, such that
landing back on `/explorer` will open the last visited page. Similar
behaviour to Table Editor and SQL Editor

Would also be useful when going between the SQL Editor and Explorer to
bring snippets over

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Explorer now remembers and restores the last visited query, chat, or
notebook tab.
* Automatically returns to the Explorer home screen when a saved tab is
unavailable.
* Displays a loading state while the last visited tab is being restored.

* **Bug Fixes**
  * Closing deleted chat tabs now clears their saved history.

* **Tests**
* Added coverage for Explorer tab restoration, loading states, and stale
history cleanup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-21 16:34:50 +08:00

105 lines
4.0 KiB
TypeScript

import { act, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it } from 'vitest'
import { useDashboardHistory } from './useDashboardHistory'
import { customRenderHook } from '@/tests/lib/custom-render'
// useParams from 'common' is globally mocked to { ref: 'default' } in vitestSetup
const renderDashboardHistory = async () => {
const utils = customRenderHook(() => useDashboardHistory())
await waitFor(() => expect(utils.result.current.isHistoryLoaded).toBe(true))
return utils
}
describe('useDashboardHistory', () => {
beforeEach(() => {
localStorage.clear()
})
it('stores the last visited snippet', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedSnippet('snippet-a'))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
})
describe('clearSnippetsFromHistory', () => {
it('purges the last visited snippet when it is one of the deleted ids', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedSnippet('snippet-a'))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
act(() => result.current.clearSnippetsFromHistory(['snippet-b', 'snippet-a']))
await waitFor(() => expect(result.current.history.sql).toBeUndefined())
})
it('keeps the last visited snippet when it is not among the deleted ids', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedSnippet('snippet-a'))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
act(() => result.current.clearSnippetsFromHistory(['snippet-b']))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
})
it('does not touch the table editor history', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedTable('table-1'))
// setLastVisitedSnippet spreads the render-time history, so wait for the
// table update to propagate before setting the snippet
await waitFor(() => expect(result.current.history.editor).toBe('table-1'))
act(() => result.current.setLastVisitedSnippet('snippet-a'))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
act(() => result.current.clearSnippetsFromHistory(['snippet-a']))
await waitFor(() => expect(result.current.history.sql).toBeUndefined())
expect(result.current.history.editor).toBe('table-1')
})
})
describe('setLastVisitedExplorerTab', () => {
it('stores the last visited Explorer tab', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedExplorerTab({ type: 'notebook', id: 'notebook-1' }))
await waitFor(() =>
expect(result.current.history.explorer).toEqual({ type: 'notebook', id: 'notebook-1' })
)
})
it('clears the last visited Explorer tab when called with undefined', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedExplorerTab({ type: 'chat', id: 'chat-1' }))
await waitFor(() => expect(result.current.history.explorer).toBeDefined())
act(() => result.current.setLastVisitedExplorerTab(undefined))
await waitFor(() => expect(result.current.history.explorer).toBeUndefined())
})
it('does not touch the SQL or table editor history', async () => {
const { result } = await renderDashboardHistory()
act(() => result.current.setLastVisitedSnippet('snippet-a'))
await waitFor(() => expect(result.current.history.sql).toBe('snippet-a'))
act(() => result.current.setLastVisitedExplorerTab({ type: 'query', id: 'query-1' }))
await waitFor(() =>
expect(result.current.history.explorer).toEqual({ type: 'query', id: 'query-1' })
)
expect(result.current.history.sql).toBe('snippet-a')
})
})
})