/testing-core-processors
How to write integration tests for error processors in `packages/core/src/processors/`.
$ npx -y skills add mastra-ai/mastra --skill testing-core-processors --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/testing-core-processors
Context preview
The summary Claude sees to decide when to auto-load this skill.
How to write integration tests for error processors in `packages/core/src/processors/`.
SKILL.md
testing-core-processors.SKILL.mdTesting Core Error Processors
How to write integration tests for error processors in `packages/core/src/processors/`.
Prerequisites
- Build core before running tests: `pnpm build:core` (from repo root)
- If focused vitest runs fail to resolve `@internal/test-utils/setup`, the build step was skipped
Mock Model Pattern
Use `MockLanguageModelV2` from `@internal/ai-sdk-v5/test` to simulate API errors and verify retry behavior.
import { APICallError } from '@internal/ai-sdk-v5';
import { convertArrayToReadableStream, MockLanguageModelV2 } from '@internal/ai-sdk-v5/test';
// Track calls and captured prompts
let callCount = 0;
const receivedPrompts: any[] = [];
const model = new MockLanguageModelV2({
doGenerate: async ({ prompt }) => {
callCount++;
receivedPrompts.push(JSON.parse(JSON.stringify(prompt)));
if (callCount === 1) {
throw new APICallError({
message: '...',
url: '...',
requestBodyValues: {},
statusCode: 400,
responseBody: '...',
isRetryable: false,
});
}
return {
rawCall: { rawPrompt: null, rawSettings: {} },
finishReason: 'stop',
usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },
content: [{ type: 'text', text: 'response' }],
warnings: [],
};
},
doStream: async ({ prompt }) => {
// Same error logic as doGenerate
// IMPORTANT: Stream response must include all event types:
return {
rawCall: { rawPrompt: null, rawSettings: {} },
warnings: [],
stream: convertArrayToReadableStream([
{ type: 'stream-start', warnings: [] },
{ type: 'response-metadata', id: 'id-0', modelId: 'mock-model', timestamp: new Date(0) },
{ type: 'text-start', id: 'text-1' },
{ type: 'text-delta', id: 'text-1', delta: 'response text' },
{ type: 'text-end', id: 'text-1' },
{ type: 'finish', finishReason: 'stop', usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 } },
]),
};
},
});Stream Mock Gotcha
The stream mock format requires `stream-start`, `response-metadata`, `text-start`, `text-delta`, `text-end`, and `finish` events. Using only `text-delta` + `finish` (the minimal format) will result in empty text output because the AI SDK expects the full event sequence. See `prefill-error-recovery.test.ts` for the reference pattern.
Test Structure
For each error processor, write at minimum:
1. **Happy path**: Processor catches the target error, modifies messages, retries successfully
- Assert: `agent.generate()` succeeds, mock called 2x, retry prompt has expected modifications
2. **Control test**: Same scenario without the processor — error propagates
- Assert: `agent.generate()` throws the expected error
3. **Selectivity test**: Processor ignores unrelated errors (e.g. rate limit 429)
- Assert: Error propagates, mock called only 1x
Passing Messages with Tool Calls
When seeding conversation history for tool-related tests, pass messages as the second argument to `agent.generate()` or `agent.stream()` using the AI SDK message format:
const messages = [
{ role: 'user', content: 'Do something' },
{ role: 'assistant', content: [{ type: 'tool-call', toolCallId: 'some-id', toolName: 'myTool', args: {} }] },
{ role: 'tool', content: [{ type: 'tool-result', toolCallId: 'some-id', toolName: 'myTool', result: 'done' }] },
];
await agent.generate(messages);Running Tests
# Run focused processor tests
npx vitest run packages/core/src/processors/my-processor.test.ts
# Run all processor tests
npx vitest run packages/core/src/processors/
# Full core test suite (slower)
pnpm test:core
Devin Secrets Needed
None for mock-based integration tests. For live API tests:
- `ANTHROPIC_API_KEY` — for testing against real Anthropic API
- `OPENROUTER_API_KEY` — for testing provider switching scenarios
Read more
Testing Core Error Processors
How to write integration tests for error processors in `packages/core/src/processors/`.
Prerequisites
- Build core before running tests: `pnpm build:core` (from repo root)
- If focused vitest runs fail to resolve `@internal/test-utils/setup`, the build step was skipped
Mock Model Pattern
Use `MockLanguageModelV2` from `@internal/ai-sdk-v5/test` to simulate API errors and verify retry behavior.
import { APICallError } from '@internal/ai-sdk-v5';
import { convertArrayToReadableStream, MockLanguageModelV2 } from '@internal/ai-sdk-v5/test';
// Track calls and captured prompts
let callCount = 0;
const receivedPrompts: any[] = [];
const model = new MockLanguageModelV2({
doGenerate: async ({ prompt }) => {
callCount++;
receivedPrompts.push(JSON.parse(JSON.stringify(prompt)));
if (callCount === 1) {
throw new APICallError({
message: '...',
url: '...',
requestBodyValues: {},
statusCode: 400,
responseBody: '...',
isRetryable: false,
});
}
return {
rawCall: { rawPrompt: null, rawSettings: {} },
finishReason: 'stop',
usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },
content: [{ type: 'text', text: 'response' }],
warnings: [],
};
},
doStream: async ({ prompt }) => {
// Same error logic as doGenerate
// IMPORTANT: Stream response must include all event types:
return {
rawCall: { rawPrompt: null, rawSettings: {} },
warnings: [],
stream: convertArrayToReadableStream([
{ type: 'stream-start', warnings: [] },
{ type: 'response-metadata', id: 'id-0', modelId: 'mock-model', timestamp: new Date(0) },
{ type: 'text-start', id: 'text-1' },
{ type: 'text-delta', id: 'text-1', delta: 'response text' },
{ type: 'text-end', id: 'text-1' },
{ type: 'finish', finishReason: 'stop', usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 } },
]),
};
},
});Stream Mock Gotcha
The stream mock format requires `stream-start`, `response-metadata`, `text-start`, `text-delta`, `text-end`, and `finish` events. Using only `text-delta` + `finish` (the minimal format) will result in empty text output because the AI SDK expects the full event sequence. See `prefill-error-recovery.test.ts` for the reference pattern.
Test Structure
For each error processor, write at minimum:
1. **Happy path**: Processor catches the target error, modifies messages, retries successfully
- Assert: `agent.generate()` succeeds, mock called 2x, retry prompt has expected modifications
2. **Control test**: Same scenario without the processor — error propagates
- Assert: `agent.generate()` throws the expected error
3. **Selectivity test**: Processor ignores unrelated errors (e.g. rate limit 429)
- Assert: Error propagates, mock called only 1x
Passing Messages with Tool Calls
When seeding conversation history for tool-related tests, pass messages as the second argument to `agent.generate()` or `agent.stream()` using the AI SDK message format:
const messages = [
{ role: 'user', content: 'Do something' },
{ role: 'assistant', content: [{ type: 'tool-call', toolCallId: 'some-id', toolName: 'myTool', args: {} }] },
{ role: 'tool', content: [{ type: 'tool-result', toolCallId: 'some-id', toolName: 'myTool', result: 'done' }] },
];
await agent.generate(messages);Running Tests
# Run focused processor tests npx vitest run packages/core/src/processors/my-processor.test.ts # Run all processor tests npx vitest run packages/core/src/processors/ # Full core test suite (slower) pnpm test:core
Devin Secrets Needed
None for mock-based integration tests. For live API tests:
- `ANTHROPIC_API_KEY` — for testing against real Anthropic API
- `OPENROUTER_API_KEY` — for testing provider switching scenarios
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack. It includes everything you need to go from early prototypes to production-ready applications.
Repo: mastra-ai/mastra
Other skills on mastra.
- /builder-smoke-test
Smoke test the Agent Builder feature branch end-to-end against a hermetic project scaffolded by the skill (linked to the current worktree). Covers workspace reconciliation, stored agents/skills CRUD, ownership, visibility, stars, registry/library Copy flow, picker allowlists,
Open skill - /debugging-difficult-bugs
Use early when debugging a medium or hard bug, especially when tests alone may not reveal the real runtime failure. Trigger this before extended TDD iteration when a bug involves runtime state, ordering, persistence, streaming, concurrency, UI/manual reproduction, external
Open skill - /docs-audit
Interactive documentation quality review for Mastra docs. Use when auditing, reviewing, or critiquing Mastra documentation; checking docs against source code; validating code examples, API accuracy, or property completeness; checking whether docs follow the styleguide and
Open skill - /e2e-tests-studio
REQUIRED when modifying any file in packages/playground-ui or packages/playground. Triggers on: React component creation/modification/refactoring, UI changes, new playground features, bug fixes affecting studio UI. Generates Playwright E2E tests that validate PRODUCT BEHAVIOR,
Open skill - /mastra-docs
Documentation guidelines for Mastra. This skill should be used when writing or editing documentation for Mastra. Triggers on tasks involving documentation creation or updates.
Open skill - /mastra-frontend
How to build Mastra frontend interfaces with the @mastra/playground-ui design system. This skill should be used when creating or modifying any application UI — pages, components, styling, or tokens — in this repo or in an external consumer of the design system. The docs site has
Open skill

