TaxJar Mock Harness
The TaxJar mock harness is a local, self-contained replacement for
api.taxjar.com. It lets tests drive the full tax-bearing order flow
without a live TaxJar account or internet access.
It implements two TaxJar v2 endpoints:
POST /v2/taxes— returns deterministic tax based on a hard-coded US state rate table and a configurable nexus list.GET /v2/rates/:zip— returns the rate for a state identified by the?state=query parameter.
Everything lives under devtools/taxjar-mock/. Nothing in src/** depends
on it; the real TaxJar adapter points at it via the TAXJAR_API_BASE env var.
Quick start (manual exploration)
# Boot the mock on port 4004 (default)
pnpm taxjar-mock
# In another shell, hit it directly
curl -s -X POST http://localhost:4004/v2/taxes \
-H 'Content-Type: application/json' \
-d '{"to_state":"NY","amount":50,"shipping":5}' | jq .
The mock accepts any non-empty Authorization: Bearer <token> header — no
real API key is needed.
Rate table
| State | Rate |
|---|---|
| NY | 8.875% |
| CA | 7.25% |
| TX | 6.25% |
| FL | 6.00% |
| IL | 6.25% |
| PA | 6.00% |
| OH | 5.75% |
| NJ | 6.625% |
| GA | 4.00% |
| NC | 4.75% |
Any state not in the table returns a 0% rate. Nexus is simulated via the
nexusStates constructor option — states not in the list always return
0 tax regardless of rate.
Wiring in a test
import { startTaxJarMockServer } from '../devtools/taxjar-mock/server.js'
import { createTaxJarAdapter } from '../src/adapters/taxjar.adapter.js'
const mock = await startTaxJarMockServer({ port: 0, nexusStates: ['NY'] })
const adapter = createTaxJarAdapter({
apiKey: 'test-key', // any non-empty string
logger,
baseUrl: mock.baseUrl
})
// ...run test...
await mock.stop()
Configuration
| Option | Description | Default |
|---|---|---|
port | Port to listen on. 0 = OS-assigned ephemeral. | 4004 |
nexusStates | Array of 2-letter state codes the tenant has nexus in. | all 10 |
Env var TAXJAR_MOCK_PORT overrides the default when using pnpm taxjar-mock.
Default port
4004. Configurable via TAXJAR_MOCK_PORT env var or the port option
passed to startTaxJarMockServer(). Integration specs always pass port: 0
to get a random ephemeral port, avoiding conflicts in parallel test runs.