TEST REPORT: API Integrator for QuickBooks Online v1.0.0
Run from a clean unzipped copy of the dist zip (fresh npm install / pip install). Started 2026-10-17 06:15:02 BST (UTC+01:00), finished 2026-10-17 06:15:04 BST (UTC+01:00) (times from date at run time). Box: Linux, Node v24.22.0, Python 3.13.5.
Result: 19/19 passed. The TypeScript typecheck is clean.
Method: all Intuit HTTP is mocked through an injected fetch. It has not been run against a real QuickBooks sandbox company.
npm test
✔ authorize URL has required params and random state (1.09905ms)
✔ code exchange: Basic auth, form body, realmId captured, expiries computed (14.872662ms)
✔ state mismatch rejected before any network call (0.482511ms)
✔ invalid_grant on refresh => needsReconnect (0.566316ms)
✔ token manager refreshes near expiry and persists the ROTATED refresh token (0.56133ms)
✔ token manager uses cached token when fresh (no network) (0.121646ms)
✔ concurrent callers share a single refresh (0.437338ms)
✔ createCustomer: sandbox URL, minorversion=75, requestid, bearer, body shape (1.619872ms)
✔ query escapes single quotes (0.602712ms)
✔ upsertCustomer: duplicate-name fault (6240) falls back to lookup (1.133973ms)
✔ QBO fault surfaces code, message and intuit_tid (0.562907ms)
✔ createInvoice body: SalesItemLineDetail lines, BillEmail, rounding (0.606028ms)
✔ retrying a create with the same requestId sends the same requestid (0.501266ms)
✔ 401 triggers one forced refresh then succeeds with the new token (0.661265ms)
✔ 429 backs off (Retry-After honoured) then succeeds (0.451514ms)
✔ persistent 5xx gives up after maxRetries (0.457414ms)
✔ sendInvoice uses octet-stream and sendTo (0.395691ms)
✔ hard expiry: opt-in header sent and x_refresh_token_hard_expires_in parsed on refresh (0.275112ms)
✔ hard expiry: absent field -> undefined; old SDK name x_refresh_token_lifetime_expires_in is NOT used (0.337836ms)
ℹ tests 19
ℹ pass 19
ℹ fail 0
typecheck: OK
Changes in this run
The hard-expiry field is now x_refresh_token_hard_expires_in. That is the name in Intuit's developer blog ("Track your refresh token's hard expiry") and oauth-jsclient PR #207; an earlier oauth-jsclient build used x_refresh_token_lifetime_expires_in. Two new tests check that the opt-in header is sent, that the field is parsed on refresh, that an absent field gives undefined, and that the old wrong name is ignored.
Written from (Intuit docs, Oct 2026)
- OAuth endpoints, Basic auth, realmId on the callback.
- 1-hour access tokens; refresh tokens with a 100-day rolling window that rotate; the 5-year hard cap.
- The minorversion 75 floor;
requestididempotency; octet-stream for /send.
Not tested
- A live sandbox company: the fixtures follow Intuit's documented shapes but were not captured from real traffic.
- The rate limit (about 500 requests/minute per realm) is quoted from the docs, not tested.
- The multi-instance refresh lock is described in SKILL.md but not implemented.
- Fault 5010 handling is not exercised by any test.
Agent dry-run
This was a self-review by the builder, not an independent agent run.