Testing & Debugging¶
This guide covers running tests, debugging, and the pre-commit hook system.
Running Tests¶
Web Unit Tests (Vitest)¶
pnpm --filter @meisterbill/web test:unit # Run web tests
pnpm --filter @meisterbill/web test:unit --run # Run without watch mode
Test Count: 143 passing tests (1 skipped)
Framework: Vitest
Location: apps/web/test/unit/
API Tests (Jest)¶
pnpm --filter @meisterbill/api test # Run API tests
Test Count: 397 passing tests
Framework: Jest
Location: apps/api/src/**/*.test.ts
App Unit Tests (Vitest)¶
pnpm --filter @meisterbill/app test:unit # Run app unit tests
Framework: Vitest
Location: apps/app/
Schema Tests (Vitest)¶
pnpm --filter @meisterbill/schemas test # Run schema tests
Test Count: 414 passing tests
Framework: Vitest
Location: schemas/src/**/*.test.ts
E2E Tests¶
pnpm --filter @meisterbill/app test:e2e # App E2E tests (Cypress)
pnpm e2e # Full E2E tests (Playwright)
App E2E: Cypress Full E2E: Playwright
Pre-commit Hook¶
A git pre-commit hook automatically runs all unit tests before allowing commits.
Location: .git/hooks/pre-commit
Tests Run:
- Web unit tests (@meisterbill/web)
- API tests (@meisterbill/api)
- App unit tests (@meisterbill/app)
- Schema tests (@meisterbill/schemas)
Behavior: - Commit is aborted if any tests fail - Ensures only tested code is committed to the repository
The hook is installed automatically and will run on every git commit.
Test File Organization¶
Web Tests¶
apps/web/
├── test/unit/
│ ├── CookieBanner.spec.ts
│ ├── CustomerHelper.spec.ts
│ ├── Formater.spec.ts
│ ├── image-processing.spec.ts
│ ├── useAuth.spec.ts
│ ├── useInvoiceStatusMachine.spec.ts
│ └── plugins/
│ └── AuthInit.spec.ts
└── pages/
└── **/__tests__/
└── *.test.ts
API Tests¶
apps/api/src/
├── routes/
│ ├── addresses.test.ts
│ ├── auth.test.ts
│ ├── brands.test.ts
│ ├── credit-notes.test.ts
│ ├── founder-deal.test.ts
│ ├── payments.test.ts
│ ├── projects.test.ts
│ └── ...
├── services/
│ ├── EmailService.test.ts
│ └── CommitSummarizationService.test.ts
└── utils/
└── documentNumber.test.ts
Schema Tests¶
schemas/src/
├── AccountSchema.test.ts
├── AddressFormatters.test.ts
├── AddressSchema.test.ts
├── BreadcrumbSchema.test.ts
├── CurrencyCodeSchema.test.ts
├── CustomerSchema.test.ts
├── DocumentItemSchema.test.ts
├── DocumentSchema.test.ts
├── EventSchema.test.ts
├── ServiceProviderSchema.test.ts
├── TaxCalculationSchema.test.ts
├── TaxNumberSchema.test.ts
└── forms/
├── NewPasswordSchema.test.ts
└── SignUpSchema.test.ts
Debugging¶
Console Logging¶
Use console.debug for JavaScript debugging (not console.log):
console.debug('User logged in:', userId);
console.debug('Invoice state:', invoice);
This follows the project convention defined in CLAUDE.md.
API Hot Reloading¶
The API server has hot reloading enabled. No need to restart after changes.
Web Hot Reloading¶
The web server also has hot reloading. Changes are reflected immediately.
Testing Specific Files¶
# Web - test specific file
pnpm --filter @meisterbill/web test:unit CustomerHelper.spec.ts
# API - test specific file pattern
pnpm --filter @meisterbill/api test addresses
# Schemas - test specific file
pnpm --filter @meisterbill/schemas test AddressFormatters
Common Test Scenarios¶
Testing Event Bus¶
Example from apps/web/test/unit/plugins/AuthInit.spec.ts:
import { eventBus } from '~/composables/useEventBus';
it('emits auth.login.success event', () => {
const handler = vi.fn();
eventBus.on('auth.login.success', handler);
// Trigger login
await login({ email, password });
expect(handler).toHaveBeenCalledWith(expect.objectContaining({
userId: 'test-user-id',
}));
});
Testing State Machines¶
Example from apps/web/test/unit/useInvoiceStatusMachine.spec.ts:
import { useInvoiceStatusMachine } from '~/composables/useInvoiceStatusMachine';
it('transitions from draft to finalized', () => {
const { canTransitionTo, getValidNextStatuses } = useInvoiceStatusMachine();
expect(canTransitionTo('draft', 'finalized')).toBe(true);
expect(getValidNextStatuses('draft')).toContain('finalized');
});
Testing API Routes¶
Example from apps/api/src/routes/auth.test.ts:
import { app } from '../index';
describe('POST /auth/signup', () => {
it('creates a new user', async () => {
const res = await app.request('/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'test@example.com',
password: 'SecurePass123!',
terms_accepted: true,
}),
});
expect(res.status).toBe(201);
});
});
Test Coverage Goals¶
- Critical paths: 100% coverage
- Business logic: 90%+ coverage
- UI components: 70%+ coverage
- Overall: 80%+ coverage target
Continuous Integration¶
All tests run automatically in CI/CD before deployment. Tests are defined in the .gitea/workflows/deploy.yml file.
See Also¶
- Development Setup - Initial setup for testing
- Event Bus Architecture - Testing event subscribers