2026-02-17 11:59:17 +01:00
|
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
|
|
|
|
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64)
* feat: add search backend (qmd CLI) and design file
- Add search.rs: qmd integration for keyword (BM25), semantic (vsearch),
and hybrid search modes via CLI JSON output
- Register search_vault Tauri command in lib.rs
- Design file with 3 frames: empty, results, no-results states
- Fix pre-existing test failures: install @tauri-apps/plugin-opener,
add mock in test setup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add SearchPanel UI with Cmd+Shift+F shortcut
- SearchPanel component: full-text search overlay with keyword/semantic
mode toggle, debounced search (200ms), arrow key navigation, result
count + elapsed time display, note type badges from vault entries
- Cmd+Shift+F shortcut registered in useAppKeyboard
- Mock search_vault handler in mock-tauri for browser dev mode
- SearchResult/SearchResponse types in types.ts
- Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut
- scrollIntoView mock in test setup for jsdom compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct SearchPanel imports for Tauri/browser dual-mode
Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri
with a searchCall wrapper, fixing the TypeScript build error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: make test_detect_collection_fallback robust when qmd not installed
* fix: reset localStorage between App tests to prevent view mode state leak
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
|
|
|
// Provide a localStorage mock that supports all methods (jsdom's may be incomplete)
|
|
|
|
|
const localStorageMock = (() => {
|
|
|
|
|
let store: Record<string, string> = {}
|
|
|
|
|
return {
|
|
|
|
|
getItem: (key: string) => store[key] ?? null,
|
|
|
|
|
setItem: (key: string, value: string) => { store[key] = value },
|
|
|
|
|
removeItem: (key: string) => { delete store[key] },
|
|
|
|
|
clear: () => { store = {} },
|
|
|
|
|
}
|
|
|
|
|
})()
|
|
|
|
|
Object.defineProperty(globalThis, 'localStorage', { value: localStorageMock, writable: true })
|
|
|
|
|
|
2026-02-17 11:59:17 +01:00
|
|
|
// 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,
|
2026-03-03 11:22:04 +01:00
|
|
|
template: null, sort: null,
|
2026-02-25 15:04:49 +01:00
|
|
|
outgoingLinks: [],
|
2026-02-17 11:59:17 +01:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
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,
|
2026-03-03 11:22:04 +01:00
|
|
|
template: null, sort: null,
|
2026-02-25 15:04:49 +01:00
|
|
|
outgoingLinks: [],
|
2026-02-17 11:59:17 +01:00
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
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',
|
|
|
|
|
}
|
|
|
|
|
|
feat: vault-native theming system with live reload (#154)
* feat: add theming system design file with 3 frames
Design frames for Settings > Appearance panel, Command Palette
theme switching, and live theme editing flow visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Rust backend for vault-native theming system
Theme files live in _themes/*.json with colors, typography, and spacing
sections. Vault-level settings (.laputa/settings.json) store the active
theme. Built-in themes (default, dark, minimal) are seeded on vault
creation. All 6 Tauri commands registered: list_themes, get_theme,
get_vault_settings, save_vault_settings, set_active_theme, create_theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add frontend theme engine, settings UI, and command palette integration
Wire up useThemeManager hook to load themes via Tauri IPC, apply CSS
custom properties to :root, and support switching/creating themes.
Add Appearance section to Settings panel with color swatches and theme
cards. Register theme switch and create commands in the command registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use .to_string() instead of format! for string literal (clippy)
* style: cargo fmt on theme.rs
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:05:14 +01:00
|
|
|
const mockCommandResults: Record<string, unknown> = {
|
|
|
|
|
list_vault: mockEntries,
|
2026-03-31 11:14:50 +02:00
|
|
|
list_vault_folders: [],
|
2026-04-02 20:54:06 +02:00
|
|
|
list_views: [],
|
feat: vault-native theming system with live reload (#154)
* feat: add theming system design file with 3 frames
Design frames for Settings > Appearance panel, Command Palette
theme switching, and live theme editing flow visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Rust backend for vault-native theming system
Theme files live in _themes/*.json with colors, typography, and spacing
sections. Vault-level settings (.laputa/settings.json) store the active
theme. Built-in themes (default, dark, minimal) are seeded on vault
creation. All 6 Tauri commands registered: list_themes, get_theme,
get_vault_settings, save_vault_settings, set_active_theme, create_theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add frontend theme engine, settings UI, and command palette integration
Wire up useThemeManager hook to load themes via Tauri IPC, apply CSS
custom properties to :root, and support switching/creating themes.
Add Appearance section to Settings panel with color swatches and theme
cards. Register theme switch and create commands in the command registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use .to_string() instead of format! for string literal (clippy)
* style: cargo fmt on theme.rs
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:05:14 +01:00
|
|
|
get_all_content: mockAllContent,
|
|
|
|
|
get_modified_files: [],
|
|
|
|
|
get_note_content: mockAllContent['/vault/project/test.md'] || '',
|
|
|
|
|
get_file_history: [],
|
2026-04-12 17:08:07 +02:00
|
|
|
get_settings: { auto_pull_interval_minutes: null, telemetry_consent: true, crash_reporting_enabled: null, analytics_enabled: null, anonymous_id: null, release_channel: null },
|
feat: vault-native theming system with live reload (#154)
* feat: add theming system design file with 3 frames
Design frames for Settings > Appearance panel, Command Palette
theme switching, and live theme editing flow visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Rust backend for vault-native theming system
Theme files live in _themes/*.json with colors, typography, and spacing
sections. Vault-level settings (.laputa/settings.json) store the active
theme. Built-in themes (default, dark, minimal) are seeded on vault
creation. All 6 Tauri commands registered: list_themes, get_theme,
get_vault_settings, save_vault_settings, set_active_theme, create_theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add frontend theme engine, settings UI, and command palette integration
Wire up useThemeManager hook to load themes via Tauri IPC, apply CSS
custom properties to :root, and support switching/creating themes.
Add Appearance section to Settings panel with color swatches and theme
cards. Register theme switch and create commands in the command registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use .to_string() instead of format! for string literal (clippy)
* style: cargo fmt on theme.rs
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:05:14 +01:00
|
|
|
git_pull: { status: 'up_to_date', message: 'Already up to date', updatedFiles: [], conflictFiles: [] },
|
|
|
|
|
save_settings: null,
|
|
|
|
|
check_vault_exists: true,
|
2026-03-02 23:46:03 +01:00
|
|
|
get_default_vault_path: '/Users/mock/Documents/Getting Started',
|
feat: vault-native theming system with live reload (#154)
* feat: add theming system design file with 3 frames
Design frames for Settings > Appearance panel, Command Palette
theme switching, and live theme editing flow visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Rust backend for vault-native theming system
Theme files live in _themes/*.json with colors, typography, and spacing
sections. Vault-level settings (.laputa/settings.json) store the active
theme. Built-in themes (default, dark, minimal) are seeded on vault
creation. All 6 Tauri commands registered: list_themes, get_theme,
get_vault_settings, save_vault_settings, set_active_theme, create_theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add frontend theme engine, settings UI, and command palette integration
Wire up useThemeManager hook to load themes via Tauri IPC, apply CSS
custom properties to :root, and support switching/creating themes.
Add Appearance section to Settings panel with color swatches and theme
cards. Register theme switch and create commands in the command registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use .to_string() instead of format! for string literal (clippy)
* style: cargo fmt on theme.rs
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:05:14 +01:00
|
|
|
list_themes: [],
|
|
|
|
|
get_vault_settings: { theme: null },
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-17 11:59:17 +01:00
|
|
|
vi.mock('./mock-tauri', () => ({
|
|
|
|
|
isTauri: () => false,
|
feat: vault-native theming system with live reload (#154)
* feat: add theming system design file with 3 frames
Design frames for Settings > Appearance panel, Command Palette
theme switching, and live theme editing flow visualization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Rust backend for vault-native theming system
Theme files live in _themes/*.json with colors, typography, and spacing
sections. Vault-level settings (.laputa/settings.json) store the active
theme. Built-in themes (default, dark, minimal) are seeded on vault
creation. All 6 Tauri commands registered: list_themes, get_theme,
get_vault_settings, save_vault_settings, set_active_theme, create_theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add frontend theme engine, settings UI, and command palette integration
Wire up useThemeManager hook to load themes via Tauri IPC, apply CSS
custom properties to :root, and support switching/creating themes.
Add Appearance section to Settings panel with color swatches and theme
cards. Register theme switch and create commands in the command registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use .to_string() instead of format! for string literal (clippy)
* style: cargo fmt on theme.rs
---------
Co-authored-by: Test <test@test.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:05:14 +01:00
|
|
|
mockInvoke: vi.fn(async (cmd: string) => mockCommandResults[cmd] ?? null),
|
2026-02-17 11:59:17 +01:00
|
|
|
addMockEntry: vi.fn(),
|
|
|
|
|
updateMockContent: vi.fn(),
|
|
|
|
|
}))
|
|
|
|
|
|
2026-03-01 19:49:58 +01:00
|
|
|
// Mock ai-chat utilities
|
2026-02-22 13:42:20 +01:00
|
|
|
vi.mock('./utils/ai-chat', () => ({
|
|
|
|
|
buildSystemPrompt: vi.fn(() => ({ prompt: '', totalTokens: 0, truncated: false })),
|
2026-03-01 19:49:58 +01:00
|
|
|
checkClaudeCli: vi.fn(async () => ({ installed: false })),
|
|
|
|
|
streamClaudeChat: vi.fn(async () => 'mock-session'),
|
2026-02-22 13:42:20 +01:00
|
|
|
}))
|
|
|
|
|
|
2026-02-17 11:59:17 +01:00
|
|
|
// 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: () => {},
|
2026-02-17 17:56:57 +01:00
|
|
|
onMount: (cb: () => void) => { cb(); return () => {} },
|
2026-02-17 11:59:17 +01:00
|
|
|
}),
|
|
|
|
|
SuggestionMenuController: () => null,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@blocknote/mantine', () => ({
|
2026-02-22 13:10:26 +01:00
|
|
|
BlockNoteView: ({ children }: { children?: React.ReactNode }) => <div data-testid="blocknote-view">{children}</div>,
|
2026-02-17 11:59:17 +01:00
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
vi.mock('@blocknote/mantine/style.css', () => ({}))
|
|
|
|
|
|
|
|
|
|
import App from './App'
|
|
|
|
|
|
|
|
|
|
describe('App', () => {
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
vi.clearAllMocks()
|
2026-02-25 18:30:12 +01:00
|
|
|
|
feat: integrate welcome screen with tests and fix App tests
WelcomeScreen component (14 tests):
- welcome mode: title, buttons, hint, loading, error states
- vault-missing mode: path badge, different button labels
useOnboarding hook (10 tests):
- vault exists → ready, vault missing → welcome
- dismissed + missing → vault-missing
- create vault, open folder, dismiss transitions
- error handling, picker cancellation, command failure fallback
App.test.tsx updated to mock new Tauri commands
(check_vault_exists, get_default_vault_path).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:55:35 +01:00
|
|
|
// Reset view mode and onboarding state between tests
|
2026-04-12 01:35:34 +02:00
|
|
|
localStorage.removeItem('tolaria-view-mode')
|
|
|
|
|
localStorage.removeItem('tolaria-view-mode')
|
feat: full-text search with qmd backend and SearchPanel UI (Cmd+Shift+F) (#64)
* feat: add search backend (qmd CLI) and design file
- Add search.rs: qmd integration for keyword (BM25), semantic (vsearch),
and hybrid search modes via CLI JSON output
- Register search_vault Tauri command in lib.rs
- Design file with 3 frames: empty, results, no-results states
- Fix pre-existing test failures: install @tauri-apps/plugin-opener,
add mock in test setup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add SearchPanel UI with Cmd+Shift+F shortcut
- SearchPanel component: full-text search overlay with keyword/semantic
mode toggle, debounced search (200ms), arrow key navigation, result
count + elapsed time display, note type badges from vault entries
- Cmd+Shift+F shortcut registered in useAppKeyboard
- Mock search_vault handler in mock-tauri for browser dev mode
- SearchResult/SearchResponse types in types.ts
- Tests: 15 new tests for SearchPanel + 2 for keyboard shortcut
- scrollIntoView mock in test setup for jsdom compatibility
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct SearchPanel imports for Tauri/browser dual-mode
Use invoke from @tauri-apps/api/core and mockInvoke from mock-tauri
with a searchCall wrapper, fixing the TypeScript build error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: make test_detect_collection_fallback robust when qmd not installed
* fix: reset localStorage between App tests to prevent view mode state leak
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:09:50 +01:00
|
|
|
localStorage.removeItem('laputa-view-mode')
|
2026-04-12 01:35:34 +02:00
|
|
|
localStorage.removeItem('tolaria_welcome_dismissed')
|
feat: integrate welcome screen with tests and fix App tests
WelcomeScreen component (14 tests):
- welcome mode: title, buttons, hint, loading, error states
- vault-missing mode: path badge, different button labels
useOnboarding hook (10 tests):
- vault exists → ready, vault missing → welcome
- dismissed + missing → vault-missing
- create vault, open folder, dismiss transitions
- error handling, picker cancellation, command failure fallback
App.test.tsx updated to mock new Tauri commands
(check_vault_exists, get_default_vault_path).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:55:35 +01:00
|
|
|
localStorage.removeItem('laputa_welcome_dismissed')
|
2026-02-17 11:59:17 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
})
|
|
|
|
|
|
2026-02-23 19:53:36 +01:00
|
|
|
// Cmd+S with no pending changes shows "Nothing to save"
|
2026-02-17 11:59:17 +01:00
|
|
|
fireEvent.keyDown(window, { key: 's', metaKey: true })
|
|
|
|
|
await waitFor(() => {
|
2026-02-23 19:53:36 +01:00
|
|
|
expect(screen.getByText('Nothing to save')).toBeInTheDocument()
|
2026-02-17 11:59:17 +01:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
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()
|
2026-03-06 23:16:23 +01:00
|
|
|
expect(screen.getByText('Archive')).toBeInTheDocument()
|
2026-02-17 11:59:17 +01:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2026-04-10 13:52:39 +02:00
|
|
|
it('defaults to All Notes when explicit organization is disabled in vault config', async () => {
|
|
|
|
|
const disabledWorkflowConfig = JSON.stringify({
|
|
|
|
|
zoom: null,
|
|
|
|
|
view_mode: null,
|
|
|
|
|
editor_mode: null,
|
|
|
|
|
tag_colors: null,
|
|
|
|
|
status_colors: null,
|
|
|
|
|
property_display_modes: null,
|
|
|
|
|
inbox: { noteListProperties: null, explicitOrganization: false },
|
|
|
|
|
})
|
|
|
|
|
localStorage.setItem('laputa:vault-config:/Users/mock/Documents/Getting Started', disabledWorkflowConfig)
|
|
|
|
|
localStorage.setItem('laputa:vault-config:/Volumes/Jupiter/Workspace/laputa-app/demo-vault-v2', disabledWorkflowConfig)
|
|
|
|
|
|
|
|
|
|
render(<App />)
|
|
|
|
|
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.queryByText('Inbox')).not.toBeInTheDocument()
|
|
|
|
|
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
2026-02-17 11:59:17 +01:00
|
|
|
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()
|
|
|
|
|
})
|
2026-02-25 18:30:12 +01:00
|
|
|
|
|
|
|
|
it('Cmd+1 hides sidebar and note list (editor-only mode)', async () => {
|
|
|
|
|
render(<App />)
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// All panels visible by default
|
|
|
|
|
expect(document.querySelector('.app__sidebar')).toBeInTheDocument()
|
|
|
|
|
expect(document.querySelector('.app__note-list')).toBeInTheDocument()
|
|
|
|
|
|
|
|
|
|
// Cmd+1 → editor-only
|
|
|
|
|
fireEvent.keyDown(window, { key: '1', metaKey: true })
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(document.querySelector('.app__sidebar')).not.toBeInTheDocument()
|
|
|
|
|
expect(document.querySelector('.app__note-list')).not.toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('Cmd+2 shows editor + note list (sidebar hidden)', async () => {
|
|
|
|
|
render(<App />)
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
fireEvent.keyDown(window, { key: '2', metaKey: true })
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(document.querySelector('.app__sidebar')).not.toBeInTheDocument()
|
|
|
|
|
expect(document.querySelector('.app__note-list')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
it('Cmd+3 restores all panels after Cmd+1', async () => {
|
|
|
|
|
render(<App />)
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(screen.getByText('All Notes')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Switch to editor-only first
|
|
|
|
|
fireEvent.keyDown(window, { key: '1', metaKey: true })
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(document.querySelector('.app__sidebar')).not.toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Cmd+3 → all panels
|
|
|
|
|
fireEvent.keyDown(window, { key: '3', metaKey: true })
|
|
|
|
|
await waitFor(() => {
|
|
|
|
|
expect(document.querySelector('.app__sidebar')).toBeInTheDocument()
|
|
|
|
|
expect(document.querySelector('.app__note-list')).toBeInTheDocument()
|
|
|
|
|
})
|
|
|
|
|
})
|
2026-02-17 11:59:17 +01:00
|
|
|
})
|