Skip to content

Commit 2c2fa2f

Browse files
authored
Merge pull request #32 from redwyre/dev
Update spec test
2 parents 9d84e88 + ec7eb20 commit 2c2fa2f

14 files changed

Lines changed: 4754 additions & 3715 deletions

File tree

.github/workflows/test.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,38 @@ name: Test specification
22
on:
33
workflow_dispatch:
44
schedule:
5-
- cron: '0 0 * * *'
5+
- cron: "0 0 * * *"
66
jobs:
77
generic:
88
runs-on: ubuntu-latest
99
steps:
1010
- name: Checkout
11-
uses: actions/checkout@v4
11+
uses: actions/checkout@v6
1212

13-
- uses: pnpm/action-setup@v4
13+
- uses: pnpm/action-setup@v6
1414
name: Install pnpm
1515
with:
16-
version: 8
16+
version: 11
1717
run_install: false
1818

1919
- name: Install Node.js
20-
uses: actions/setup-node@v4
20+
uses: actions/setup-node@v6
2121
with:
22-
node-version: 20
23-
cache: 'pnpm'
22+
node-version: 24
23+
cache: "pnpm"
2424

2525
- name: Install dependencies
2626
run: |
27-
pnpm install
27+
pnpm ci
2828
sudo apt-get install -y jq
2929
3030
- name: Test
3131
run: |
3232
curl -L -o openapi.yaml "$(curl -s https://api.github.com/repos/vrchatapi/specification/releases \
3333
| jq -r '.[] | select(.prerelease) | .assets[] | select(.name=="openapi-internal+legacy.yaml").browser_download_url' \
3434
| head -n 1)"
35-
36-
35+
36+
3737
rm data/state -rf
3838
3939
./node_modules/.bin/ava reset-cache

.vscode/launch.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Run tests via PNPM",
9+
"type": "node",
10+
"request": "launch",
11+
"runtimeExecutable": "pnpm",
12+
"runtimeArgs": [
13+
"run",
14+
"test"
15+
],
16+
"skipFiles": [
17+
"<node_internals>/**"
18+
],
19+
"console": "integratedTerminal",
20+
"internalConsoleOptions": "neverOpen",
21+
},
22+
{
23+
"name": "Run fast-fail tests via PNPM",
24+
"type": "node",
25+
"request": "launch",
26+
"runtimeExecutable": "pnpm",
27+
"runtimeArgs": [
28+
"run",
29+
"fast-fail"
30+
],
31+
"skipFiles": [
32+
"<node_internals>/**",
33+
"${workspaceFolder}/node_modules/**",
34+
"**/dist/pnpm.mjs"
35+
],
36+
"console": "integratedTerminal",
37+
"internalConsoleOptions": "neverOpen",
38+
}
39+
]
40+
}

AGENTS.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Agent instructions for this project
2+
3+
## Package manager
4+
- Use `pnpm` for all package management
5+
6+
## Setup and Commands
7+
8+
### Initial Setup Checklist
9+
1. Create a `.env` file in the project root (loaded via `dotenv/config`)
10+
2. Verify all required environment variables are set and non-empty:
11+
- `VRCHAT_EMAIL`
12+
- `VRCHAT_USERNAME`
13+
- `VRCHAT_PASSWORD`
14+
- `VRCHAT_TOTP_SECRET`
15+
- `VRCHAT_FRIEND_ID`
16+
- `VRCHAT_GROUP_ID`
17+
- **If any variable is missing, empty, or malformed, stop immediately and print the exact variable names that must be set before any test run.**
18+
3. Before every local test run, execute `pnpm test:clean` first. Do not reuse any existing `data/state/` or AVA cache from a previous run. (CI does this automatically.)
19+
4. Execute `pnpm get-spec` to download the latest `openapi-internal+legacy.yaml` to `openapi.yaml` (CI does this automatically).
20+
21+
### Available Commands
22+
- `pnpm test` — run all tests (AVA; serial mode configured in `ava.config.js`)
23+
- `pnpm fast-fail` — stop on first failure
24+
- `pnpm type-check` — TypeScript type check
25+
- `pnpm test:clean` — clear `data/state` and AVA cache (`pwsh ./scripts/clean.ps1`)
26+
- `pnpm get-spec` — download latest `openapi-internal+legacy.yaml` to `openapi.yaml`
27+
28+
## Project purpose
29+
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.
30+
31+
## Test structure
32+
- Test files in `tests/*.ts`, run in the order defined by `tests/_order.json`: authentication → users → worlds → instances → avatars (then alphabetical)
33+
- All tests are serial (`ava --serial`)
34+
- Tests share state via `data/state/` (files on disk — cookies, session data, cached values)
35+
- Test results recorded as markdown to `data/requests/`
36+
37+
## Running tests
38+
39+
### Authentication and Error Handling
40+
- Auth flow: login with Basic auth → 2FA TOTP → verify → cookie-based reuse
41+
- Rate-limit protection: 200ms between requests, exponential backoff up to 10 retries on 429
42+
- **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.**
43+
44+
## Test patterns
45+
- `testOperation` macro (from `_utilities.ts`) handles: parameter injection, schema validation (`@exodus/schemasafe` lax mode), response logging
46+
- `unstable: true | string[]` — marks response values that change every run (timestamps, versions, etc.)
47+
- `sensitive: true` — redacts the entire response body
48+
- `test.todo(...)` — placeholder for unimplemented endpoints
49+
- Use `test.before(failUnauthenticated)` in files that need a logged-in user
50+
51+
## Key files
52+
- `tests/_utilities.ts` — core test framework (fetch, schema validation, request/response recorder)
53+
- `tests/_consts.ts` — env vars, shared constants like `tupperUserId`, `defaultAvatarId`
54+
- `tests/_cache.ts` — file-based state and caching, sensitive/unstable value tracking
55+
- `tests/_users.ts` — shared unstable key lists (e.g. `unstableUserKeys`)
56+
- `ava.config.js` — AVA config with serial mode, custom test ordering via `_order.json`, tsx loader
57+
- `scripts/clean.ps1` — clears `data/state/` and AVA cache for a fresh run (`pnpm test:clean`)
58+
- `scripts/get-spec.ps1` — downloads latest `openapi-internal+legacy.yaml` to `openapi.yaml`
59+
- `openapi.yaml` (in `.gitignore`) — downloaded at test time by CI or `scripts/get-spec.ps1`
60+
- `data/` — ignored except for `data/requests/` (test output committed by CI)
61+
62+
## CI
63+
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.

