# Debug a Single Failing Test in TypeScript with Atlas (2026)

> Atlas debugs a failing TypeScript test by isolating it with pnpm vitest, following the types with the lsp tool, and fixing the module rather than weakening the assertion.

Atlas debugs a single failing TypeScript test by isolating it first: pnpm vitest run src/pricing/quote.test.ts with a -t filter through the bash tool, so the session sees one assertion diff instead of a thousand lines. Atlas then reads the spec and the module it exercises, follows the types and the call path with the lsp tool's goToDefinition and findReferences operations, and edits the implementation. In TypeScript the interesting question is usually where a type stopped being true, at an as cast, an any at an API boundary, or a path alias in tsconfig.json resolving to the wrong module.

## Key takeaways

- A TypeScript test can fail while tsc reports zero errors: the bug is where a type stopped being true, at an as cast, an any, or a drifted vi.mock.
- Isolate first with pnpm vitest run <file> -t "<name>" through the bash tool, which collapses a monorepo suite to one assertion diff.
- The lsp tool's goToDefinition operation resolves path aliases from tsconfig.json that a text search cannot follow.
- Never fix a TypeScript test by widening the type or casting the assertion; edit the implementation so the declared type is true again.
- apply_patch handles a multi-hunk TypeScript fix, such as tightening a return type and updating every caller, in one patch.
- Re-run the single test, then the full suite, run prettier on the changed .ts files, and delete every temporary log.

## Why is a TypeScript test failing when the code type checks?

A TypeScript test can fail while tsc reports 0 errors, because a type is a claim and a test is a measurement. Atlas hunts the place where the claim stopped being true, usually an as cast, an any at a fetch boundary, or a vi.mock whose shape drifted from the real module it replaces.

Type checking and testing answer different questions. Passing tsc means every expression is consistent with the annotations you wrote. Passing pnpm vitest means the values at runtime were what you expected. The gap between them is where TypeScript bugs live, and every one of them has a location: a response typed as QuoteResponse because someone wrote as QuoteResponse rather than parsing it, an any leaking out of a third-party client, a strictNullChecks setting relaxed for one file. Atlas is looking for that location, not for a way to make the assertion agree with the wrong value. The job is to find why one specific test fails and fix the code, not the assertion.

## How do you isolate one failing vitest test in a TypeScript project?

Atlas runs the single TypeScript test through the bash tool with vitest's filter flag, for example pnpm vitest run src/pricing/quote.test.ts -t "applies the volume tier". Filtering to 1 test collapses the output to the expected value, the received value, and a frame pointing into src/pricing/quote.ts.

Isolation is the cheapest debugging move available and it is routinely skipped. A full pnpm vitest run in a TypeScript monorepo emits thousands of lines and a summary; a filtered run emits an assertion diff you can hold in your head. Atlas reads the scripts block in package.json first so the command matches what the repo actually defines, and passes the path to the exact .test.ts file. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, so the pnpm command surfaces for approval before executing. Atlas tools this workflow uses are bash, read, lsp, edit, and apply_patch.

## How does Atlas follow types and call paths in TypeScript?

Atlas uses 2 lsp operations on a failing TypeScript test: goToDefinition lands on the real declaration behind a symbol, and findReferences lists every callsite. In a project with path aliases in tsconfig.json, goToDefinition resolves what a text search cannot, which module @/pricing actually points at.

TypeScript's indirection is type-shaped. A value passes through a generic, gets narrowed by a type guard, and arrives at the assertion having been widened by an interface declaration merged from two files. Reading source alone does not resolve that; the language server does. Atlas calls goToDefinition on the failing symbol to reach the actual declaration, then findReferences to see who else depends on that contract, which decides whether the fix belongs in the function or in its caller. Atlas indexes code by AST declarations using tree-sitter, not blind line windows, so the retrieved unit is a real interface, type alias, or function declaration.

## How do you confirm a hypothesis about a failing TypeScript test?

Atlas states a hypothesis about the TypeScript failure and then verifies it 2 ways: temporary logging added with the edit tool, or a re-run with a verbose flag through the bash tool. Because bash is a real shell, every lever you would pull by hand in your own terminal is available inside the session.

Hypotheses in a TypeScript codebase are concrete and checkable. The parsed JSON does not match the interface it was cast to. A vi.mock returns a partial object where the real module returns a full one, so a field is undefined at runtime while the type insists it exists. A discriminated union lost its discriminant across a serialization boundary. Atlas adds a temporary log inside src/pricing/quote.ts with edit, re-runs pnpm vitest run src/pricing/quote.test.ts -t "applies the volume tier" through bash, and reads the value that actually arrived. The type said one thing. The log says what happened.

## How does Atlas fix TypeScript code instead of weakening the assertion?

