---
name: test-coverage
description: Write Vitest specs for Vue 3 JavaScript (Vite Plus, happy-dom, @vue/test-utils) and analyze V8 coverage + Fallow health to prioritize test-first refactors. Reference implementation is work/realness. Use when writing or fixing tests, mocking composables, improving coverage, or after test:coverage or npx fallow fails thresholds.
---

# Tests, coverage, and refactor risk

Canonical reference: **`work/realness`** (`@realness.online/web`). Run every
command below from that directory.

Match `tests/**/*.spec.js` there. Do not introduce Jest, React Testing Library, TypeScript test files, or co-located `*.test.ts`.

Two jobs:

1. **Write specs** - patterns below; detail in [references/web-realness.md](references/web-realness.md)
2. **Prioritize** - `npm run test:risk` before refactors; not a blind chase for 100%

## Stack

| Piece | What we use |
| --- | --- |
| Runner | Vite Plus - `vp test`, `import ... from 'vite-plus/test'` |
| Engine | Vitest (`vite-plus-test` alias) |
| DOM | `happy-dom` |
| Vue | `@vue/test-utils` - prefer `shallowMount` |
| Language | JavaScript + JSDoc |
| Coverage | V8, 80% global, `all: true` |

## Commands

```bash
vp test run --reporter=dot          # npm run test
vp test watch                       # npm run test:watch
vp test run --coverage              # npm run test:coverage
vp test run --bail=1 --reporter=dot # npm run test:fail-fast
npm run test:risk                   # coverage + fallow + risk report
```

Pre-commit: `vp check --fix && vp run type && vp test run`.

## Writing specs

### Layout

- All specs in `tests/**/*.spec.js` mirroring `src/` (not co-located)
- `describe('@/utils/itemid', ...)` or view/component name
- `@/` -> `src/`; `@@/` -> `tests/mocks/`
- Config: `vite.config.js` -> `test` block; setup: `tests/setup.js`, `tests/mocks/`

### Skeleton

```javascript
import { describe, it, expect, vi, beforeEach } from 'vite-plus/test'
import { fn_under_test } from '@/utils/example'

describe('@/utils/example', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  it('describes behavior in plain language', () => {
    expect(fn_under_test('input')).toBe('output')
  })
})
```

Test behavior, not internals (JS style: AGENTS.md).

### Key patterns

| Pattern | Approach | Reference spec |
| --- | --- | --- |
| Pure utils | Input/output, nested `describe` | `tests/utils/itemid.spec.js` |
| Module mocks | Top-level `vi.mock()`; `vi.clearAllMocks()` in `beforeEach` | `tests/utils/itemid.spec.js` |
| Vue components | `shallowMount`, stubs, semantic queries | `tests/components/account/as-notifications.spec.js` |
| Composable mocks | `vi.hoisted()` refs for `vi.mock` closures | `tests/views/Account.spec.js` |
| Composables | `with_setup()` + `mount(defineComponent(...))` | `tests/use/poster.spec.js` |
| Async errors | `await expect(...).rejects.toThrow()` | `tests/utils/itemid.spec.js` |

**Hoisted mocks** (reset `.value` in `beforeEach`):

```javascript
const { mock_status, mock_enable } = vi.hoisted(() => {
  const create_ref = value => ({ value, __v_isRef: true })
  return {
    mock_status: create_ref('off'),
    mock_enable: vi.fn().mockResolvedValue(true)
  }
})

vi.mock('@/use/push', () => ({
  use_push: () => ({ status: mock_status, enable: mock_enable })
}))
```

Global mocks: `tests/mocks/default.js`, `tests/mocks/browser/*`. Per-spec mocks only when behavior differs.

`mockReset: false` in config - mocks keep implementations; clear call history each test.

### What we do not do

| Avoid | Use instead |
| --- | --- |
| Jest / React Testing Library | `vite-plus/test` + `@vue/test-utils` |
| TypeScript test files | `.spec.js` + JSDoc |
| `@faker-js/faker` | Domain fixtures (item IDs, directories) |
| supertest / live DB | Mock `idb-keyval`, `serverless` |
| `data-testid` | Semantic DOM queries |
| 100% coverage | 80% gate + risk report |

Full patterns, templates, file map: [references/web-realness.md](references/web-realness.md)

## Coverage workflow

### 1. Risk report (start here)

```bash
npm run test:risk
# or, if reports already exist:
npm run test:risk:report
```

Runs `scripts/prioritize-refactor-risk.js`.

- **Delete or wire** - fallow `unused-files`; do not add tests
- **Test before refactor** - ranked by coverage gap + CRAP + fan-in + hotspots + P0/P1

Options: `--threshold 80 --top 25 --root .`

### 2. Coverage-only table

```bash
node skills/test-coverage/scripts/summarize-coverage.js --root .
```

### 3. HTML + line detail

Open `coverage/index.html` for uncovered lines.

### 4. Fallow detail

```bash
npx fallow health --targets
npx fallow health --hotspots
npx fallow --format json
```

### 5. Classify each item

| Verdict | Meaning |
| --- | --- |
| **test-first** | Add/extend specs before refactor |
| **refactor-with-tests** | Some coverage; shore up hot paths then refactor |
| **delete-or-wire** | Fallow unused file - entry point or delete |
| **defer** | Low product risk |

Priority: **P0** IDs/auth/sync/payments, **P1** posters/potrace/3D, **P2** rest.

### 6. Implement tests

Only when the user asks. Re-run `npm run test:risk` after changes.

### 7. Evolving Fallow config

When behavior changes, update `.fallowrc.json`, [references/fallow-integration.md](references/fallow-integration.md), and this file if needed.

## Output format (risk reports)

```markdown
# Refactor risk (coverage + fallow)

## Delete or wire
- ...

## Test before refactor
| file | pri | cov% | risk | ... |

## Workflow
```

## Judgment principles

- Unused in fallow graph -> **delete or wire**, not test
- High complexity + low coverage + high fan-in -> **test-first**
- Cycles (`itemid` <-> `serverless`, `Directory`) -> characterize with tests, then break
- Nuclear triad: typecheck + lint + tests; coverage supports refactors
- Match existing spec style; extend specs over new files
- Excluded from coverage: `src/main.js`, `src/router.js`, `src/wasm/**`

## Scripts

| Script | Purpose |
| --- | --- |
| `scripts/summarize-coverage.js` | Coverage table |
| `scripts/prioritize-refactor-risk.js` | Coverage + fallow merge |
| `scripts/lib/coverage-metrics.js` | Shared Istanbul parsing |

## References

- [web-realness.md](references/web-realness.md) - stack, patterns, file map, judgment
- [fallow-integration.md](references/fallow-integration.md) - `.fallowrc.json`
- Vitest: https://vitest.dev/
- Vue Test Utils: https://test-utils.vuejs.org/
