npm test # Run all tests
npm test -- --watch # Watch mode
npm test -- path/to/file.test.ts # Specific fileTests in src/**/*.test.ts alongside implementation.
// src/lib/balances.test.ts
const makeExpense = (overrides: Partial<BalancesExpense>): BalancesExpense =>
({
id: 'e1',
expenseDate: new Date('2025-01-01T00:00:00.000Z'),
title: 'Dinner',
amount: 0,
isReimbursement: false,
splitMode: 'EVENLY',
paidBy: { id: 'p0', name: 'P0' },
paidFor: [{ participant: { id: 'p0', name: 'P0' }, shares: 1 }],
...overrides,
}) as BalancesExpense
// Usage
const expenses = [
makeExpense({
amount: 100,
paidBy: { id: 'p0', name: 'P0' },
paidFor: [
{ participant: { id: 'p0', name: 'P0' }, shares: 1 },
{ participant: { id: 'p1', name: 'P1' }, shares: 1 },
],
}),
]balances.test.ts- Balance calculations, split modes, edge casestotals.test.ts- Expense totals, user sharescurrency.test.ts- Currency formatting
npm run test-e2e # Runs against local dev serverTests in tests/e2e/*.spec.ts and tests/*.spec.ts.
| Helper | Purpose |
|---|---|
createGroupViaAPI(page, name, participants) |
Fast group setup via API |
createExpense(page, { title, amount, payer }) |
Fill expense form |
navigateToExpenseCreate(page, groupId) |
Go to expense creation |
fillParticipants(page, names) |
Add participants to form |
selectComboboxOption(page, label, value) |
Select dropdown value |
// Wait after navigation
await page.goto(`/groups/${groupId}`)
await page.waitForLoadState()
// Wait for URL after form submission
await page.getByRole('button', { name: 'Create' }).click()
await page.waitForURL(/\/groups\/[^/]+\/expenses/)
// Use API for fast setup
const groupId = await createGroupViaAPI(page, 'Test Group', ['Alice', 'Bob'])import { createExpense } from '../helpers'
import { createGroupViaAPI } from '../helpers/batch-api'
test('creates expense with correct values', async ({ page }) => {
const groupId = await createGroupViaAPI(page, `Test ${randomId(4)}`, [
'Alice',
'Bob',
])
await page.goto(`/groups/${groupId}/expenses`)
await createExpense(page, {
title: 'Dinner',
amount: '150.00',
payer: 'Alice',
})
await expect(page.getByText('Dinner')).toBeVisible()
await expect(page.getByText('$150.00')).toBeVisible()
})fullyParallel: falsein playwright.config.ts prevents DB conflicts- Runs Chromium, Firefox, WebKit
jsonreporter whenCLAUDE_CODEenv var detected