Atlas edits the TypeScript implementation, not the expectation. When the fix spans several hunks, for example tightening a return type in src/pricing/quote.ts and updating its 3 callers, Atlas uses apply_patch instead of chaining brittle edits, and computes a unified diff for every file edit and surfaces it for approval before writing.

The tempting non-fix in TypeScript is a cast. Adding as any to the assertion, or widening the interface until the wrong value is legal, turns a red test green and leaves the bug in production. Atlas goes the other way: if the runtime value does not match the declared type, either the value is wrong or the type is a lie, and both are fixed in the implementation. A multi-hunk change like removing an as cast and parsing the payload properly touches the module, its type declaration, and the callers that relied on the loose shape, which is exactly what apply_patch exists for. Run prettier over the changed .ts files afterwards.

## How do you verify a TypeScript test fix and clean up after it?

Atlas re-runs the single TypeScript test with the same pnpm vitest -t filter, then runs the full suite, then removes every temporary log it added. Removing the logging is step 5 of the documented workflow, and skipping it is how a console.log ends up shipped inside a typed API client.

Verification for a TypeScript fix is layered. The narrow vitest run proves the specific assertion now holds. The full suite proves the tightened type did not break a consumer that was relying on the loose one, which is common when the fix removes an any. Type checking still has to pass, since a fix that satisfies the test by loosening a signature has moved the bug rather than removed it. Atlas snapshots file changes as git patches so edits can be diffed and rolled back, and Atlas reads git branches, status, and diffs, so the final change set is reviewable before it becomes a commit.

## Steps

1. Run atlas in a project with a tsconfig.json and let Atlas read your type definitions, path aliases, and strictness settings.
2. Run just the failing test with the bash tool using vitest's filter flag, for example pnpm vitest run src/pricing/quote.test.ts -t "applies the volume tier", so the output is small enough to reason about.
3. Read the failing .test.ts file and the module it exercises, then use the lsp tool's goToDefinition and findReferences operations to walk the call path through generics, type guards, and the path aliases declared in tsconfig.json.
4. Look for the place a type stopped being true: an as cast, an any at a fetch boundary, or a vi.mock whose shape drifted from the real module.
5. Form a hypothesis and check it: add temporary logging with the edit tool, or re-run with a verbose flag through the bash tool, since bash is a real shell.
6. Fix the production TypeScript module with edit; if the change spans several hunks, such as tightening a return type and updating its callers, use apply_patch instead of chaining brittle edits.
7. Review the unified diff Atlas surfaces, then run prettier over the changed .ts files.
8. Re-run the single test with the same pnpm vitest command, then the full suite, and remove every temporary log you added.

## FAQ

### why does my typescript test fail even though tsc passes

Type checking proves your annotations are consistent; a test proves the runtime values were right. The gap is usually an as cast, an any leaking from a third-party client, or a vi.mock whose shape drifted from the real module. Atlas hunts that exact location instead of relaxing the assertion.

### how do I run one vitest test file in a typescript monorepo

Use pnpm vitest run src/pricing/quote.test.ts with the -t filter for the test name. Atlas runs it through its bash tool so the output collapses to the expected value, the received value, and the frame pointing into the module under test.

### how do I trace a typescript path alias to the real module

Use the lsp tool's goToDefinition operation, which Atlas calls directly. Path aliases declared in tsconfig.json cannot be followed by a text search, but the language server resolves them, so you land on the module @/pricing actually points at.

### should I add as any to make a failing typescript test pass

No. Casting the assertion turns the test green and leaves the bug in production. If the runtime value does not match the declared type, either the value is wrong or the type is a lie, and Atlas fixes the implementation rather than the expectation.

### can an AI agent debug a failing typescript test for me

Yes. Atlas runs the single test with bash, reads the spec and the module it exercises, walks the call path with the lsp tool's goToDefinition and findReferences operations, and fixes the code with edit or apply_patch. Every tool call is permission-gated against allow, ask, and deny rules.

### why is a mocked module returning undefined in my vitest test

A vi.mock that returns a partial object still satisfies the type at compile time while a field is undefined at runtime. Confirm it by adding a temporary log with Atlas's edit tool and re-running pnpm vitest with the -t filter, then align the mock with the real module's shape.

### does atlas read my tsconfig.json strictness settings

Yes. Run atlas in a project with a tsconfig.json and let Atlas read your type definitions, path aliases, and strictness settings. Those settings frequently explain why a value that looked safe at compile time was not safe at runtime.

### how do I fix a typescript bug that spans several files

Use apply_patch rather than chaining brittle edits. Tightening a return type in one module and updating its callers is a multi-hunk change, and Atlas applies it as one patch, then surfaces a unified diff for approval before writing.

---

Canonical HTML: https://runatlas.sh/resources/stacks/debug-a-failing-test-in-typescript
Source of truth: aeo_pages row `/resources/stacks/debug-a-failing-test-in-typescript` (segment: Stacks) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
