| name | clade-ci-integration |
| description | Test and validate Claude integrations in CI/CD pipelines —
Use when working with ci-integration patterns.
GitHub Actions, mocking strategies, and cost control.
Trigger with "anthropic ci", "test claude in ci", "anthropic github actions",
"claude automated testing".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| compatible-with | claude-code |
| tags | ["saas","anthropic","claude","ci","testing"] |
Anthropic CI Integration
Overview
Testing Claude integrations in CI requires handling API keys securely, mocking for unit tests, and making real calls only in integration tests.
GitHub Actions Setup
name: Test Claude Integration
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run test:unit
- run: npm run test:integration
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
Mock Strategy for Unit Tests
import { vi } from 'vitest';
export function mockAnthropicClient() {
return {
messages: {
create: vi.fn().mockResolvedValue({
id: 'msg_mock',
type: 'message',
role: 'assistant',
model: 'claude-sonnet-4-20250514',
content: [{ type: 'text', text: 'Mock response' }],
stop_reason: 'end_turn',
usage: { input_tokens: 10, output_tokens: 5 },
}),
stream: vi.fn().mockReturnValue({
async *[Symbol.asyncIterator]() {
yield { type: 'content_block_delta', delta: { type: 'text_delta', text: 'Mock' } };
},
finalMessage: vi.fn().mockResolvedValue({ usage: { input_tokens: , : } }),
}),
},
};
}
{ mockAnthropicClient } ;
(, () => {
client = ();
result = (client, );
(result).();
(client..).(
expect.({ : })
);
});
Integration Test (Real API)
import Anthropic from '@claude-ai/sdk';
import { describe, test, expect } from 'vitest';
describe('Claude API Integration', () => {
const client = new Anthropic();
test('messages.create returns valid response', async () => {
const message = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 50,
messages: [{ role: 'user', content: 'Say "test passed" in 2 words.' }],
});
expect(message.content[0].type).toBe('text');
expect(message.stop_reason).toBe('end_turn');
expect(message.usage.output_tokens).toBeGreaterThan(0);
}, 30_000);
});
Cost Control in CI
| Strategy | How |
|---|
| Use Haiku only | Cheapest model, fast |
| Limit max_tokens | max_tokens: 50 for validation tests |
| Skip on PRs from forks | Don't expose API key to untrusted code |
| Run integration tests only on main | if: github.ref == 'refs/heads/main' |
| Budget cap | Set spending limits in Anthropic console |
Output
- GitHub Actions workflow running unit tests (mocked, no API key needed)
- Integration tests making real Claude API calls on main branch
- Mock client returning realistic response shapes for unit tests
- CI costs controlled via Haiku model and tight max_tokens
Error Handling
| Error | Cause | Solution |
|---|
| API Error | Check error type and status code | See clade-common-errors |
Examples
See GitHub Actions YAML, Mock Strategy with Vitest, Integration Test with real API, and Cost Control table above.
Resources
Next Steps
See clade-deploy-integration for deploying to production.
Prerequisites
- GitHub repository with Actions enabled
ANTHROPIC_API_KEY stored as GitHub Actions secret
- Test framework installed (Vitest, Jest, or pytest)
Instructions
Step 1: Review the patterns below
Each section contains production-ready code examples. Copy and adapt them to your use case.
Step 2: Apply to your codebase
Integrate the patterns that match your requirements. Test each change individually.
Step 3: Verify
Run your test suite to confirm the integration works correctly.