Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { computed, reactive, ref } from 'vue'

globalThis.computed = computed
globalThis.reactive = reactive
globalThis.ref = ref

interface FolderNode {
id: number
children: FolderNode[]
}

interface SetupOptions {
displayedSnippetIds?: number[]
folderId?: number
folders?: FolderNode[]
snippetId?: number
tagId?: number
tags?: Array<{ id: number, name: string }>
}

async function setup(options: SetupOptions = {}) {
vi.resetModules()

const state = reactive<{
folderId?: number
libraryFilter?: string
snippetId?: number
tagId?: number
}>({
folderId: options.folderId,
snippetId: options.snippetId,
tagId: options.tagId,
})

const folders = ref<FolderNode[] | undefined>(
options.folders ?? [
{ id: 7, children: [] },
{ id: 9, children: [] },
],
)
const tags = ref(options.tags ?? [{ id: 1, name: 'work' }])
const displayedSnippets = ref(
(options.displayedSnippetIds ?? []).map(id => ({ id })),
)

const getSnippets = vi.fn(async () => undefined)
const selectFirstSnippet = vi.fn(() => {
state.snippetId = displayedSnippets.value[0]?.id
})

vi.doMock('../useApp', () => ({
useApp: () => ({
state,
}),
}))

vi.doMock('../useFolders', () => ({
useFolders: () => ({
folders,
}),
}))

vi.doMock('../useTags', () => ({
useTags: () => ({
tags,
}),
}))

vi.doMock('../useSnippets', () => ({
useSnippets: () => ({
displayedSnippets,
getSnippets,
selectFirstSnippet,
}),
}))

const { normalizeCodeSelectionState } = await import(
'../useCodeSelectionNormalization'
)

return {
displayedSnippets,
folders,
getSnippets,
normalizeCodeSelectionState,
selectFirstSnippet,
state,
tags,
}
}

beforeEach(() => {
vi.clearAllMocks()
})

describe('normalizeCodeSelectionState', () => {
it('clears stale tagId before requesting snippets', async () => {
const context = await setup({
folderId: 7,
tagId: 999,
})

await context.normalizeCodeSelectionState()

expect(context.state.tagId).toBeUndefined()
expect(context.getSnippets).toHaveBeenCalledTimes(1)
})

it('falls back to the first folder when saved folderId is missing', async () => {
const context = await setup({
folderId: 999,
folders: [
{ id: 7, children: [] },
{ id: 9, children: [] },
],
})

await context.normalizeCodeSelectionState()

expect(context.state.folderId).toBe(7)
expect(context.getSnippets).toHaveBeenCalledTimes(1)
})

it('selects the first snippet when saved snippetId is absent from the list', async () => {
const context = await setup({
displayedSnippetIds: [1, 2],
folderId: 7,
snippetId: 42,
})

await context.normalizeCodeSelectionState()

expect(context.selectFirstSnippet).toHaveBeenCalledTimes(1)
expect(context.state.snippetId).toBe(1)
})
})
79 changes: 79 additions & 0 deletions src/renderer/composables/__tests__/useCodeSpaceInit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ref } from 'vue'

globalThis.ref = ref

async function setup() {
vi.resetModules()

const callOrder: string[] = []
const isCodeSpaceInitialized = ref(false)
const getFolders = vi.fn(async () => {
callOrder.push('getFolders')
})
const getSnippets = vi.fn(async () => {
callOrder.push('getSnippets')
})
const getTags = vi.fn(async () => {
callOrder.push('getTags')
})
const normalizeCodeSelectionState = vi.fn(async () => {
callOrder.push('normalizeCodeSelectionState')
})

vi.doMock('../useApp', () => ({
useApp: () => ({
isCodeSpaceInitialized,
}),
}))

vi.doMock('../useFolders', () => ({
useFolders: () => ({
getFolders,
}),
}))

vi.doMock('../useTags', () => ({
useTags: () => ({
getTags,
}),
}))

vi.doMock('../useSnippets', () => ({
useSnippets: () => ({
getSnippets,
}),
}))

vi.doMock('../useCodeSelectionNormalization', () => ({
normalizeCodeSelectionState,
}))

const { initCodeSpace } = await import('../useCodeSpaceInit')

return {
callOrder,
initCodeSpace,
isCodeSpaceInitialized,
normalizeCodeSelectionState,
}
}

