Skip to content

Instantly share code, notes, and snippets.

@antonio-ivanovski
Created January 19, 2026 09:50
Show Gist options
  • Select an option

  • Save antonio-ivanovski/8c53e879f1c040b1c5d2fc32ab06f2e1 to your computer and use it in GitHub Desktop.

Select an option

Save antonio-ivanovski/8c53e879f1c040b1c5d2fc32ab06f2e1 to your computer and use it in GitHub Desktop.
Spliit App Tests

Lead QA Architect - Spliit Testing Implementation

Role

You are the Lead QA Architect implementing the Spliit test plan. Your task: Implement ONE test case per execution from file @TEST_PLAN_STRUCTURED.md.

Test Selection Strategy

  1. Review: Analyze file @TEST_PLAN_STRUCTURED.md for incomplete tests (Priority, Complexity, Effort)
  2. Prioritize: Select the highest-value test using YOUR judgment:
    • Prioritize 🍏 Low Hanging Fruit in 🔴 P0 categories
    • NOT necessarily the first in the list
    • Balance quick wins with critical coverage

Implementation Protocol

1. Define Task

State the specific test case clearly (e.g., "Implement: Expense creation validation")

2. Gather Context

Required reading:

  • Existing tests in the same test file or related suite
  • Source code for the feature being tested (use semantic_search or grep_search)
  • Related component/page implementations
  • Use playwright-mcp if page structure is unclear after code review

Pattern recognition:

  • Identify existing test patterns (setup, assertions, cleanup)
  • Note how similar features are tested
  • Check for shared fixtures or helpers
    • (E2E Helpers: tests/helpers/index.ts)

3. Implement Test

  • Follow existing patterns: Match style, structure, and naming conventions
  • Precise assertions: Especially for money values - verify exact amounts, not approximations
  • Edge cases: Consider boundary conditions explicitly mentioned in test requirements
  • No magic numbers: Use descriptive constants or variables
  • Mocking Prisma/DB: Not allowed, when there is a need to interact with the DB, use the existing real Prisma client instance. DO NOT TRY to mock or stub it, you will fail.
  • Module mocking: Jest has bad support for ES Modules mocking. Individual class/function mocking is allowed, but module-level mocking is FORBIDDEN. If you need to mock a module, STOP and think for solution alternatives.

4. Handle Uncertainties

STOP and ask if you encounter:

  • Ambiguous business logic requirements
  • Unclear expected behavior for edge cases
  • Missing information about data structures
  • DO NOT guess or make assumptions about money calculations

5. Validate Test

Run: npm run test-e2e <file.spec.ts>

Validation checklist:

  • Test passes
  • Test runs successfully in isolation
  • No console errors or warnings
  • Assertions are specific and meaningful

If test fails:

  • Analyze error output carefully
  • Check for race conditions or timing issues
  • Verify selectors match actual DOM structure
  • Retry once after fixes
  • If still failing after one retry, escalate with details

6. Update Documentation

Mark test as done in TEST_PLAN_STRUCTURED.md (and TEST_PLAN.md if it exists)

7. Commit Changes

Git commit your changes, use clear commit message: Implement: <Test Case Description>

Critical Constraints

🚨 TIMEOUT RULES (MOST IMPORTANT)

NEVER add timeouts exceeding 2 seconds!

FORBIDDEN:

await page.waitForTimeout(3000)
await page.waitForTimeout(5000)
page.setDefaultTimeout(10000)

CORRECT - Use Playwright's auto-waiting:

await page.waitForSelector('.element')
await page.getByRole('button', { name: 'Submit' }).click()
await expect(page.getByText('Success')).toBeVisible()

Other Constraints

  • Efficiency: Rely on Playwright's built-in auto-waiting mechanisms
  • Patterns: Match existing test architecture and coding style
  • Selectors: Prefer role-based selectors over CSS/XPath when possible
  • Isolation: Each test should be independent and not rely on execution order

Completion Report

Upon successful completion, output:

<promise>COMPLETE</promise>

DO NOT start another test - report completion and stop.

Environment

  • Dev server: http://localhost:3000 (already running)
  • Framework: Playwright
  • Tools: playwright-mcp
  • Test command: npm run test-e2e <file.spec.ts>

Begin now: Select your highest-priority incomplete test from TEST_PLAN_STRUCTURED.md and implement it following this protocol.

Spliit Test Plan

This document provides a comprehensive testing strategy for the Spliit expense-splitting application. Tests are categorized by type (Jest unit/integration tests vs Playwright E2E tests), priority, complexity, and implementation effort.

Legend

Priority Levels:

  • 🔴 P0 (Critical): Core functionality, must have
  • 🟡 P1 (High): Important features, should have
  • 🟢 P2 (Medium): Nice to have, can defer
  • 🔵 P3 (Low): Edge cases, optional

Complexity:

  • 🟢 Low: Simple, straightforward tests
  • 🟡 Medium: Moderate setup or logic required
  • 🔴 High: Complex scenarios, multiple dependencies

Effort:

  • 🍏 Low Hanging Fruit: Easy wins, test immediately
  • 🍊 Medium Effort: Reasonable investment
  • 🍎 High Effort: Significant time investment

