Files
supabase/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.test.tsx
Charis 08c4f64c42 test(sql-editor): add mock-free hook tests (Step 4) (#48214)
## What

Step 4 of the SQL editor testability plan: **mock-free hook tests** for
the extracted SQL editor hooks, built on the Step 3 renderHook harness
(`tests/lib/sql-editor-test-utils.tsx`) — in-memory editor port + real
valtio stores + MSW. **Zero `vi.mock`.**

| File | Tests | Covers |
|------|-------|--------|
| `useSqlEditorExecution.test.tsx` | 8 | destructive-query gating
(`potentialIssues` vs. forced run), auto-limit suffixing,
connection-string → `x-connection-encrypted` header,
`onSuccess`/`onError` session-store writes, error-line highlight,
diff-open short-circuit |
| `useSqlEditorAi.test.tsx` | 7 | one-shot diff-request drain (empty vs.
non-empty editor), drain-exactly-once across remounts, accept/discard
diff, `onDebug` opening the assistant chat + debug prompt |
| `usePrettifyQuery.test.tsx` | 2 | in-place format + write-back,
diff-open no-op |
| `useSnippetIdentity.test.tsx` | 2 | generated identity + store-driven
loading state |
| `useSnippetTitleGenerator.test.tsx` | 2 | untitled-snippet naming via
the title endpoint |

Every test exercises real dependencies at the seam where they're real:
network via MSW, stores used real and reset per test, Monaco via the
in-memory editor port.

## Test plan

- [x] `pnpm test:studio -- SQLEditor` → **286/286 passing** (21 new
tests included)
- [x] `pnpm --filter studio typecheck` clean
- [x] Confirmed zero `vi.mock` in the new files


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

## Summary by CodeRabbit

* **Tests**
* Added comprehensive automated coverage for SQL query formatting,
snippet identity, and AI-generated titles.
* Added coverage for AI-assisted SQL editing, including diff acceptance,
rejection, debugging, and request handling.
* Added coverage for query execution, result persistence, safety checks,
replica selection, error highlighting, and diff-state behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-22 14:53:46 -04:00

68 lines
2.2 KiB
TypeScript

import { act, waitFor } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { usePrettifyQuery } from './usePrettifyQuery'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { formatSql } from '@/lib/formatSql'
import { sqlEditorState } from '@/state/sql-editor/sql-editor-state'
import {
createInMemoryEditor,
renderSqlEditorHook,
resetSqlEditorStores,
seedSnippet,
setupSqlEditorMocks,
} from '@/tests/lib/sql-editor-test-utils'
const SNIPPET_ID = 'prettify-snippet'
const MESSY_SQL = 'select id,name from users'
function usePrettifyHarness({ isDiffOpen }: { isDiffOpen: boolean }) {
const { data: project } = useSelectedProjectQuery()
const prettifyQuery = usePrettifyQuery({ id: SNIPPET_ID, isDiffOpen })
return { prettifyQuery, isReady: !!project }
}
beforeEach(() => {
resetSqlEditorStores()
setupSqlEditorMocks()
seedSnippet({ id: SNIPPET_ID, name: 'My query', sql: MESSY_SQL })
})
afterEach(() => {
resetSqlEditorStores()
})
describe('usePrettifyQuery', () => {
it('formats the editor SQL in place and writes it back to the snippet store', async () => {
const inMemoryEditor = createInMemoryEditor(MESSY_SQL)
const { result } = renderSqlEditorHook(
(props: { isDiffOpen: boolean }) => usePrettifyHarness(props),
{ inMemoryEditor, initialProps: { isDiffOpen: false } }
)
await waitFor(() => expect(result.current.isReady).toBe(true))
await act(async () => {
await result.current.prettifyQuery()
})
const expected = formatSql(MESSY_SQL)
expect(inMemoryEditor.editor.getValue()).toBe(expected)
expect(sqlEditorState.snippets[SNIPPET_ID].snippet.content?.unchecked_sql).toBe(expected)
})
it('is a no-op while a diff is open', async () => {
const inMemoryEditor = createInMemoryEditor(MESSY_SQL)
const { result } = renderSqlEditorHook(
(props: { isDiffOpen: boolean }) => usePrettifyHarness(props),
{ inMemoryEditor, initialProps: { isDiffOpen: true } }
)
await waitFor(() => expect(result.current.isReady).toBe(true))
await act(async () => {
await result.current.prettifyQuery()
})
expect(inMemoryEditor.editor.getValue()).toBe(MESSY_SQL)
})
})