beforeEach(() => {
vi.clearAllMocks()
})

describe('initCodeSpace', () => {
it('loads folders and tags before normalizing selection state', async () => {
const context = await setup()

await context.initCodeSpace()

expect(context.callOrder).toEqual([
'getFolders',
'getTags',
'normalizeCodeSelectionState',
])
expect(context.isCodeSpaceInitialized.value).toBe(true)
})
})
1 change: 1 addition & 0 deletions src/renderer/composables/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './math-notebook'
export * from './spaces/notes'
export * from './useApp'
export * from './useCodeSelectionNormalization'
export * from './useCodeSpaceInit'
export * from './useCopyToClipboard'
export * from './useDialog'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { computed, reactive, ref } from 'vue'

globalThis.computed = computed
globalThis.reactive = reactive
globalThis.ref = ref

interface FolderNode {
id: number
children: FolderNode[]
}

interface SetupOptions {
displayedNoteIds?: number[]
folderId?: number
folders?: FolderNode[]
noteId?: number
tagId?: number
tags?: Array<{ id: number, name: string }>
}

async function setup(options: SetupOptions = {}) {
vi.resetModules()

const notesState = reactive<{
folderId?: number
libraryFilter?: string
noteId?: number
tagId?: number
}>({
folderId: options.folderId,
noteId: options.noteId,
tagId: options.tagId,
})

const folders = ref<FolderNode[] | undefined>(
options.folders ?? [
{ id: 11, children: [] },
{ id: 12, children: [] },
],
)
const tags = ref(options.tags ?? [{ id: 1, name: 'docs' }])
const displayedNotes = ref(
(options.displayedNoteIds ?? []).map(id => ({ id })),
)

const getNotes = vi.fn(async () => undefined)
const selectFirstNote = vi.fn(() => {
notesState.noteId = displayedNotes.value[0]?.id
})

vi.doMock('../useNotesApp', () => ({
useNotesApp: () => ({
notesState,
}),
}))

vi.doMock('../useNoteFolders', () => ({
useNoteFolders: () => ({
folders,
}),
}))

vi.doMock('../useNoteTags', () => ({
useNoteTags: () => ({
tags,
}),
}))

vi.doMock('../useNotes', () => ({
useNotes: () => ({
getNotes,
selectFirstNote,
}),
}))

vi.doMock('../useNoteSearch', () => ({
useNoteSearch: () => ({
displayedNotes,
}),
}))

const { normalizeNotesSelectionState } = await import(
'../useNotesSelectionNormalization'
)

return {
getNotes,
normalizeNotesSelectionState,
notesState,
selectFirstNote,
}
}

beforeEach(() => {
vi.clearAllMocks()
})

describe('normalizeNotesSelectionState', () => {
it('clears stale tagId before requesting notes', async () => {
const context = await setup({
folderId: 11,
tagId: 999,
})

await context.normalizeNotesSelectionState()

expect(context.notesState.tagId).toBeUndefined()
expect(context.getNotes).toHaveBeenCalledTimes(1)
})

it('falls back to the first folder when saved notes folderId is missing', async () => {
const context = await setup({
folderId: 999,
folders: [
{ id: 11, children: [] },
{ id: 12, children: [] },
],
})

await context.normalizeNotesSelectionState()

expect(context.notesState.folderId).toBe(11)
expect(context.getNotes).toHaveBeenCalledTimes(1)
})

it('selects the first note when saved noteId is absent from the list', async () => {
const context = await setup({
displayedNoteIds: [3, 4],
folderId: 11,
noteId: 99,
})

await context.normalizeNotesSelectionState()

expect(context.selectFirstNote).toHaveBeenCalledTimes(1)
expect(context.notesState.noteId).toBe(3)
})
})
Loading