From 5289062414f724320e38b8f6d26666d5b5cddcbc Mon Sep 17 00:00:00 2001 From: Yunfei He Date: Fri, 29 May 2026 14:10:59 +0800 Subject: [PATCH] docs(agents): update for concurrent-by-default main suite The main suite is now concurrent too, so correct the earlier "not concurrent" note. Record the convention: snapshot tests stay concurrent via context-local expect; process-global-state tests (fake timers, listener/node counts) move to *.sequential.test.* files marked it.sequential / describe.sequential. --- AGENTS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 0192f31..bb384be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,10 +7,10 @@ - Bug fixes must follow test-first: write a failing test that reproduces the bug, then fix the code and verify the test passes. - Tests must simulate real user conditions. Non-TTY environments disable chalk colors — use `FORCE_COLOR` env var so ANSI output is always exercised. A bug invisible in tests but visible in a real terminal is a testing gap, not a minor issue. - When debugging color/ANSI output in non-TTY environments (e.g. Claude Code shell), use `FORCE_COLOR=3` env var to force chalk to output ANSI codes. -- The **PTY suite** (`vitest.pty.config.ts`) runs tests **concurrently** (`sequence.concurrent: true`). Each test spawns its own isolated subprocess/app, so they don't share state. Never assert on wall-clock-dependent behavior there (e.g. exact render/commit counts that rely on the renderer's ~32ms throttle): trigger the event so it renders synchronously and assert immediately after, or it flakes under CPU contention. `it.sequential` does NOT fix cross-fork CPU contention — fix the timing dependency instead. -- Two test patterns are **incompatible with concurrent execution** and must run sequentially (this is why the main `vite.config.ts` suite is **not** concurrent): - - **Inline/file snapshots** (`toMatchInlineSnapshot`): the module-level `expect` loses snapshot test context under concurrency. _Fixable_ — destructure the context-local `expect`: `test.concurrent("name", async ({ expect }) => { expect(x).toMatchInlineSnapshot() })`. - - **Fake timers** (`vi.useFakeTimers` / `advanceTimersByTime`): these mutate the **process-global** timer functions, so a concurrent test calling `useRealTimers()` yanks the mocked API out from under another mid-`advanceTimersByTime` ("timers not mocked"). _Not fixable_ with context — these tests must stay sequential. +- **Tests run concurrently by default** (`sequence.concurrent: true` in both the main `vite.config.ts` and `vitest.pty.config.ts`). Write each test self-contained — own subprocess/app, no shared mutable state. Never assert on wall-clock-dependent behavior (e.g. exact render/commit counts that rely on the renderer's ~32ms throttle): trigger the event so it renders synchronously and assert immediately after, or it flakes under CPU contention. `it.sequential` does NOT fix cross-fork CPU contention — fix the timing dependency instead. +- A few patterns are **incompatible with concurrent execution**. Handle by cause: + - **Inline/file snapshots** (`toMatchInlineSnapshot`): the module-level `expect` loses snapshot test context under concurrency. _Fix in place_ — use the context-local `expect`: `test("name", async ({ expect }) => { expect(x).toMatchInlineSnapshot() })`. These stay concurrent. + - **Process-global state** — fake timers (`vi.useFakeTimers`, which mutates global `setTimeout`/`performance`), or assertions on shared globals (e.g. `process.listenerCount`, live yoga-node counts). A concurrent sibling clobbers the shared state mid-test. _Not fixable_ in place — put these in a `*.sequential.test.*` file and mark them `it.sequential` / `describe.sequential`, with a header comment saying which global forces it. - After completing any task, run `vp run ready` (or `vpr ready`) to verify: lint, type-check, test all packages, and build. - Never commit anything under `docs/`. That directory is for local working notes and specs — it must stay out of git.