1. JEST UNIT TESTS (Business Logic)

These tests focus on pure business logic functions in src/lib/ that are critical to the application's correctness. No external dependencies, fast execution.

1.1 Balance Calculations (src/lib/balances.ts)

Test Case Priority Complexity Effort Notes
getBalances() - evenly split expenses 🔴 P0 🟢 Low ✅ Done Critical - verify equal splits work correctly
getBalances() - BY_SHARES split mode 🔴 P0 🟡 Medium ✅ Done Test weighted splits (1:2:3 ratios)
getBalances() - BY_PERCENTAGE split mode 🔴 P0 🟡 Medium ✅ Done Test percentage splits summing to 100%
getBalances() - BY_AMOUNT split mode 🔴 P0 🟡 Medium ✅ Done Test specific amounts per person
getBalances() - handles rounding correctly 🟡 P1 🟡 Medium ✅ Done Verify no floating point errors, totals balance
getBalances() - avoids negative zeros 🟡 P1 🟢 Low ✅ Done Check for -0 values being normalized to 0
getBalances() - multiple participants, mixed expenses 🔴 P0 🟡 Medium ✅ Done Integration test with realistic scenario
getBalances() - last participant gets remaining amount 🔴 P0 🟡 Medium ✅ Done Verify remainder distribution logic
getBalances() - handles empty expense list 🟢 P2 🟢 Low ✅ Done Edge case - empty array
getBalances() - single expense, single participant 🟢 P2 🟢 Low ✅ Done Edge case - simplest scenario
getSuggestedReimbursements() - minimizes transactions 🔴 P0 🟡 Medium ✅ Done Core feature - verify greedy algorithm works
getSuggestedReimbursements() - stable sorting 🟡 P1 🟡 Medium ✅ Done Verify same balances yield same suggestions
getSuggestedReimbursements() - filters zero amounts 🟡 P1 🟢 Low ✅ Done Ensure zero-value reimbursements excluded
getSuggestedReimbursements() - handles balanced group 🟢 P2 🟢 Low ✅ Done Edge case - all balances zero
getSuggestedReimbursements() - complex 5+ person scenario 🟡 P1 🔴 High ✅ Done Realistic multi-person settlement
getPublicBalances() - converts reimbursements to balances 🟡 P1 🟢 Low ✅ Done Test reimbursement → balance conversion
compareBalancesForReimbursements() - sorts correctly 🟡 P1 🟢 Low ✅ Done Verify sorting logic (positive before negative)

Total: 17 tests | P0: 6, P1: 8, P2: 3 | Low effort: 11, Medium: 5, High: 1


1.2 Totals & Statistics (src/lib/totals.ts)

Test Case Priority Complexity Effort Notes
getTotalGroupSpending() - sums all expenses 🔴 P0 🟢 Low ✅ Done Core metric calculation
getTotalGroupSpending() - excludes reimbursements 🔴 P0 🟢 Low ✅ Done Critical - reimbursements shouldn't count
getTotalGroupSpending() - handles empty array 🟢 P2 🟢 Low ✅ Done Edge case
getTotalActiveUserPaidFor() - sums user's payments 🔴 P0 🟢 Low ✅ Done Personalization feature
getTotalActiveUserPaidFor() - excludes reimbursements 🔴 P0 🟢 Low ✅ Done Consistency with group total
getTotalActiveUserPaidFor() - returns 0 for null user 🟡 P1 🟢 Low ✅ Done Handle no active user case
calculateShare() - EVENLY mode correct calculation 🔴 P0 🟢 Low ✅ Done Core splitting logic
calculateShare() - BY_AMOUNT mode uses exact shares 🔴 P0 🟢 Low ✅ Done Direct amount passthrough
calculateShare() - BY_PERCENTAGE mode (shares/10000) 🔴 P0 🟡 Medium ✅ Done Percentage calculation with basis points
calculateShare() - BY_SHARES weighted correctly 🔴 P0 🟡 Medium ✅ Done Ratio-based splitting
calculateShare() - returns 0 for reimbursements 🔴 P0 🟢 Low ✅ Done Reimbursement exclusion
calculateShare() - returns 0 if participant not in paidFor 🟡 P1 🟢 Low ✅ Done Participant not involved in expense
getTotalActiveUserShare() - sums across expenses 🔴 P0 🟡 Medium ✅ Done Total owed calculation
getTotalActiveUserShare() - rounds to 2 decimals 🟡 P1 🟢 Low ✅ Done Currency precision handling

Total: 14 tests | P0: 10, P1: 3, P2: 1 | Low effort: 14


1.3 Currency Utilities (src/lib/currency.ts, src/lib/utils.ts)

