Testing
This project uses Vitest for testing with a comprehensive suite covering CLI commands and core TUI state behavior.
Running Tests
# Run all tests
npm test
# Run tests with coverage report
npm test -- --coverage
# Run tests in watch mode (during development)
npm run test:watch
# Run specific test file
npm test -- src/__tests__/commands/auth.test.ts
Test Structure
src/__tests__/
├── setup.ts # Global test setup (console mocking)
├── mocks/ # Shared mock implementations
│ ├── leetcodeClient.ts # Mock LeetCode API client
│ └── storage.ts # Mock storage modules
├── commands/ # Unit tests for each command
│ ├── auth.test.ts # login, logout, whoami
│ ├── browse.test.ts # list, show, daily, random
│ ├── changelog.test.ts # changelog
│ ├── collab.test.ts # collab host/join/sync/compare/leave/status
│ ├── config.test.ts # config
│ ├── diff.test.ts # diff command
│ ├── hint.test.ts # hint command
│ ├── notes.test.ts # notes, bookmark
│ ├── progress.test.ts # stat, submissions, today
│ ├── snapshot.test.ts # snapshot save/list/restore/diff/delete
│ ├── solve.test.ts # pick, test, submit (+ security tests)
│ ├── sync.test.ts # sync
│ ├── timer.test.ts # timer
│ ├── update.test.ts # update
│ └── workspace.test.ts # workspace create/use/list/delete
├── storage/
│ └── workspace-integration.test.ts # Multi-workspace isolation
├── tui/
│ └── problem-screen.test.ts # TUI problem drawer/navigation behavior
├── utils/
│ └── visualize.test.ts # Visual debugging output
└── integration/
└── cli.test.ts # Integration tests (runs actual CLI binary)
Test Categories
Unit Tests (~182 tests)
Test individual command logic with mocked dependencies:
- API client is mocked to avoid network calls
- Storage modules are mocked to avoid file system access
- All command options and input variations are tested
- Security tests: Path traversal prevention in test/submit/diff
Integration Tests (~49 tests)
Run the actual compiled CLI binary to catch:
- Missing shebang in
dist/index.js - Broken imports or build errors
- Commands not registered with Commander.js
- Missing command aliases
- Help text and error handling
Coverage
Current coverage by area:
| Area | Statements | Lines |
|---|---|---|
| Commands | 70.33% | 71.47% |
| Overall | 54.64% | 55.93% |
Lower overall coverage is expected because we mock:
src/api/client.ts- LeetCode API callssrc/storage/*- Configuration persistencesrc/utils/display.ts- Console output formatting
These are intentionally mocked in unit tests to isolate command logic.
Writing New Tests
When adding a new command:
- Create a test file in
src/__tests__/commands/ - Mock dependencies using
vi.mock() - Import the command function after mocking
- Test all options and input variations
- Add an integration test in
cli.test.tsfor command registration
Example test structure:
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock dependencies first
vi.mock('../../api/client.js', () => ({
leetcodeClient: {
// Mock methods
},
}));
// Import after mocking
import { myCommand } from '../../commands/myCommand.js';
describe('myCommand', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should handle basic usage', async () => {
await myCommand({});
// assertions
});
});
CI Integration
Tests run automatically on every push via GitHub Actions. The CI workflow:
- Builds the project (
npm run build) - Runs all tests (
npm test) - Fails the build if any test fails