- Use
pnpmfor all package management
- Create a
.envfile in the project root (loaded viadotenv/config) - Verify all required environment variables are set and non-empty:
VRCHAT_EMAILVRCHAT_USERNAMEVRCHAT_PASSWORDVRCHAT_TOTP_SECRETVRCHAT_FRIEND_IDVRCHAT_GROUP_ID- If any variable is missing, empty, or malformed, stop immediately and print the exact variable names that must be set before any test run.
- Before every local test run, execute
pnpm test:cleanfirst. Do not reuse any existingdata/state/or AVA cache from a previous run. (CI does this automatically.) - Execute
pnpm get-specto download the latestopenapi-internal+legacy.yamltoopenapi.yaml(CI does this automatically).
pnpm test— run all tests (AVA; serial mode configured inava.config.js)pnpm fast-fail— stop on first failurepnpm type-check— TypeScript type checkpnpm test:clean— cleardata/stateand AVA cache (pwsh ./scripts/clean.ps1)pnpm get-spec— download latestopenapi-internal+legacy.yamltoopenapi.yaml
Integration-test suite against the live VRChat API. Downloads the latest openapi-internal+legacy.yaml from vrchatapi/specification releases, then validates actual API responses against the schema.
- Test files in
tests/*.ts, run in the order defined bytests/_order.json: authentication → users → worlds → instances → avatars (then alphabetical) - All tests are serial (
ava --serial) - Tests share state via
data/state/(files on disk — cookies, session data, cached values) - Test results recorded as markdown to
data/requests/
- Auth flow: login with Basic auth → 2FA TOTP → verify → cookie-based reuse
- Rate-limit protection: 200ms between requests, exponential backoff up to 10 retries on 429
- If login fails, TOTP verification fails, or cookie-based reuse cannot be established, abort the run immediately with a clear error message and do not continue with partial state.
testOperationmacro (from_utilities.ts) handles: parameter injection, schema validation (@exodus/schemasafelax mode), response loggingunstable: true | string[]— marks response values that change every run (timestamps, versions, etc.)sensitive: true— redacts the entire response bodytest.todo(...)— placeholder for unimplemented endpoints- Use
test.before(failUnauthenticated)in files that need a logged-in user
tests/_utilities.ts— core test framework (fetch, schema validation, request/response recorder)tests/_consts.ts— env vars, shared constants liketupperUserId,defaultAvatarIdtests/_cache.ts— file-based state and caching, sensitive/unstable value trackingtests/_users.ts— shared unstable key lists (e.g.unstableUserKeys)ava.config.js— AVA config with serial mode, custom test ordering via_order.json, tsx loaderscripts/clean.ps1— clearsdata/state/and AVA cache for a fresh run (pnpm test:clean)scripts/get-spec.ps1— downloads latestopenapi-internal+legacy.yamltoopenapi.yamlopenapi.yaml(in.gitignore) — downloaded at test time by CI orscripts/get-spec.ps1data/— ignored except fordata/requests/(test output committed by CI)
GitHub Actions runs daily (or manual dispatch). Downloads spec via curl+jq, clears data/state/, runs ava --serial, commits updated data/requests/ back to repo.