Editor mode is now stored as a global preference in VaultConfig instead of being tracked per-tab. Toggling raw mode persists across tab switches and app restarts via the editor_mode field in config/ui.config.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
155 lines
5.0 KiB
TypeScript
155 lines
5.0 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
import { renderHook, act } from '@testing-library/react'
|
|
import { useRawMode } from './useRawMode'
|
|
import * as store from '../utils/vaultConfigStore'
|
|
|
|
describe('useRawMode', () => {
|
|
let onFlushPending: ReturnType<typeof vi.fn>
|
|
|
|
beforeEach(() => {
|
|
onFlushPending = vi.fn().mockResolvedValue(true)
|
|
// Reset vault config to defaults before each test
|
|
store.resetVaultConfigStore()
|
|
store.bindVaultConfigStore(
|
|
{ zoom: null, view_mode: null, editor_mode: null, tag_colors: null, status_colors: null, property_display_modes: null },
|
|
vi.fn(),
|
|
)
|
|
})
|
|
|
|
afterEach(() => {
|
|
store.resetVaultConfigStore()
|
|
})
|
|
|
|
function renderRawHook(activeTabPath: string | null = '/note.md') {
|
|
return renderHook(
|
|
({ path }) => useRawMode({ activeTabPath: path, onFlushPending }),
|
|
{ initialProps: { path: activeTabPath } },
|
|
)
|
|
}
|
|
|
|
it('starts with raw mode off', () => {
|
|
const { result } = renderRawHook()
|
|
expect(result.current.rawMode).toBe(false)
|
|
})
|
|
|
|
it('toggles raw mode on', async () => {
|
|
const { result } = renderRawHook()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(result.current.rawMode).toBe(true)
|
|
})
|
|
|
|
it('flushes pending edits when activating raw mode', async () => {
|
|
const { result } = renderRawHook()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(onFlushPending).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('does not flush pending edits when deactivating raw mode', async () => {
|
|
const { result } = renderRawHook()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
onFlushPending.mockClear()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(onFlushPending).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('toggles raw mode off when already on', async () => {
|
|
const { result } = renderRawHook()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(result.current.rawMode).toBe(true)
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(result.current.rawMode).toBe(false)
|
|
})
|
|
|
|
it('persists raw mode across tab switches', async () => {
|
|
const { result, rerender } = renderRawHook('/note-a.md')
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(result.current.rawMode).toBe(true)
|
|
|
|
rerender({ path: '/note-b.md' })
|
|
expect(result.current.rawMode).toBe(true)
|
|
})
|
|
|
|
it('works without onFlushPending callback', async () => {
|
|
const { result } = renderHook(() => useRawMode({ activeTabPath: '/note.md' }))
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(result.current.rawMode).toBe(true)
|
|
})
|
|
|
|
it('does not activate raw mode when activeTabPath is null', async () => {
|
|
const { result } = renderRawHook(null)
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
// rawMode is false because there's no active tab, even though preference is enabled
|
|
expect(result.current.rawMode).toBe(false)
|
|
})
|
|
|
|
it('calls onBeforeRawEnd when deactivating raw mode', async () => {
|
|
const onBeforeRawEnd = vi.fn()
|
|
const { result } = renderHook(
|
|
({ path }) => useRawMode({ activeTabPath: path, onFlushPending, onBeforeRawEnd }),
|
|
{ initialProps: { path: '/note.md' } },
|
|
)
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(result.current.rawMode).toBe(true)
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(onBeforeRawEnd).toHaveBeenCalledOnce()
|
|
expect(result.current.rawMode).toBe(false)
|
|
})
|
|
|
|
it('does not call onBeforeRawEnd when activating raw mode', async () => {
|
|
const onBeforeRawEnd = vi.fn()
|
|
const { result } = renderHook(
|
|
({ path }) => useRawMode({ activeTabPath: path, onFlushPending, onBeforeRawEnd }),
|
|
{ initialProps: { path: '/note.md' } },
|
|
)
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
|
|
expect(onBeforeRawEnd).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('persists editor_mode to vault config on toggle', async () => {
|
|
const saveFn = vi.fn()
|
|
store.resetVaultConfigStore()
|
|
store.bindVaultConfigStore(
|
|
{ zoom: null, view_mode: null, editor_mode: null, tag_colors: null, status_colors: null, property_display_modes: null },
|
|
saveFn,
|
|
)
|
|
|
|
const { result } = renderRawHook()
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(store.getVaultConfig().editor_mode).toBe('raw')
|
|
|
|
await act(async () => { await result.current.handleToggleRaw() })
|
|
expect(store.getVaultConfig().editor_mode).toBe('preview')
|
|
})
|
|
|
|
it('restores raw mode from vault config on init', () => {
|
|
store.resetVaultConfigStore()
|
|
store.bindVaultConfigStore(
|
|
{ zoom: null, view_mode: null, editor_mode: 'raw', tag_colors: null, status_colors: null, property_display_modes: null },
|
|
vi.fn(),
|
|
)
|
|
|
|
const { result } = renderRawHook()
|
|
expect(result.current.rawMode).toBe(true)
|
|
})
|
|
})
|