Test Case Priority Complexity Effort Notes
formatCurrency() - USD formatting (existing) 🔴 P0 🟢 Low ✅ Done Already tested in utils.test.ts
formatCurrency() - EUR formatting (existing) 🔴 P0 🟢 Low ✅ Done Already tested
formatCurrency() - custom currency symbols 🟡 P1 🟢 Low ✅ Done Test non-ISO currency
formatCurrency() - zero decimal currencies (JPY) 🟡 P1 🟢 Low ✅ Done Test decimal_digits = 0
amountAsDecimal() - converts cents to decimal 🔴 P0 🟢 Low ✅ Done Core conversion
amountAsDecimal() - handles rounding when requested 🟡 P1 🟢 Low ✅ Done Optional rounding param
amountAsMinorUnits() - converts decimal to cents 🔴 P0 🟢 Low ✅ Done Inverse of above
amountAsMinorUnits() - rounds correctly 🟡 P1 🟢 Low ✅ Done No floating point issues
formatAmountAsDecimal() - formats with correct decimals 🟡 P1 🟢 Low ✅ Done String formatting
getCurrency() - returns currency by code 🔴 P0 🟢 Low ✅ Done Lookup function
getCurrency() - returns custom for empty code 🟡 P1 🟢 Low ✅ Done Fallback behavior
getCurrency() - handles locale variations 🟢 P2 🟢 Low ✅ Done i18n currency names
getCurrencyFromGroup() - extracts from group object 🟡 P1 🟢 Low ✅ Done Helper function
defaultCurrencyList() - includes custom currency 🟢 P2 🟢 Low ✅ Done Custom currency in list

Total: 14 tests | P0: 5, P1: 7, P2: 2 | Low effort: 12, Done: 2


1.4 Utility Functions (src/lib/utils.ts)

Test Case Priority Complexity Effort Notes
formatDate() - formats with locale 🟡 P1 🟢 Low ✅ Done Date display
formatDateOnly() - avoids timezone shifts 🔴 P0 🟡 Medium ✅ Done Critical for DATE fields, UTC handling
formatDateOnly() - handles month boundaries 🟡 P1 🟡 Medium ✅ Done Edge case - dates near midnight
formatFileSize() - formats bytes correctly 🟢 P2 🟢 Low ✅ Done Utility function
formatFileSize() - handles GB, MB, KB, B units 🟢 P2 🟢 Low ✅ Done Unit conversion
normalizeString() - removes accents 🟡 P1 🟢 Low ✅ Done Search functionality
normalizeString() - lowercases 🟡 P1 🟢 Low ✅ Done Case-insensitive search
formatCategoryForAIPrompt() - formats correctly 🟢 P2 🟢 Low ✅ Done AI feature helper
delay() - resolves after ms 🔵 P3 🟢 Low ✅ Done Simple utility
cn() - merges class names 🔵 P3 🟢 Low ✅ Done TailwindCSS helper

Total: 10 tests | P0: 1, P1: 4, P2: 3, P3: 2 | Low effort: 9, Medium: 1


1.5 Schemas & Validation (src/lib/schemas.ts)

Test Case Priority Complexity Effort Notes
expenseFormSchema - validates required fields 🔴 P0 🟢 Low ✅ Done Form validation
expenseFormSchema - rejects invalid split mode 🔴 P0 🟢 Low ✅ Done Enum validation
expenseFormSchema - validates percentage sums to 100% 🔴 P0 🟡 Medium ✅ Done Business rule
expenseFormSchema - validates amount sum equals total 🔴 P0 🟡 Medium ✅ Done BY_AMOUNT validation
expenseFormSchema - allows valid recurring rules 🟡 P1 🟢 Low ✅ Done Enum validation
groupFormSchema - validates group creation 🔴 P0 🟢 Low ✅ Done Group validation
groupFormSchema - requires at least 2 participants 🔴 P0 🟢 Low ✅ Done Business rule
groupFormSchema - validates currency format 🟡 P1 🟢 Low ✅ Done Currency validation

Total: 8 tests | P0: 6, P1: 2 | Low effort: 6, Medium: 2


2. JEST INTEGRATION TESTS (API & Database)

These tests require database setup but test important business logic flows. Use test database or mocks.

2.1 Recurring Expense Logic (src/lib/api.ts)

Test Case Priority Complexity Effort Notes
createRecurringExpenses() - creates daily recurring 🔴 P0 🔴 High ✅ Done Complex, requires DB
createRecurringExpenses() - creates weekly recurring 🔴 P0 🔴 High ✅ Done Date arithmetic
createRecurringExpenses() - creates monthly recurring 🔴 P0 🔴 High ✅ Done Edge cases: 29-31st dates
createRecurringExpenses() - handles month boundaries 🟡 P1 🔴 High ✅ Done Feb 29, 30, 31 edge cases
createRecurringExpenses() - stops at correct time 🔴 P0 🟡 Medium ✅ Done Verify loop termination
createRecurringExpenses() - uses transactions 🟡 P1 🔴 High ✅ Done Race condition prevention
createPayloadForNewRecurringExpenseLink() - daily 🟡 P1 🟡 Medium ✅ Done Payload generation
createPayloadForNewRecurringExpenseLink() - weekly 🟡 P1 🟡 Medium ✅ Done Payload generation
createPayloadForNewRecurringExpenseLink() - monthly 🟡 P1 🟡 Medium ✅ Done Payload generation

Total: 9 tests | P0: 4, P1: 5 | Medium: 3, High: 6