ava.config.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@ testOrder = Object.fromEntries(
1010
);
1111

1212
export default {
13-
cache: false,
13+
cache: true,
14+
serial: true,
1415
concurrency: 0,
15-
extensions: {
16-
ts: "module"
17-
},
16+
extensions: ["js", "ts"],
1817
files: ["tests/**/*"],
19-
nodeArguments: ["--import=tsimp"],
20-
// sortTestFiles: (file1, file2) => testData[file1].order - testData[file2].order,
18+
nodeArguments: ["--import=tsx", "--trace-deprecation"],
2119
sortTestFiles: (a, b) => {
2220
a = path.relative(import.meta.dirname, a);
2321
const aOrder = testOrder[a] || Infinity;

package.json

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,43 @@
55
"type": "module",
66
"main": "index.js",
77
"scripts": {
8-
"test": "ava --serial"
8+
"test": "ava",
9+
"fast-fail": "ava --fail-fast",
10+
"type-check": "tsc --noEmit",
11+
"test:clean": "pwsh ./scripts/clean.ps1",
12+
"get-spec": "pwsh ./scripts/get-spec.ps1"
913
},
1014
"keywords": [],
1115
"author": "",
1216
"license": "ISC",
13-
"dependencies": {
14-
"@apidevtools/json-schema-ref-parser": "^11.6.4",
17+
"devDependencies": {
18+
"@apidevtools/json-schema-ref-parser": "^15.3.5",
19+
"@ariesclark/eslint-config": "^3.1.1",
1520
"@exodus/schemasafe": "^1.3.0",
16-
"ava": "^6.1.3",
21+
"@types/ms": "^2.1.0",
22+
"@types/node": "^25.9.1",
23+
"@types/object-path": "^0.11.4",
24+
"@types/totp-generator": "^0.0.8",
25+
"@types/tough-cookie": "^4.0.5",
26+
"ava": "^8.0.1",
1727
"change-case": "^5.4.4",
18-
"dotenv": "^16.4.5",
19-
"fetch-cookie": "^3.0.1",
28+
"dotenv": "^17.4.2",
29+
"eslint": "^10.4.1",
30+
"eslint-plugin-ava": "^17.0.0",
31+
"fetch-cookie": "^3.2.0",
2032
"jsonpointer": "^5.0.1",
2133
"ms": "^2.1.3",
2234
"object-path": "^0.11.8",
23-
"totp-generator": "^1.0.0",
24-
"tough-cookie": "^4.1.4",
25-
"vrchat": "^1.18.5",
26-
"yaml": "^2.4.5"
27-
},
28-
"devDependencies": {
29-
"@ariesclark/eslint-config": "^2.0.1",
30-
"@types/ms": "^0.7.34",
31-
"@types/object-path": "^0.11.4",
32-
"@types/totp-generator": "^0.0.8",
33-
"@types/tough-cookie": "^4.0.5",
34-
"eslint": "^9.7.0",
35-
"eslint-plugin-ava": "^15.0.1",
3635
"openapi-types": "^12.1.3",
36+
"totp-generator": "^2.0.1",
37+
"tough-cookie": "^6.0.1",
3738
"ts-node": "^10.9.2",
38-
"tsimp": "^2.0.11",
39-
"typescript": "^5.5.3"
39+
"tsx": "^4.22.4",
40+
"typescript": "^6.0.3",
41+
"vrchat": "^2.21.7",
42+
"yaml": "^2.9.0"
43+
},
44+
"engines": {
45+
"node": "24"
4046
}
4147
}

0 commit comments

Comments
 (0)