133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
import { act, renderHook } from '@testing-library/react'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import type { MutableRefObject } from 'react'
|
|
import type { SidebarSelection, VaultEntry } from '../types'
|
|
import {
|
|
useNeighborhoodEntry,
|
|
useNeighborhoodEscape,
|
|
} from './useNeighborhoodSelection'
|
|
|
|
function buildEntry(path: string, title: string): VaultEntry {
|
|
return {
|
|
path,
|
|
filename: `${title.toLowerCase()}.md`,
|
|
title,
|
|
isA: 'Note',
|
|
aliases: [],
|
|
belongsTo: [],
|
|
relatedTo: [],
|
|
status: null,
|
|
archived: false,
|
|
owner: null,
|
|
cadence: null,
|
|
modifiedAt: 1,
|
|
createdAt: null,
|
|
fileSize: 1,
|
|
snippet: '',
|
|
wordCount: 1,
|
|
relationships: {},
|
|
icon: null,
|
|
color: null,
|
|
order: null,
|
|
sidebarLabel: null,
|
|
template: null,
|
|
sort: null,
|
|
view: null,
|
|
visible: true,
|
|
organized: false,
|
|
favorite: false,
|
|
favoriteIndex: null,
|
|
listPropertiesDisplay: [],
|
|
outgoingLinks: [],
|
|
properties: {},
|
|
hasH1: true,
|
|
fileKind: 'markdown',
|
|
}
|
|
}
|
|
|
|
function ref<T>(current: T): MutableRefObject<T> {
|
|
return { current }
|
|
}
|
|
|
|
const inboxSelection: SidebarSelection = { kind: 'filter', filter: 'inbox' }
|
|
const alphaSelection: SidebarSelection = { kind: 'entity', entry: buildEntry('/vault/alpha.md', 'Alpha') }
|
|
const betaSelection: SidebarSelection = { kind: 'entity', entry: buildEntry('/vault/beta.md', 'Beta') }
|
|
|
|
function renderNeighborhoodEntry(
|
|
currentSelection: SidebarSelection,
|
|
history: SidebarSelection[],
|
|
) {
|
|
const selectionRef = ref(currentSelection)
|
|
const historyRef = ref<SidebarSelection[]>(history)
|
|
const setSelection = vi.fn((selection: SidebarSelection) => {
|
|
selectionRef.current = selection
|
|
})
|
|
const hook = renderHook(() => useNeighborhoodEntry({
|
|
neighborhoodHistoryRef: historyRef,
|
|
selectionRef,
|
|
setSelection,
|
|
}))
|
|
|
|
return { historyRef, hook, setSelection }
|
|
}
|
|
|
|
describe('useNeighborhoodEntry', () => {
|
|
beforeEach(() => {
|
|
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => {
|
|
callback(0)
|
|
return 0
|
|
})
|
|
document.body.innerHTML = '<div data-testid="note-list-container" tabindex="-1"></div>'
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
document.body.innerHTML = ''
|
|
})
|
|
|
|
it('toggles the repeated active neighborhood action back to the previous list', () => {
|
|
const { historyRef, hook, setSelection } = renderNeighborhoodEntry(alphaSelection, [inboxSelection])
|
|
|
|
act(() => hook.result.current(alphaSelection.entry))
|
|
|
|
expect(setSelection).toHaveBeenCalledWith(inboxSelection, { preserveNeighborhoodHistory: true })
|
|
expect(historyRef.current).toEqual([])
|
|
expect(document.activeElement).toBe(document.querySelector('[data-testid="note-list-container"]'))
|
|
})
|
|
|
|
it('uses the same stacked history as Escape when toggling the active neighborhood off', () => {
|
|
const { historyRef, hook, setSelection } = renderNeighborhoodEntry(betaSelection, [inboxSelection, alphaSelection])
|
|
|
|
act(() => hook.result.current(betaSelection.entry))
|
|
|
|
expect(setSelection).toHaveBeenCalledWith(alphaSelection, { preserveNeighborhoodHistory: true })
|
|
expect(historyRef.current).toEqual([inboxSelection])
|
|
})
|
|
|
|
it('switches between neighborhoods without collapsing to all notes', () => {
|
|
const { historyRef, hook, setSelection } = renderNeighborhoodEntry(alphaSelection, [inboxSelection])
|
|
|
|
act(() => hook.result.current(betaSelection.entry))
|
|
|
|
expect(setSelection).toHaveBeenCalledWith(betaSelection, { preserveNeighborhoodHistory: true })
|
|
expect(historyRef.current).toEqual([inboxSelection, alphaSelection])
|
|
})
|
|
})
|
|
|
|
describe('useNeighborhoodEscape', () => {
|
|
it('routes Escape to neighborhood history when focus is already outside editable controls', () => {
|
|
const onBack = vi.fn(() => true)
|
|
renderHook(() => useNeighborhoodEscape({
|
|
onBack,
|
|
selectionRef: ref(alphaSelection),
|
|
shouldBlockNeighborhoodEscape: false,
|
|
}))
|
|
|
|
const event = new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true })
|
|
window.dispatchEvent(event)
|
|
|
|
expect(onBack).toHaveBeenCalledOnce()
|
|
expect(event.defaultPrevented).toBe(true)
|
|
})
|
|
})
|