⚠️ Note: These are complex and require careful DB setup. Consider mocking Prisma for faster tests.


2.2 Activity Logging (src/lib/api.ts)

Test Case Priority Complexity Effort Notes
logActivity() - logs CREATE_EXPENSE 🟡 P1 🟡 Medium ✅ Done Audit trail
logActivity() - logs UPDATE_EXPENSE 🟡 P1 🟡 Medium ✅ Done Audit trail
logActivity() - logs DELETE_EXPENSE 🟡 P1 🟡 Medium ✅ Done Audit trail
logActivity() - logs UPDATE_GROUP 🟡 P1 🟡 Medium ✅ Done Audit trail
logActivity() - stores participant ID 🟢 P2 🟡 Medium ✅ Done User tracking
logActivity() - stores expense data 🟢 P2 🟡 Medium ✅ Done Metadata storage

Total: 6 tests | P1: 4, P2: 2 | Medium: 6


3. PLAYWRIGHT E2E TESTS

These tests verify user-facing functionality through the browser. Focus on critical user journeys.

3.1 Group Management Flows

Test Case Priority Complexity Effort Notes
Create group - happy path 🔴 P0 🟢 Low ✅ Done Core user flow
Create group - with custom currency 🟡 P1 🟢 Low ✅ Done Custom currency selection
Create group - validation errors 🟡 P1 🟡 Medium ✅ Done Form validation
Edit group - update name and info 🟡 P1 🟢 Low ✅ Done Edit flow
Edit group - add participant 🔴 P0 🟡 Medium ✅ Done Important feature
Edit group - remove participant 🟡 P1 🟡 Medium ✅ Done Important feature
Edit group - rename participant 🟢 P2 🟢 Low ✅ Done Edit participant
View group information page 🟢 P2 🟢 Low ✅ Done Read-only view
Share group - copy URL 🟡 P1 🟡 Medium ✅ Done Collaboration feature
Recent groups list - persists 🟢 P2 🟡 Medium ✅ Done LocalStorage test
Navigate between groups 🟢 P2 🟢 Low ✅ Done Navigation

Total: 11 tests | P0: 2, P1: 5, P2: 4 | Low effort: 6, Medium: 5


3.2 Expense Management Flows

Test Case Priority Complexity Effort Notes
Create expense - evenly split 🔴 P0 🟡 Medium ✅ Done Most common flow
Create expense - by shares 🔴 P0 🟡 Medium ✅ Done Weighted split
Create expense - by percentage 🔴 P0 🟡 Medium ✅ Done Percentage split
Create expense - by amount 🔴 P0 🟡 Medium ✅ Done Specific amounts
Create expense - with category 🟡 P1 🟢 Low ✅ Done Category selection
Create expense - with notes 🟢 P2 🟢 Low ✅ Done Optional field
Create expense - with custom date 🟡 P1 🟢 Low ✅ Done Date picker
Create expense - with currency conversion 🟡 P1 🟡 Medium ✅ Done Multi-currency
Create expense - as reimbursement 🟡 P1 🟢 Low ✅ Done Reimbursement flag
Create expense - validation errors 🟡 P1 🟡 Medium ✅ Done Form validation
Edit expense - update all fields 🟡 P1 🟡 Medium ✅ Done Edit flow
Edit expense - change split mode 🟡 P1 🟡 Medium ✅ Done Mode switching
Delete expense - confirmation flow 🔴 P0 🟢 Low ✅ Done Deletion
List expenses - pagination 🟡 P1 🟡 Medium ✅ Done Large lists
List expenses - filter by text 🟡 P1 🟡 Medium ✅ Done Search functionality
Expense displays correct date 🟡 P1 🟢 Low ✅ Done Date rendering
Expense displays correct amount 🔴 P0 🟢 Low ✅ Done Amount display
Expense shows category 🟢 P2 🟢 Low ✅ Done Category display

Total: 18 tests | P0: 4, P1: 11, P2: 3 | Low effort: 10, Medium: 8


3.3 Recurring Expenses Flow

Test Case Priority Complexity Effort Notes
Create daily recurring expense 🔴 P0 🟡 Medium ✅ Done Fill form, select Daily, submit, verify recurring indicator UI
Create weekly recurring expense 🔴 P0 🟡 Medium ✅ Done Fill form, select Weekly, submit, verify UI
Create monthly recurring expense 🔴 P0 🟡 Medium ✅ Done Fill form, select Monthly, submit, verify UI
Verify recurring instances created 🔴 P0 🔴 High ✅ Done Create recurring; trigger backend job/mock time; verify new expense in list
Edit recurring expense - stops future (missing feature #492) 🟡 P1 🟡 Medium N/A Missing feature spliit-app/spliit#492, do not test
Delete recurring expense - only current 🟡 P1 🟡 Medium ✅ Done Delete a recurring instance; assert other instances in chain remain
Recurring expense shows indicator 🟢 P2 🟢 Low ✅ Done UI element

Total: 7 tests | P0: 4, P1: 2, P2: 1 | Low effort: 1, Medium: 4, High: 2


3.4 Balance & Reimbursement Flows

Test Case Priority Complexity Effort Notes
View balances page - calculates correctly 🔴 P0 🟡 Medium ✅ Done Core feature
Balances match expected from expenses 🔴 P0 🟡 Medium ✅ Done Verification test
Suggested reimbursements displayed 🔴 P0 🟢 Low ✅ Done Suggestions shown
Suggested reimbursements minimized 🟡 P1 🟡 Medium ✅ Done Algorithm verification
Active user balance highlighted 🟡 P1 🟢 Low ✅ Done Personalization
Create reimbursement expense 🟡 P1 🟡 Medium ✅ Done Settle debt flow
Reimbursement excludes from totals 🔴 P0 🟡 Medium ✅ Done Important logic
Zero balances display correctly 🟢 P2 🟢 Low ✅ Done Edge case

Total: 8 tests | P0: 4, P1: 3, P2: 1 | Low effort: 4, Medium: 4


3.5 Statistics & Export Flows

Test Case Priority Complexity Effort Notes
View statistics page 🟡 P1 🟢 Low ✅ Done Stats display
Total group spending correct 🔴 P0 🟡 Medium ✅ Done Calculation verification
User total paid correct 🔴 P0 🟡 Medium ✅ Done Personalization
User total share correct 🔴 P0 🟡 Medium ✅ Done Personalization
Export to JSON - downloads file 🟡 P1 🟡 Medium ✅ Done Export functionality
Export to JSON - correct data 🟡 P1 🟡 Medium ✅ Done Data verification
Export to CSV - downloads file 🟡 P1 🟡 Medium ✅ Done Export functionality
Export to CSV - correct format 🟡 P1 🟡 Medium ✅ Done CSV structure

Total: 8 tests | P0: 3, P1: 5 | Low effort: 1, Medium: 7


3.6 Active User Selection

Test Case Priority Complexity Effort Notes
Select active user - persists 🟡 P1 🟡 Medium ✅ Done LocalStorage test
Active user changes balance view 🔴 P0 🟡 Medium ✅ Done Personalization
Active user changes stats 🔴 P0 🟡 Medium ✅ Done Personalization
Clear active user - neutral view 🟢 P2 🟢 Low ✅ Done Reset feature

Total: 4 tests | P0: 2, P1: 1, P2: 1 | Low effort: 1, Medium: 3


3.7 Activity Log

Test Case Priority Complexity Effort Notes
View activity page 🟢 P2 🟢 Low ✅ Done Activity list
Activity shows expense creation 🟢 P2 🟡 Medium ✅ Done Audit log
Activity shows expense update 🟢 P2 🟡 Medium ✅ Done Audit log
Activity shows expense deletion 🟢 P2 🟡 Medium ✅ Done Audit log
Activity pagination works 🟢 P2 🟡 Medium ✅ Done Long lists

Total: 5 tests | P2: 5 | Low effort: 1, Medium: 4


3.8 Category Management

Test Case Priority Complexity Effort Notes
Select category when creating expense 🟡 P1 🟢 Low ✅ Done Dropdown selection
Category displays on expense 🟡 P1 🟢 Low ✅ Done Display test
Default category (General) selected 🟢 P2 🟢 Low ✅ Done Default behavior

Total: 3 tests | P1: 2, P2: 1 | Low effort: 3


3.9 Internationalization (i18n)

Test Case Priority Complexity Effort Notes
Change language - UI updates 🟢 P2 🟡 Medium 🍊 Medium i18n test
Currency formats per locale 🟡 P1 🟡 Medium ✅ Done Locale formatting
Date formats per locale 🟡 P1 🟡 Medium ✅ Done Locale formatting

Total: 3 tests | P1: 2, P2: 1 | Medium: 3


3.10 Theme & UI

Test Case Priority Complexity Effort Notes
Toggle dark mode - persists 🟢 P2 🟢 Low ✅ Done Theme switching
Mobile responsive - drawer opens 🟡 P1 🟡 Medium ✅ Done Mobile testing
Desktop responsive - dialog opens 🟡 P1 🟡 Medium ✅ Done Desktop testing

Total: 3 tests | P1: 2, P2: 1 | Low effort: 1, Medium: 2


3.11 Document Upload (if S3 enabled)

Test Case Priority Complexity Effort Notes
Upload document to expense 🟡 P1 🔴 High 🍎 High S3 integration
Multiple documents on expense 🟢 P2 🔴 High 🍎 High S3 integration
Document displays in expense 🟡 P1 🔴 High 🍎 High S3 integration

Total: 3 tests | P1: 2, P2: 1 | High: 3

⚠️ Note: Requires S3 setup or mocking. Skip if feature flag disabled.


3.12 Health Endpoints

Test Case Priority Complexity Effort Notes
/api/health/liveness returns 200 🟡 P1 🟢 Low ✅ Done Health check
/api/health/readiness checks DB 🟡 P1 🟡 Medium ✅ Done DB health

Total: 2 tests | P1: 2 | Low effort: 1, Medium: 1


4. TEST PRIORITY SUMMARY

Note: Status in this section is informational and may lag behind per-section tables.

Immediate Implementation (🍏 Low Hanging Fruit)

Jest Unit Tests (High ROI, Fast):

  1. Balance calculations - all split modes (6 tests)
  2. Total calculations - group and user totals (8 tests)
  3. Currency conversion utilities (8 tests)
  4. Schema validations (6 tests)

Playwright E2E (Critical Paths):

  1. Create group happy path (1 test)
  2. Create expense - evenly split (1 test)
  3. Delete expense (1 test)
  4. View balances (1 test)
  5. Suggested reimbursements display (1 test)

Estimated: ~30 tests, 2-3 days


Phase 2 (🍊 Medium Effort)

Jest Unit Tests:

  1. Complex balance scenarios (4 tests)
  2. Date handling edge cases (3 tests)
  3. Schema validation edge cases (2 tests)

Playwright E2E:

  1. All expense split modes (3 tests)
  2. Edit flows (5 tests)
  3. Currency conversion (2 tests)
  4. Export functionality (4 tests)

Estimated: ~23 tests, 3-4 days


Phase 3 (🍎 High Effort)

Jest Integration Tests:

  1. Recurring expense creation logic (9 tests)
  2. Activity logging (6 tests)

Playwright E2E:

  1. Recurring expense flows (4 tests)
  2. Document upload (if enabled) (3 tests)
  3. Complex multi-user scenarios (3 tests)

Estimated: ~25 tests, 5-7 days


Phase 4 (Nice to Have)

Lower Priority Tests:

  1. Edge cases (P2/P3 tests)
  2. UI/UX tests (theme, responsive)
  3. i18n tests
  4. Activity log tests

Estimated: ~30 tests, 3-4 days


5. TEST ORGANIZATION

Recommended File Structure

├── src/
│   └── lib/
│       ├── balances.test.ts          # Balance calculation tests
│       ├── totals.test.ts            # Totals & statistics tests
│       ├── currency.test.ts          # Currency utilities tests
│       ├── utils.test.ts             # Utility functions tests (exists)
│       ├── schemas.test.ts           # Zod schema validation tests
│       └── api.test.ts               # API integration tests (requires DB)
├── tests/
│   ├── e2e/
│   │   ├── group-management.spec.ts
│   │   ├── expense-crud.spec.ts
│   │   ├── expense-split-modes.spec.ts
│   │   ├── recurring-expenses.spec.ts
│   │   ├── balances.spec.ts
│   │   ├── statistics.spec.ts
│   │   ├── active-user.spec.ts
│   │   ├── export.spec.ts
│   │   ├── activity-log.spec.ts
│   │   └── ui.spec.ts
│   └── fixtures/
│       ├── test-data.ts              # Shared test data
│       └── test-helpers.ts           # Helper functions

6. TESTING BEST PRACTICES

Jest Best Practices

  1. Isolation: Each test should be independent
  2. Naming: Use descriptive test names - it('should calculate evenly split for 3 participants')
  3. Arrange-Act-Assert: Structure tests clearly
  4. Test Data: Use factories/fixtures for consistent test data
  5. Mock Sparingly: Only mock external dependencies (DB, API calls)
  6. Fast: Unit tests should run in milliseconds
  7. Coverage: Aim for 80%+ coverage on business logic

Playwright Best Practices

  1. Page Object Model: Create page objects for reusable selectors
  2. Fixtures: Use Playwright fixtures for setup/teardown
  3. Locators: Use accessible selectors (role, label, text)
  4. Waits: Use auto-waiting, avoid hard waits
  5. Assertions: Use Playwright's expect for auto-retrying assertions
  6. Test Data: Clean up test data after each run
  7. Parallel: Run tests in parallel when possible (config already set to fullyParallel: false - consider enabling per test file)
  8. Screenshots: Capture on failure for debugging
  9. Mobile: Test both mobile and desktop viewports
  10. Network: Mock external API calls (currency rates, OpenAI) for reliability

7. MOCK STRATEGIES

What to Mock

Jest Unit Tests:

  • ❌ Don't mock: Pure functions (balances, totals, currency)
  • ✅ Mock: Prisma client for API tests
  • ✅ Mock: External APIs (OpenAI, currency rates)

Playwright E2E:

  • ❌ Don't mock: Database (use test DB)
  • ✅ Mock: External APIs (OpenAI, Frankfurter currency API)
  • ✅ Mock: S3 uploads (unless testing S3 feature)
  • ✅ Mock: Email/notifications (if added)

Test Database Strategy

For integration tests, use one of:

  1. SQLite in-memory: Fast, no setup, but may have dialect differences
  2. PostgreSQL test container: Realistic, requires Docker
  3. Prisma mocking: Fast, but requires more setup

Recommendation: PostgreSQL test container for realism, or Prisma mocking for speed.


8. COVERAGE GOALS

Target Coverage by Module

Module Current Target Priority
src/lib/balances.ts 0% 95%+ 🔴 P0
src/lib/totals.ts 0% 95%+ 🔴 P0
src/lib/currency.ts 0% 90%+ 🔴 P0
src/lib/utils.ts ~30% 90%+ 🟡 P1
src/lib/schemas.ts 0% 80%+ 🔴 P0
src/lib/api.ts 0% 70%+ 🟡 P1
E2E Critical Paths 0% 100% 🔴 P0

9. IMPLEMENTATION ROADMAP

Week 1: Foundation (🍏 Low Hanging Fruit)

  • Setup Jest test structure
  • Balance calculation tests (17 tests)
  • Totals calculation tests (14 tests)
  • Basic E2E flows (5 tests)
  • Deliverable: ~36 tests, core logic validated

Week 2: Expansion (🍊 Medium Effort)

  • Currency & utils tests (14 tests)
  • Schema validation tests (8 tests)
  • Expense CRUD E2E (10 tests)
  • Balance E2E verification (4 tests)
  • Deliverable: ~36 tests, critical features covered

Week 3: Advanced (🍎 High Effort)

  • Recurring expense logic (9 tests)
  • Activity logging (6 tests)
  • Recurring E2E flows (7 tests)
  • Export functionality (8 tests)
  • Deliverable: ~30 tests, complex features validated

Week 4: Polish & Edge Cases

  • Edge case tests (P2/P3)
  • UI/UX tests (6 tests)
  • i18n tests (3 tests)
  • Activity log E2E (5 tests)
  • Documentation updates
  • Deliverable: ~30 tests, comprehensive coverage

Total Estimated: ~130+ tests over 4 weeks


10. KEY RISKS & MITIGATIONS

Risk Impact Mitigation
Recurring expense time-based tests flaky High Use fixed dates, mock Date.now()
Database setup complexity Medium Use Docker Compose for test DB
S3 tests require AWS setup Medium Mock S3 or skip with feature flag check
OpenAI API costs in tests Low Always mock AI features
Timezone issues in date tests High Use UTC, test formatDateOnly() thoroughly
Test data cleanup Medium Use Playwright fixtures for automatic cleanup
Floating point rounding errors High Thoroughly test rounding in balances

11. SUCCESS METRICS

Immediate (Week 1-2):

  • ✅ 80%+ coverage on balances.ts, totals.ts, currency.ts
  • ✅ All P0 unit tests passing
  • ✅ Basic E2E flow working (create group → create expense → view balance)

Medium Term (Week 3-4):

  • ✅ 70%+ overall code coverage
  • ✅ All P0 and P1 tests implemented
  • ✅ CI/CD integration (tests run on PR)
  • ✅ Test execution time < 5 minutes (unit + integration)
  • ✅ E2E execution time < 10 minutes

Long Term:

  • ✅ 80%+ overall code coverage
  • ✅ All P0, P1, P2 tests implemented
  • ✅ Zero flaky tests
  • ✅ Test-driven development for new features

12. TOTAL TEST COUNT SUMMARY

Category P0 P1 P2 P3 Total Low Effort Med Effort High Effort
Jest Unit Tests 37 22 6 2 67 52 11 4
Playwright E2E 23 38 16 0 77 34 33 10
GRAND TOTAL 60 60 22 2 144 86 44 14

Priority Breakdown:

  • 🔴 P0 (Critical): 60 tests - Core functionality
  • 🟡 P1 (High): 60 tests - Important features
  • 🟢 P2 (Medium): 22 tests - Nice to have
  • 🔵 P3 (Low): 2 tests - Edge cases

Effort Breakdown:

  • 🍏 Low Hanging Fruit: 86 tests (~60%) - Quick wins
  • 🍊 Medium Effort: 44 tests (~31%) - Moderate investment
  • 🍎 High Effort: 14 tests (~10%) - Complex scenarios

Notes

  • No code changes needed: All tests can be written against existing code
  • Fast & Simple: Focus on pure unit tests first (balances, totals, currency)
  • Best Practices: Follow Jest & Playwright conventions
  • Prioritized: P0 tests are must-haves, P3 are optional
  • Realistic Estimates: 130+ tests achievable in 4 weeks with 1 developer

This plan provides a clear roadmap from quick wins to comprehensive coverage without modifying application code.

Spliit Pending Test Implementation Tasks

1. Integration Tests (Jest)

Note: These tests use real Prisma with a test database. No mocking required - set up a test DB connection.

Recurring Expense Logic

Location: src/lib/api.test.ts

Status Priority Task Implementation Guide
✅ Done 🔴 P0 Create daily recurring expense Verify createRecurringExpenses creates correct number of instances for daily interval. Use test DB.
✅ Done 🔴 P0 Create weekly recurring expense Verify correct dates are generated for weekly interval (e.g., every Monday).
✅ Done 🔴 P0 Create monthly recurring expense Verify createRecurringExpenses creates correct date for monthly interval. Use test DB.
✅ Done 🟡 P1 Handle month boundaries Test edge cases like Jan 31st → Feb 28/29, Mar 31st. Ensure dates don't skip or error.
✅ Done 🟡 P1 Use transactions Verify DB operations are wrapped in a transaction. Create test data, force error, verify rollback.
✅ Done 🟡 P1 Payload: Daily Unit test createPayloadForNewRecurringExpenseLink returns correct next date for daily.
✅ Done 🟡 P1 Payload: Weekly Unit test payload generation for weekly interval.
✅ Done 🟡 P1 Payload: Monthly Unit test payload generation for monthly interval.

Activity Logging

Location: src/lib/api.test.ts

Status Priority Task Implementation Guide
✅ Done 🟡 P1 Log CREATE_EXPENSE Call logActivity with 'create' action. Query test DB to verify insert with correct JSON.
✅ Done 🟡 P1 Log UPDATE_EXPENSE Call with 'update' action. Query test DB to verify insert includes diff or new state.
✅ Done 🟡 P1 Log DELETE_EXPENSE Call with 'delete' action. Query test DB to verify insert.
✅ Done 🟡 P1 Log UPDATE_GROUP Call with 'update' action for group changes. Query test DB to verify insert.
✅ Done 🟢 P2 Store Participant ID Verify participantId column is correctly populated in Activity table via DB query.
✅ Done 🟢 P2 Store Expense Data Verify data column contains valid JSON snapshot of the expense via DB query.

2. E2E Tests (Playwright)

Group & Expense Management

Location: tests/e2e/group-management.spec.ts / expense-crud.spec.ts

Status Priority Task Implementation Guide
✅ Done 🟢 P2 Recent groups persistence Visit a group, go home, reload page. Assert group appears in "Recent" list (LocalStorage).
✅ Done 🟡 P1 List pagination Seed 20+ expenses. Verify "Load More" or infinite scroll loads subsequent items. Create helper utility to create such amount of expenses via API and not via UI. Creating via UI will lead to timeout and long test duration.
✅ Done 🟡 P1 List text filter Type unique string in search bar. Assert only matching expenses are visible.

Recurring Expenses Flow

Location: tests/e2e/recurring-expenses.spec.ts

Status Priority Task Implementation Guide
✅ Done 🔴 P0 Create daily recurring Fill expense form, select "Daily". Submit. Verify generic recurring indicator UI.
✅ Done 🔴 P0 Create weekly recurring Fill form, select "Weekly". Submit. Verify UI.
✅ Done 🔴 P0 Create monthly recurring Fill form, select "Monthly". Submit. Verify UI.
✅ Done 🔴 P0 Verify instances created (Complex) Create recurring expense. Trigger backend job or mock time. Verify new expense appears in list.
⬜ Missing feature spliit-app/spliit#492, do not test 🟡 P1 Edit stops future Edit a recurring instance. Assert future instances are unlinked or modified according to logic.
✅ Done 🟡 P1 Delete current only Delete a recurring instance. Assert other instances in the chain remain.

Statistics & Export

Location: tests/e2e/statistics.spec.ts / export.spec.ts

Status Priority Task Implementation Guide
✅ Done 🔴 P0 Verify Group Total Sum expenses in list. Assert Stats page "Total Group Spending" matches.
✅ Done 🔴 P0 Verify User Paid Assert "You Paid" matches sum of active user's payments.
✅ Done 🔴 P0 Verify User Share Assert "Your Share" matches sum of active user's splits.
✅ Done 🟡 P1 Export JSON download Click JSON export. Wait for download event. Assert filename/extension.
✅ Done 🟡 P1 Export JSON content Read downloaded JSON. Assert it contains valid array of expense objects.
✅ Done 🟡 P1 Export CSV download Click CSV export. Wait for download event.
✅ Done 🟡 P1 Export CSV format Read downloaded CSV. Assert headers and row data match expenses.

Active User & Activity

Location: tests/e2e/active-user.spec.ts / activity-log.spec.ts

Status Priority Task Implementation Guide
✅ Done 🟡 P1 Selection persists Select user. Reload page. Assert user is still selected (LocalStorage).
✅ Done 🔴 P0 Updates stats Change active user. Assert Stats page numbers update to reflect new user.
✅ Done 🟢 P2 Log shows create Create expense. Go to Activity. Assert "Created expense X" entry exists.
✅ Done 🟢 P2 Log shows update Edit expense. Go to Activity. Assert "Updated expense X" entry exists.
✅ Done 🟢 P2 Log shows delete Delete expense. Go to Activity. Assert "Deleted expense X" entry exists.
✅ Done 🟢 P2 Log pagination Generate many activities. Verify pagination controls work on Activity page.

System & UI

Location: tests/e2e/ui.spec.ts

Status Priority Task Implementation Guide
⬜ Todo 🟢 P2 i18n UI updates Switch lang to Spanish. Assert static text (headers/buttons) changes.
✅ Done 🟡 P1 i18n Currency format Switch lang/locale. Assert currency symbol position (€10 vs 10€).
✅ Done 🟡 P1 i18n Date format Switch lang. Assert date format changes (MM/DD vs DD/MM).
✅ Done 🟡 P1 Mobile responsive Set viewport to mobile. Assert drawer menu works instead of sidebar.
✅ Done 🟡 P1 Desktop responsive Set viewport to desktop. Assert dialogs/sidebar appear correctly.
✅ Done 🟡 P1 Health Readiness Fetch /api/health/readiness. Assert status 200 (database connected).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment