feat: publish HoloLake model-native living system source
This commit is contained in:
parent
6ad10edde1
commit
c395dd3a99
2467 changed files with 615073 additions and 0 deletions
|
|
@ -0,0 +1,185 @@
|
|||
import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { VaultEntry } from '../types'
|
||||
import { TableOfContentsPanel } from './TableOfContentsPanel'
|
||||
import { buildTableOfContents, buildTableOfContentsFromMarkdown } from './tableOfContentsModel'
|
||||
|
||||
const entry = {
|
||||
title: 'The Compounding Software Factory',
|
||||
modifiedAt: 1700000000,
|
||||
createdAt: 1700000000,
|
||||
fileSize: 2048,
|
||||
} as VaultEntry
|
||||
|
||||
const blocks = [
|
||||
{ id: 'h1', type: 'heading', props: { level: 1 }, content: [{ type: 'text', text: 'The default path is degradation' }] },
|
||||
{ id: 'h2', type: 'heading', props: { level: 2 }, content: [{ type: 'text', text: 'What causes teams to degrade' }] },
|
||||
{ id: 'h3', type: 'heading', props: { level: 3 }, content: [{ type: 'text', text: 'Poor coding hygiene' }] },
|
||||
{ id: 'ignored', type: 'paragraph', props: {}, content: [{ type: 'text', text: 'Body' }] },
|
||||
]
|
||||
|
||||
describe('TableOfContentsPanel', () => {
|
||||
it('builds a title-rooted H1/H2/H3 hierarchy', () => {
|
||||
const toc = buildTableOfContents(entry.title, blocks)
|
||||
|
||||
expect(toc.title).toBe('The Compounding Software Factory')
|
||||
expect(toc.children[0].title).toBe('The default path is degradation')
|
||||
expect(toc.children[0].children[0].title).toBe('What causes teams to degrade')
|
||||
expect(toc.children[0].children[0].children[0].title).toBe('Poor coding hygiene')
|
||||
})
|
||||
|
||||
it('does not duplicate the note title when the first markdown H1 matches it', () => {
|
||||
const toc = buildTableOfContentsFromMarkdown(
|
||||
'Introducing Tolaria',
|
||||
'# Introducing Tolaria\n\n## Tolaria + Refactoring\n\n## Principles',
|
||||
)
|
||||
|
||||
expect(toc.title).toBe('Introducing Tolaria')
|
||||
expect(toc.children.map((item) => item.title)).toEqual(['Tolaria + Refactoring', 'Principles'])
|
||||
})
|
||||
|
||||
it('ignores markdown headings inside fenced and inline code areas', () => {
|
||||
const toc = buildTableOfContentsFromMarkdown(
|
||||
'Markdown Outline',
|
||||
[
|
||||
'# Markdown Outline',
|
||||
'',
|
||||
'## Real Setup',
|
||||
'',
|
||||
'```ts',
|
||||
'# Fenced code is not a heading',
|
||||
'## Nested fenced code is not a heading',
|
||||
'```',
|
||||
'',
|
||||
'This paragraph mentions `# Inline code is not a heading`.',
|
||||
'',
|
||||
'## Real Followup',
|
||||
].join('\n'),
|
||||
)
|
||||
|
||||
expect(toc.children.map((item) => item.title)).toEqual(['Real Setup', 'Real Followup'])
|
||||
expect(toc.children.flatMap((item) => item.children)).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps navigation ids after removing a duplicate markdown title H1', async () => {
|
||||
const setTextCursorPosition = vi.fn()
|
||||
render(
|
||||
<TableOfContentsPanel
|
||||
editor={{
|
||||
document: [
|
||||
{ id: 'title-block', type: 'heading', props: { level: 1 }, content: [{ type: 'text', text: 'Introducing Tolaria' }] },
|
||||
{ id: 'section-block', type: 'heading', props: { level: 2 }, content: [{ type: 'text', text: 'Tolaria + Refactoring' }] },
|
||||
],
|
||||
setTextCursorPosition,
|
||||
}}
|
||||
entry={{ ...entry, title: 'Introducing Tolaria' } as VaultEntry}
|
||||
sourceContent={'# Introducing Tolaria\n\n## Tolaria + Refactoring'}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', { name: /Introducing Tolaria/ }))
|
||||
expect(setTextCursorPosition).toHaveBeenCalledWith('title-block', 'start')
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', { name: /Tolaria \+ Refactoring/ }))
|
||||
expect(setTextCursorPosition).toHaveBeenCalledWith('section-block', 'start')
|
||||
})
|
||||
|
||||
it('resolves navigation ids on click after the async TOC build starts without ids', async () => {
|
||||
const setTextCursorPosition = vi.fn()
|
||||
const editor = {
|
||||
document: [] as unknown[],
|
||||
setTextCursorPosition,
|
||||
}
|
||||
render(
|
||||
<TableOfContentsPanel
|
||||
editor={editor}
|
||||
entry={{ ...entry, title: 'New Note' } as VaultEntry}
|
||||
sourceContent={'# New Note\n\n## New Heading'}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
await screen.findByRole('button', { name: /New Heading/ })
|
||||
editor.document = [
|
||||
{ id: 'title-block', type: 'heading', props: { level: 1 }, content: [{ type: 'text', text: 'New Note' }] },
|
||||
{ id: 'new-heading-block', type: 'heading', props: { level: 2 }, content: [{ type: 'text', text: 'New Heading' }] },
|
||||
]
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /New Heading/ }))
|
||||
expect(setTextCursorPosition).toHaveBeenCalledWith('new-heading-block', 'start')
|
||||
})
|
||||
|
||||
it('updates from source content even when the editor document is stale', async () => {
|
||||
const { rerender } = render(
|
||||
<TableOfContentsPanel
|
||||
editor={{ document: blocks, setTextCursorPosition: vi.fn() }}
|
||||
entry={{ ...entry, title: 'Old Note' } as VaultEntry}
|
||||
sourceContent={'# Old Note\n\n## Old Heading'}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
await screen.findByRole('button', { name: /Old Heading/ })
|
||||
rerender(
|
||||
<TableOfContentsPanel
|
||||
editor={{ document: blocks, setTextCursorPosition: vi.fn() }}
|
||||
entry={{ ...entry, title: 'New Note' } as VaultEntry}
|
||||
sourceContent={'# New Note\n\n## New Heading'}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByRole('button', { name: /New Note/ })).toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: /Old Heading/ })).not.toBeInTheDocument()
|
||||
expect(await screen.findByRole('button', { name: /New Heading/ })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not show stale editor headings while new note source content is loading', () => {
|
||||
render(
|
||||
<TableOfContentsPanel
|
||||
editor={{ document: blocks, setTextCursorPosition: vi.fn() }}
|
||||
entry={{ ...entry, title: 'New Note' } as VaultEntry}
|
||||
sourceContent={null}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByRole('button', { name: /New Note/ })).toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: /The default path is degradation/ })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders heading icons, nesting guides, and navigates to clicked headings', async () => {
|
||||
const setTextCursorPosition = vi.fn()
|
||||
render(
|
||||
<TableOfContentsPanel
|
||||
editor={{ document: blocks, setTextCursorPosition }}
|
||||
entry={entry}
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Table of Contents')).toBeInTheDocument()
|
||||
expect(await screen.findByTestId('toc-connector:toc-title')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('toc-connector:h1')).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /What causes teams to degrade/ }))
|
||||
expect(setTextCursorPosition).toHaveBeenCalledWith('h2', 'start')
|
||||
})
|
||||
|
||||
it('shows note info at the bottom of the table of contents', () => {
|
||||
render(
|
||||
<TableOfContentsPanel
|
||||
editor={{ document: blocks, setTextCursorPosition: vi.fn() }}
|
||||
entry={entry}
|
||||
sourceContent="One two three"
|
||||
onClose={vi.fn()}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Info')).toBeInTheDocument()
|
||||
expect(screen.getByText('Words')).toBeInTheDocument()
|
||||
expect(screen.getByText('3')).toBeInTheDocument()
|
||||
expect(screen.getByText('2.0 KB')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue