Testing
Lokus uses Vitest for unit tests and Playwright for end-to-end tests, with @testing-library/react for component testing.
Test Structure
Section titled “Test Structure”src/├── core/│ ├── config/store.test.js # Settings persistence│ ├── theme/manager.test.js # Theme switching│ ├── shortcuts/registry.test.js # Keyboard shortcut registration│ ├── editor/live-settings.test.js # Real-time editor settings│ └── clipboard/shortcuts.test.js # Clipboard operations├── components/│ └── CommandPalette.test.jsx # Command palette UI└── utils/ └── markdown.test.js # Markdown parsing
tests/├── e2e/│ ├── app-navigation.spec.js # Route and sidebar navigation│ ├── math-rendering.spec.js # KaTeX inline/block math│ ├── editor-functionality.spec.js # Typing, formatting, wiki links│ ├── preferences.spec.js # Settings dialog│ ├── markdown-paste.spec.js # Rich text paste handling│ └── file-operations.spec.js # Create, open, save, delete files├── unit/│ ├── editor-utils.test.js # Editor utility functions│ └── math.test.js # Math rendering logic└── setup.js # Global test setup and mocksRunning Tests
Section titled “Running Tests”Unit Tests
Section titled “Unit Tests”npm test # Run all unit tests oncenpm run test:watch # Watch mode (re-runs on file changes)npm run test:watch:silent # Watch mode with minimal outputnpm run test:summary # Verbose output with test namesnpm run test:failures # Show only failuresRun a specific test file:
npx vitest run src/core/config/store.test.jsE2E Tests
Section titled “E2E Tests”npm run test:e2e # Headless (no visible browser)npm run test:e2e:headed # Visible browser windownpm run test:e2e:ui # Playwright UI mode (interactive)Development Workflow
Section titled “Development Workflow”Run the dev server and tests side by side:
npm run dev:testThis uses concurrently to start Vite and Vitest watch mode in parallel.
Test Environment
Section titled “Test Environment”Unit tests run in jsdom with comprehensive mocks for Tauri APIs and browser APIs.
Tauri API Mocks
Section titled “Tauri API Mocks”The test setup (tests/setup.js) stubs Tauri’s IPC layer:
global.window.__TAURI_INTERNALS__ = { invoke: vi.fn()}
global.window.__TAURI_METADATA__ = { currentWindow: { label: 'main' }}Browser API Mocks
Section titled “Browser API Mocks”These browser APIs are mocked for consistent test results:
navigator.clipboard(read/write)ResizeObserverIntersectionObservermatchMediaCSS.supports
Configuration
Section titled “Configuration”Vitest (vitest.config.js)
Section titled “Vitest (vitest.config.js)”{ environment: 'jsdom', setupFiles: ['./tests/setup.js'], globals: true, css: true, testTimeout: 10000, coverage: { reporter: ['text', 'json', 'html'], exclude: ['node_modules/', 'tests/', 'src-tauri/'] }}Playwright (playwright.config.js)
Section titled “Playwright (playwright.config.js)”{ testDir: './tests/e2e', timeout: 30000, use: { browserName: 'chromium', headless: true, screenshot: 'only-on-failure' }}Writing Tests
Section titled “Writing Tests”Unit Test Example
Section titled “Unit Test Example”import { describe, it, expect } from 'vitest'import { render, screen } from '@testing-library/react'import MyComponent from './MyComponent'
describe('MyComponent', () => { it('renders the button', () => { render(<MyComponent />) expect(screen.getByRole('button')).toBeInTheDocument() })})E2E Test Example
Section titled “E2E Test Example”import { test, expect } from '@playwright/test'
test('creates a new note', async ({ page }) => { await page.goto('/') await page.click('[data-testid="new-note"]') await expect(page.locator('.editor')).toBeVisible()})Debugging Tests
Section titled “Debugging Tests”npx vitest run --reporter=verbose # Detailed unit test outputnpx playwright test --headed # See the browser during E2Enpx playwright test --debug # Step through E2E testsCommon fixes for flaky tests:
- Clear mocks between tests with
vi.clearAllMocks() - Use explicit waits (
await expect(...).toBeVisible()) instead of fixed delays - Increase
testTimeoutfor slow CI environments