Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
dea4dd0
chore: ignore .worktrees directory
Ayash-Bera Apr 18, 2026
3874784
test: unit tests for Send/helpers isValidAddress, isValidAmount, isVa…
Ayash-Bera Apr 18, 2026
838a66e
test: add sweep-mode positive and NaN cases to isValidAmount tests
Ayash-Bera Apr 18, 2026
21d3248
test: unit tests for isFeatureEnabled version boundary logic
Ayash-Bera Apr 18, 2026
2f2068b
test: unit tests for utxoTags status, label, fidelity bond, and lockt…
Ayash-Bera Apr 18, 2026
788ac91
test: component tests for SendForm field rendering
Ayash-Bera Apr 18, 2026
9a5a181
test: integration tests for Send page rendering and loading state
Ayash-Bera Apr 18, 2026
c6bb471
test: component tests for Earn page rendering and initial state
Ayash-Bera Apr 18, 2026
98a9819
test: component tests for FeeConfigModal visibility and section rende…
Ayash-Bera Apr 18, 2026
a45903d
test: add afterEach cleanup for FeeConfigModal spy isolation
Ayash-Bera Apr 18, 2026
754ee98
test: add jest coverage thresholds above measured baseline
Ayash-Bera Apr 18, 2026
3a3830c
ci: enforce coverage thresholds in build pipeline
Ayash-Bera Apr 18, 2026
66caf83
docs: add TESTING.md with provider wrapping, API mocking, and WebSock…
Ayash-Bera Apr 18, 2026
391e29e
fix: correct test fixtures and boundary values from review
Ayash-Bera Apr 18, 2026
f384aff
fix: address critical review issues before PR merge
Ayash-Bera Apr 18, 2026
c615090
test: add unit tests for toStartMakerRequest maker fee logic
Ayash-Bera Apr 20, 2026
018af99
test: add per-folder coverage threshold for Send/ directory
Ayash-Bera Apr 20, 2026
d21b2c1
docs: add per-file baseline coverage notes with risk annotations
Ayash-Bera Apr 20, 2026
f3f3c0e
fix: add missing displayName to SendForm.test.tsx wallet fixture
Ayash-Bera Apr 20, 2026
9c946f2
test: add SendForm behavioral tests for valid submission and validati…
Ayash-Bera Apr 20, 2026
19d0917
test: add FeeConfigModal behavioral tests for load failure, save succ…
Ayash-Bera Apr 20, 2026
a71167c
test: add Send/index loading and direct-send API branching tests
Ayash-Bera Apr 20, 2026
8ecdcab
test: add Earn behavioral tests for maker start and disabled state
Ayash-Bera Apr 20, 2026
2dd308d
test: add coverage thresholds for Earn and settings/ critical paths
Ayash-Bera Apr 20, 2026
52a57c8
test: add Send/index negative-path tests and fix coinjoin toggle sele…
Ayash-Bera Apr 20, 2026
b203e5e
test: fix double import and strengthen selectors in Send/index.test
Ayash-Bera Apr 20, 2026
84460bc
test: add Earn maker-start failure and stop-maker lifecycle tests
Ayash-Bera Apr 20, 2026
92ffe30
test: type setupSession and makeOkResponse in Earn.test
Ayash-Bera Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ jobs:
run: npm run lint
# Test
- name: Test
run: npm test
run: npm test -- --coverage --watchAll=false
env:
CI: true
# Build
- name: Build
run: npm run build
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
npm-debug.log*

.idea/
.worktrees
82 changes: 82 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Testing Guide

## Provider Wrapping

All component tests must render inside the full provider tree. Import `render` from `src/testUtils.tsx` instead of `@testing-library/react` — it wraps components with `I18nextProvider`, `SettingsProvider`, `WalletProvider`, `ServiceConfigProvider`, `WebsocketProvider`, and `ServiceInfoProvider`.

```tsx
// correct
import { render, screen } from '../../testUtils'

// incorrect — missing context
import { render, screen } from '@testing-library/react'
```

Components that use `react-router-dom` hooks (`useNavigate`, `Link`) also need a `BrowserRouter` wrapper:

```tsx
render(
<BrowserRouter>
<MyComponent />
</BrowserRouter>
)
```

## API Mocking

Mock `src/libs/JmWalletApi` at the top of each test file. Spread `jest.requireActual` to keep type definitions and only override the functions you need:

```tsx
jest.mock('../../libs/JmWalletApi', () => ({
...jest.requireActual('../../libs/JmWalletApi'),
postCoinjoin: jest.fn(),
postDirectSend: jest.fn(),
}))
```

Use `neverResolves` for loading states, `Promise.resolve(mockResponse)` for success, `Promise.reject(new Error('...'))` for error states:

```tsx
const neverResolves = new Promise(() => {})
const successResponse = { ok: true, status: 200, json: async () => ({ result: 'ok' }) }

beforeEach(() => {
;(apiMock.postCoinjoin as jest.Mock).mockReturnValue(neverResolves)
})
```

## WebSocket Mocking

`jest-websocket-mock` is available as a devDependency. Create a mock server before each test and clean up after:

```tsx
import WS from 'jest-websocket-mock'

let wsServer: WS

beforeEach(() => {
wsServer = new WS('ws://localhost/jmws')
})

afterEach(() => {
WS.clean()
})
```

Simulate incoming messages to trigger state updates in `WebsocketProvider`:

```tsx
wsServer.send(JSON.stringify({ type: 'walletupdate', utxos: [] }))
```

## Coverage Enforcement

Coverage thresholds live in the `jest.coverageThreshold` block in `package.json`. CI runs `npm test -- --coverage --watchAll=false` which fails if any threshold is not met.

To raise thresholds after adding new tests:
1. Run `CI=true npm test -- --coverage --watchAll=false`
2. Check the `All files` row in the output
3. Update thresholds to `floor(new value)` in `package.json`
4. Commit and push

Also update thresholds when adding new source files without tests — new untested code lowers coverage percentages and will cause CI to fail if thresholds aren't adjusted.
89 changes: 89 additions & 0 deletions docs/baseline-coverage-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Baseline Coverage Notes

## Test environment

- Framework: Jest via `react-scripts` (CRA)
- Test runner: `CI=true npm test -- --coverage --watchAll=false`
- Coverage reporter: Istanbul (built into react-scripts)

## Pre-PR baseline (upstream master at v0.4.1, commit dcfab49)

Running the test suite with coverage restricted to the test files that existed
at dcfab49 (i.e., excluding the seven test files added in this PR):

| Metric | Value |
|------------|--------|
| Statements | 27.58% |
| Branches | 17.26% |
| Functions | 21.34% |
| Lines | 28.04% |

Test suites: 14 | Tests: 119

## Target files — absent from pre-PR coverage output

These files were not imported (directly or transitively) by the pre-existing test
files, so they did not appear in the coverage report at all:

| File | Risk | Reason |
|---|---|---|
| `src/components/Send/helpers.ts` | High | Pure validation logic for all send amounts and addresses |
| `src/constants/features.ts` | High | Version-gated feature flags control UI availability |
| `src/components/utxo/utils.ts` | Medium | UTXO tag classification drives UI display logic |
| `src/components/Send/SendForm.tsx` | High | Central form controlling send transaction construction |
| `src/components/Send/index.tsx` | High | Orchestrates direct send and coinjoin flows |
| `src/components/Earn.tsx` | High | Maker start/stop lifecycle and fee configuration |
| `src/components/settings/FeeConfigModal.tsx` | Medium | Fee configuration that affects transaction economics |

## Post-PR coverage (feat/test-coverage)

After adding 169 tests across 22 suites:

| Metric | Before | After |
|------------|--------|--------|
| Statements | 27.58% | 38.79% |
| Branches | 17.26% | 28.70% |
| Functions | 21.34% | 31.08% |
| Lines | 28.04% | 39.53% |

Per-file coverage for the seven target files:

| File | Statements | Branches | Functions | Lines |
|---|---|---|---|---|
| `Send/helpers.ts` | 86.66% | 80.00% | 83.33% | 86.66% |
| `constants/features.ts` | 100% | 100% | 100% | 100% |
| `utxo/utils.ts` | 100% | 92.85% | 100% | 100% |
| `Send/SendForm.tsx` | 59.21% | 49.52% | 52.38% | 57.74% |
| `Send/index.tsx` | 40.11% | 26.85% | 36.95% | 39.02% |
| `Earn.tsx` | 42.85% | 35.53% | 29.09% | 44.44% |
| `settings/FeeConfigModal.tsx` | 47.05% | 38.88% | 38.09% | 46.34% |

## Notable uncovered files (high risk, no tests added)

These files remain uncovered because they require full integration setup
(wallet unlock, WebSocket session, fidelity bond state) that is out of scope
for this PR:

| File | Risk |
|---|---|
| `src/components/fb/CreateFidelityBond.tsx` | High |
| `src/components/fb/SpendFidelityBondModal.tsx` | High |
| `src/components/jar_details/JarDetailsOverlay.tsx` | High |
| `src/hooks/WaitForUtxosToBeSpent.ts` | Medium |

## Threshold justification

Global thresholds are set at `floor(measured_after)` — the minimum the test suite
reliably clears. This prevents false passing while not inflating the bar above
what the tests actually deliver.

The `Send/` folder threshold is set tighter (statements 42, branches 38,
functions 31, lines 43) because Send is a wallet-critical path and its coverage
is meaningfully higher than the global average. Regressions here should fail CI
independently of the global gate.

Note: Jest's internal branch and line computations differ slightly from the
rounded table values. Global thresholds for branches (27) and lines (38) are
set at `floor(jest_internal_value)` — the table shows 28.70% branches and
39.53% lines, but Jest computes 27.2% and 38.98% respectively when checking
thresholds.
28 changes: 27 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,32 @@
"clearMocks": true,
"transformIgnorePatterns": [
"node_modules/(?!@table-library)"
]
],
"coverageThreshold": {
"global": {
"statements": 38,
"branches": 27,
"functions": 30,
"lines": 38
},
"./src/components/Send/": {
"statements": 42,
"branches": 38,
"functions": 31,
"lines": 43
},
"./src/components/settings/": {
"statements": 60,
"branches": 60,
"functions": 53,
"lines": 59
},
"./src/components/Earn.tsx": {
"statements": 57,
"branches": 53,
"functions": 37,
"lines": 59
}
}
}
}
Loading