Testing Guide

January 25, 2026 ยท View on GitHub

This project has a comprehensive test suite using Vitest as the testing framework.

Test Commands

# Run all tests
npm test

# Run unit tests (main/core)
npm run test:unit

# Run renderer tests (React components)
npm run test:renderer

# Watch mode (for development)
npm run test:watch

# Generate coverage report
npm run test:coverage

Test Framework and Tools

  • Vitest 2.1.8: Modern testing framework with Vite integration
  • @testing-library/react 14.0.0: React component testing
  • @testing-library/user-event 14.5.1: User event simulation
  • vitest-mock-extended 2.0.2: Enhanced mocking capabilities
  • @vitest/coverage-v8: Code coverage reporting

Test Structure

Configuration Files

FileDescription
vitest.config.tsMain/core process test configuration
vitest.config.renderer.tsRenderer process (React) test configuration
tests/setup.tsGlobal test setup (Node environment)
tests/setup.renderer.tsRenderer test setup (jsdom)

Test Helpers

FileDescription
tests/helpers/database.tsPrisma mock utilities
tests/helpers/ipc-mock.tsElectron IPC mock
tests/helpers/mock-llm.tsLLM API response mock
tests/helpers/window-api-mock.tsRenderer window.api mock

Test Fixtures

FileDescription
tests/fixtures/providers.jsonProvider test data
tests/fixtures/models.jsonModel test data
tests/fixtures/tasks.jsonTask test data

Test Files Overview (47 test files)

Infrastructure Layer

LLM Clients (7 files)

FileTestsDescription
src/core/infrastructure/adapters/llm/__tests__/OpenAIClient.test.ts22Message format conversion, streaming, tool calls
src/core/infrastructure/adapters/llm/__tests__/AnthropicClient.test.ts18Anthropic message format, system messages, base64 images
src/core/infrastructure/adapters/llm/__tests__/GeminiClient.test.ts18Gemini contents/parts format, inline_data images
src/core/infrastructure/adapters/llm/__tests__/OllamaClient.test.ts19Ollama local API, image arrays, streaming
src/core/infrastructure/adapters/llm/__tests__/OpenAIResponsesClient.test.ts19Responses API input/output format
src/core/infrastructure/adapters/llm/__tests__/LLMClient.test.ts15Base class backward compatibility
src/core/infrastructure/adapters/llm/__tests__/LLMClientFactory.test.ts8Client factory creation

Splitter Adapters (4 files)

FileDescription
src/core/infrastructure/adapters/split/__tests__/PDFSplitter.test.tsPDF splitting functionality
src/core/infrastructure/adapters/split/__tests__/ImageSplitter.test.tsImage splitting functionality
src/core/infrastructure/adapters/split/__tests__/SplitterFactory.test.tsSplitter factory creation
src/core/infrastructure/adapters/split/__tests__/ImagePathUtil.test.tsImage path utilities

Infrastructure Services (2 files)

FileDescription
src/core/infrastructure/services/__tests__/FileService.test.tsFile handling operations
src/core/infrastructure/config/__tests__/worker.config.test.tsWorker configuration

Domain Layer

Repositories (4 files)

FileDescription
src/core/domain/repositories/__tests__/ProviderRepository.test.tsProvider CRUD operations
src/core/domain/repositories/__tests__/ModelRepository.test.tsModel CRUD operations
src/core/domain/repositories/__tests__/TaskRepository.test.tsTask CRUD operations, pagination
src/core/domain/repositories/__tests__/TaskDetailRepository.test.tsTask detail operations

Domain Logic (1 file)

FileDescription
src/core/domain/split/__tests__/PageRangeParser.test.tsPage range string parsing

Application Layer

Services (2 files)

FileDescription
src/core/application/services/__tests__/ModelService.test.tsModel service business logic
src/core/application/services/__tests__/WorkerOrchestrator.test.tsWorker orchestration

Workers (4 files)

FileDescription
src/core/application/workers/__tests__/WorkerBase.test.tsBase worker functionality
src/core/application/workers/__tests__/SplitterWorker.test.tsPDF/image splitting worker
src/core/application/workers/__tests__/ConverterWorker.test.tsPage to markdown conversion worker
src/core/application/workers/__tests__/MergerWorker.test.tsMarkdown merging worker

Shared Layer (2 files)

FileDescription
src/core/shared/events/__tests__/EventBus.test.tsEvent bus pub/sub system
src/core/shared/di/__tests__/Container.test.tsDependency injection container

Main Process

Window Management (1 file)

FileDescription
src/main/__tests__/WindowManager.test.tsElectron window management

IPC Handlers (8 files)

FileDescription
src/main/ipc/__tests__/handlers.test.tsLegacy IPC handlers
src/main/ipc/__tests__/eventBridge.test.tsIPC event bridge
src/main/ipc/handlers/__tests__/provider.handler.test.tsProvider IPC handlers
src/main/ipc/handlers/__tests__/model.handler.test.tsModel IPC handlers
src/main/ipc/handlers/__tests__/task.handler.test.tsTask IPC handlers
src/main/ipc/handlers/__tests__/taskDetail.handler.test.tsTask detail IPC handlers
src/main/ipc/handlers/__tests__/file.handler.test.tsFile IPC handlers
src/main/ipc/handlers/__tests__/completion.handler.test.tsCompletion IPC handlers

Renderer Process (React)

Components (8 files)

FileDescription
src/renderer/components/__tests__/UploadPanel.test.tsxFile upload panel
src/renderer/components/__tests__/Provider.test.tsxProvider management
src/renderer/components/__tests__/AddProvider.test.tsxAdd provider form
src/renderer/components/__tests__/ModelService.test.tsxModel service settings
src/renderer/components/__tests__/MarkdownPreview.test.tsxMarkdown preview
src/renderer/components/__tests__/Layout.test.tsxApp layout
src/renderer/components/__tests__/LanguageSwitcher.test.tsxLanguage switcher
src/renderer/components/__tests__/About.test.tsxAbout dialog

Pages (4 files)

FileDescription
src/renderer/pages/__tests__/Home.test.tsxHome page
src/renderer/pages/__tests__/List.test.tsxTask list page
src/renderer/pages/__tests__/Preview.test.tsxTask preview page
src/renderer/pages/__tests__/Settings.test.tsxSettings page

Test Statistics

Unit Tests (test:unit):
  Test Suites: 295 passed
  Tests: 757 passed

Renderer Tests (test:renderer):
  Test Suites: 15 (12 passed, 3 with failures)
  Tests: 100+ (most passing)

Testing Best Practices

Mock Strategy

  • External dependencies: All mocked (electron, fs, path, fetch)
  • Database: Use vitest-mock-extended to mock Prisma
  • LLM API: Mock fetch responses
  • IPC: Mock ipcMain and dialog

Test Isolation

  • Reset all mocks before each test
  • Use beforeEach to clean state
  • Avoid dependencies between tests

Test Structure

describe('FeatureName', () => {
  describe('Scenario', () => {
    it('should do something specific', () => {
      // Arrange
      // Act
      // Assert
    })
  })
})

Coverage Report

Coverage reports are generated in the coverage/ directory:

  • HTML report: View detailed coverage in browser
  • JSON report: For CI/CD integration
  • Text report: Terminal summary

Troubleshooting

Common Issues

  1. Module import errors

    • Ensure all import paths use .js extension (ESM requirement)
    • Check mock paths are correct
  2. Mock not properly set up

    • Ensure mocks are set before importing modules
    • Use vi.mock() at file top
  3. Async test timeout

    • Ensure using await or return Promise
    • Check mock functions return Promises correctly
  4. Prisma Mock issues

    • Use mockDeep<PrismaClient>()
    • Use mockReset() in beforeEach
  5. React component test issues

    • Ensure components are properly wrapped (Router, App)
    • Use waitFor for async updates

Adding New Tests

  1. Create __tests__ folder in the corresponding directory
  2. Name test files: *.test.ts or *.test.tsx
  3. Follow existing test patterns
  4. Ensure tests are independent and repeatable
  5. Add meaningful test descriptions

Example: Repository Test

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mockDeep, mockReset } from 'vitest-mock-extended'
import { PrismaClient } from '@prisma/client'
import featureRepository from '../FeatureRepository.js'

const prismaMock = mockDeep<PrismaClient>()
vi.mock('../../../infrastructure/db/index.js', () => ({ prisma: prismaMock }))

describe('featureRepository', () => {
  beforeEach(() => { mockReset(prismaMock) })

  it('should create feature', async () => {
    prismaMock.feature.create.mockResolvedValue({ id: 1, name: 'test' })
    const result = await featureRepository.create({ name: 'test' })
    expect(result.id).toBe(1)
  })
})

Example: React Component Test

import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import FeatureComponent from '../FeatureComponent'

describe('FeatureComponent', () => {
  it('should render and interact', async () => {
    window.api.feature.action = vi.fn().mockResolvedValue({ success: true })
    render(<FeatureComponent />)
    const button = screen.getByRole('button')
    await userEvent.click(button)
    expect(window.api.feature.action).toHaveBeenCalled()
  })
})

CI Integration

The project uses GitHub Actions for CI. Tests run on every push/PR to master:

# .github/workflows/ci.yml
- name: Run unit tests
  run: npm run test:unit

- name: Run renderer tests
  run: npm run test:renderer

- name: Generate coverage
  run: npm run test:coverage

Last Updated: 2026-01-25 Total Test Files: 47 Coverage Target: >75% overall