test: add App.tsx integration tests
- Renders four-panel layout with sidebar, note list, editor - Loads and displays vault entries from mock data - Shows empty state when no note is selected - Keyboard shortcut Cmd+S shows toast - Verifies default sidebar selection (All Notes)
This commit is contained in:
160
src/App.test.tsx
Normal file
160
src/App.test.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
// Mock @tauri-apps/api/core before importing App
|
||||
vi.mock('@tauri-apps/api/core', () => ({
|
||||
invoke: vi.fn(),
|
||||
}))
|
||||
|
||||
// Mock mock-tauri module
|
||||
const mockEntries = [
|
||||
{
|
||||
path: '/vault/project/test.md',
|
||||
filename: 'test.md',
|
||||
title: 'Test Project',
|
||||
isA: 'Project',
|
||||
aliases: [],
|
||||
belongsTo: [],
|
||||
relatedTo: [],
|
||||
status: 'Active',
|
||||
owner: 'Luca',
|
||||
cadence: null,
|
||||
modifiedAt: 1700000000,
|
||||
createdAt: null,
|
||||
fileSize: 1024,
|
||||
},
|
||||
{
|
||||
path: '/vault/topic/dev.md',
|
||||
filename: 'dev.md',
|
||||
title: 'Software Development',
|
||||
isA: 'Topic',
|
||||
aliases: ['Dev'],
|
||||
belongsTo: [],
|
||||
relatedTo: [],
|
||||
status: null,
|
||||
owner: null,
|
||||
cadence: null,
|
||||
modifiedAt: 1700000000,
|
||||
createdAt: null,
|
||||
fileSize: 256,
|
||||
},
|
||||
]
|
||||
|
||||
const mockAllContent: Record<string, string> = {
|
||||
'/vault/project/test.md': '---\ntitle: Test Project\nis_a: Project\n---\n\n# Test Project\n\nSome content.',
|
||||
'/vault/topic/dev.md': '---\ntitle: Software Development\nis_a: Topic\n---\n\n# Software Development\n',
|
||||
}
|
||||
|
||||
vi.mock('./mock-tauri', () => ({
|
||||
isTauri: () => false,
|
||||
mockInvoke: vi.fn(async (cmd: string) => {
|
||||
if (cmd === 'list_vault') return mockEntries
|
||||
if (cmd === 'get_all_content') return mockAllContent
|
||||
if (cmd === 'get_modified_files') return []
|
||||
if (cmd === 'get_note_content') return mockAllContent['/vault/project/test.md'] || ''
|
||||
if (cmd === 'get_file_history') return []
|
||||
return null
|
||||
}),
|
||||
addMockEntry: vi.fn(),
|
||||
updateMockContent: vi.fn(),
|
||||
}))
|
||||
|
||||
// Mock BlockNote components (they need DOM APIs not available in jsdom)
|
||||
vi.mock('@blocknote/core', () => ({
|
||||
BlockNoteSchema: { create: () => ({}) },
|
||||
defaultInlineContentSpecs: {},
|
||||
filterSuggestionItems: vi.fn(() => []),
|
||||
}))
|
||||
|
||||
vi.mock('@blocknote/core/extensions', () => ({
|
||||
filterSuggestionItems: vi.fn(() => []),
|
||||
}))
|
||||
|
||||
vi.mock('@blocknote/react', () => ({
|
||||
createReactInlineContentSpec: () => ({ render: () => null }),
|
||||
useCreateBlockNote: () => ({
|
||||
tryParseMarkdownToBlocks: async () => [],
|
||||
replaceBlocks: () => {},
|
||||
document: [],
|
||||
insertInlineContent: () => {},
|
||||
}),
|
||||
SuggestionMenuController: () => null,
|
||||
}))
|
||||
|
||||
vi.mock('@blocknote/mantine', () => ({
|
||||
BlockNoteView: ({ children }: any) => <div data-testid="blocknote-view">{children}</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@blocknote/mantine/style.css', () => ({}))
|
||||
|
||||
import App from './App'
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('renders the four-panel layout', async () => {
|
||||
render(<App />)
|
||||
// Wait for vault to load
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('loads and displays vault entries in sidebar', async () => {
|
||||
render(<App />)
|
||||
await waitFor(() => {
|
||||
// Entries appear in both Sidebar and NoteList
|
||||
expect(screen.getAllByText('Test Project').length).toBeGreaterThan(0)
|
||||
expect(screen.getAllByText('Software Development').length).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
|
||||
it('shows empty state in editor when no note is selected', async () => {
|
||||
render(<App />)
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Select a note to start editing')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('shows keyboard shortcut hints', async () => {
|
||||
render(<App />)
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Cmd\+P to search/)).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('registers keyboard shortcuts without error', async () => {
|
||||
render(<App />)
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
// Cmd+S shows toast
|
||||
fireEvent.keyDown(window, { key: 's', metaKey: true })
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Saved')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('renders sidebar with correct default selection (All Notes)', async () => {
|
||||
render(<App />)
|
||||
await waitFor(() => {
|
||||
// "All Notes" should be rendered as the selected nav item
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
expect(screen.getByText('Favorites')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('renders status bar', async () => {
|
||||
render(<App />)
|
||||
// StatusBar should be present
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
||||
})
|
||||
// The status bar element should exist in the DOM
|
||||
const appShell = document.querySelector('.app-shell')
|
||||
expect(appShell).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user