# Verb tests

URL: /code/file-conventions/verb-tests · Id: `page:code/file-conventions/verb-tests`

> A Verb test file holds the cases a Verb's Function must pass before any Change to it merges.

A file named `[Noun].[verb].test.ts` holds the cases a [Verb](/business/nouns/verb)'s [Function](/business/nouns/function) must pass before any [Change](/business/nouns/change) to it merges.

```text
nouns/
├── Lease.renew.ts
└── Lease.renew.test.ts    its cases
```

## Reference
TypeScript with `test`, `expect` and `run` from `startup-builder/test`. The same runner runs [Workflow](/business/nouns/workflow) test blocks.

| Export | Type | Holds |
| --- | --- | --- |
| `test(name, fn)` | function | One case |
| `run(input, stubs)` | function | Runs the Function with stubbed calls and returns `{ result, calls }` |
| `expect(value)` | function | Assertions on the result and the calls |

## Examples
### Minimal
```ts title="nouns/Lease.renew.test.ts"
import { expect, run, test } from 'startup-builder/test'

test('renews for a year', async () => {
  const { result } = await run({ lease: 'lease_1', months: 12 }, { Lease: { get: () => ({ $id: 'lease_1', endsOn: '2026-12-31' }) } })
  expect(result.endsOn).toBe('2027-12-31')
})
```

### Leaseline
Leaseline declares a `Lease` [Noun](/business/nouns/noun) and caps each rent increase.

```ts title="nouns/Lease.renew.test.ts"
import { expect, run, test } from 'startup-builder/test'

const lease = { $id: 'lease_1', endsOn: '2026-12-31', rent: { amount: 1800, currency: 'USD' } }

test('a 3% increase raises the rent', async () => {
  const { result, calls } = await run({ lease: 'lease_1', months: 12, increase: 0.03 }, { Lease: { get: () => lease } })
  expect(result.rent.amount).toBe(1854)
  expect(calls).toEqual(['Lease.update'])
})
```

## What it builds
The [SoftwareBuilder](/code/builders/software) runs every case on each preview.

- a check result per case on the Change
- `Change.merge` refuses while a case fails
- `npx startup-builder dev` reruns the cases on every save

## Good to know
- Calls to outside [Integrations](/business/nouns/integration) are stubbed, so a case never moves money or sends a [Message](/business/nouns/message).
- An agentic Function's cases replay recorded model output, so CI makes no model call.