mirror of
https://github.com/zadam/trilium.git
synced 2026-09-12 19:50:20 +05:00
docs(claude): record the core API tester's header-seeded context
CoreApiTester now seeds the execution context from the trilium-* request headers, so Pattern 0 documents how to drive a hoisted request and warns that a spec omitting trilium-hoisted-note-id exercises the unhoisted path. Anything reading hoistedNoteService.getHoistedNoteId() — quick search, autocomplete, SearchContext's implicit ancestorNoteId — sees "root" without it, so a passing spec is not evidence that scoping works. A contributor's quick-search PR asserted exactly that and proved nothing. The Windows note covered only `pnpm --filter … exec vitest`; the auto-install fires for a package's own test script too. It now names the symptom seen here: EPERM / Access is denied on a node_modules directory VS Code holds open, which rolls back cleanly but loses the run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cd381e09fe
commit
d595fb33e8
@ -53,7 +53,7 @@ Some layers have a purpose-built spec harness documented in the skill that owns
|
||||
- Coverage: append `--coverage`.
|
||||
- Server tests run **sequentially** (shared DB, `pool: "forks"`, fork isolation is **per file**). Client/package tests run in parallel.
|
||||
|
||||
> **Windows/sandbox note:** `pnpm --filter … exec vitest` can trigger a pnpm auto-install that hits `EPERM`. If so, run the hoisted binary directly (it lives in the **repo-root** `node_modules`): `CI=true node node_modules/vitest/vitest.mjs run <spec> --root apps/client`, or `node_modules/.bin/vitest.CMD run <spec> --root apps/<app>`.
|
||||
> **Windows/sandbox note:** any `pnpm --filter …` invocation — `exec vitest` and the package's own `test` script alike — can trigger a pnpm auto-install that hits `EPERM`/`Access is denied` on a `node_modules` directory VS Code holds open (it rolls back, but the run is lost). If so, run the hoisted binary directly (it lives in the **repo-root** `node_modules`): `CI=true node node_modules/vitest/vitest.mjs run <spec> --root apps/client`, or `node_modules/.bin/vitest.CMD run <spec> --root apps/<app>`.
|
||||
|
||||
## Coverage config rules (Vitest 4)
|
||||
|
||||
|
||||
@ -37,6 +37,11 @@ describe("X API (core)", () => {
|
||||
- `api.<verb>(path, { body, query, headers, file })`. `createTextNote(api, {...})` → `{ noteId, branchId }`. Assert real state via `getSql()` / `becca`.
|
||||
- Mutations are auto-wrapped in cls + a SQL transaction — **no `cls.init` needed** (unlike Pattern 3 direct service calls).
|
||||
- Header-reading handlers (e.g. sync) work: pass `headers` and the handler's `req.get(name)` reads them case-insensitively.
|
||||
- **`trilium-*` headers seed the execution context**, exactly as `route_api.ts` (Express) and `browser_routes.ts` (standalone) do: `trilium-hoisted-note-id` → `cls.getHoistedNoteId()` (defaults to `"root"`), plus `trilium-component-id` and `trilium-local-now-datetime`. This is the **only** way to test a hoist-dependent route — anything reading `hoistedNoteService.getHoistedNoteId()` (quick search, autocomplete, `SearchContext`'s implicit `ancestorNoteId`) sees `"root"` unless you pass the header:
|
||||
```ts
|
||||
api.get(`/api/quick-search/${token}`, { headers: { "trilium-hoisted-note-id": workspaceId } });
|
||||
```
|
||||
A spec that omits it is asserting the *unhoisted* path, so don't read a pass as proof that scoping works.
|
||||
|
||||
### It runs REAL services end to end — including streaming + multipart. Don't mock them.
|
||||
Both test setups (`apps/server/spec/setup.ts`, `apps/standalone/src/test_setup.ts`) inject the **real platform providers** (zip = archiver/fflate, image = sharp/magic-bytes, backup = fs/OPFS), and **both vitest suites run on Node** (the standalone setup itself imports `node:fs`/`node:module`) — so `Buffer`, `node:stream`, `node:fs` are available in either runtime. The tester's mock `res` is a real Node `Writable` that also implements the Express surface (`set`/`setHeader`/`removeHeader`/`status`/`send`/`sendStatus`/`write`/`end`), so the **server** export path (`archiver.pipe(res)`, needs a real writable) and the **browser** path (`BrowserZipArchive.finalize()` → `res.send(bytes)`) both run. Match the ETAPI **zero-mock** convention: drive real inputs and assert real output.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user