بنقرة واحدة
add-test
// Use when adding unit or integration tests. Provides test patterns, naming conventions, and fixtures for Python (pytest), TypeScript (vitest), Java (JUnit/Mockito), and Rust.
// Use when adding unit or integration tests. Provides test patterns, naming conventions, and fixtures for Python (pytest), TypeScript (vitest), Java (JUnit/Mockito), and Rust.
Use when adding a new method, function, or API endpoint to the SDK. Ensures consistent implementation across all SDKs (Python, TypeScript, Java, Rust CLI) with proper types, tests, and naming conventions.
Use when CI/CD pipeline fails. Provides systematic diagnosis for lint, type, test, and build failures across Python, TypeScript, Java, Rust, and n8n SDKs.
Load ONLY for Python code Use when writing, reviewing, or refactoring Python to ensure adherence to LBYL exception handling patterns, modern type syntax (list[str], str | None), pathlib operations, ABC-based interfaces, absolute imports, and explicit error boundaries at CLI level. Also provides production-tested code smell patterns from Dagster Labs for API design, parameter complexity, and code organization. Essential for maintaining erk's dignified Python standards.
Use when running integration tests against a real Metadata instance. Guides setup of environment variables (AI_SDK_HOST, AI_SDK_TOKEN) and runs tests that make actual API calls.
Use when reviewing or validating documentation. Checks for clarity, completeness, broken links, undefined terms, and ensures beginners can follow guides without prior knowledge of the SDK.
| name | add-test |
| description | Use when adding unit or integration tests. Provides test patterns, naming conventions, and fixtures for Python (pytest), TypeScript (vitest), Java (JUnit/Mockito), and Rust. |
Add unit or integration tests for existing functionality.
/add-test <sdk> <component> [--integration]
python/tests/)Unit Test:
import pytest
from unittest.mock import AsyncMock, patch
from ai_sdk import AISdk
@pytest.fixture
def client():
return AISdk(host="https://test.example.com", token="test-token")
@pytest.mark.asyncio
async def test_method_name(client):
"""Test description."""
with patch.object(client._http, 'request', new_callable=AsyncMock) as mock:
mock.return_value = {"expected": "response"}
result = await client.agent("test").method_name("param")
assert result.expected == "response"
mock.assert_called_once_with("POST", "/expected/path", json={"param": "param"})
Integration Test: (python/tests/integration/)
import pytest
import os
@pytest.fixture
def live_client():
host = os.environ.get("AI_SDK_HOST")
token = os.environ.get("AI_SDK_TOKEN")
if not host or not token:
pytest.skip("Integration test credentials not configured")
return AISdk(host=host, token=token)
@pytest.mark.asyncio
async def test_real_api_call(live_client):
"""Integration test against real API."""
result = await live_client.agent("test-agent").invoke("hello")
assert result.response is not None
typescript/tests/)Unit Test:
import { describe, it, expect, vi } from 'vitest';
import { AISdk } from '../src';
describe('MethodName', () => {
it('should do expected behavior', async () => {
const client = new AISdk({ host: 'https://test.example.com', token: 'test' });
// Mock fetch
global.fetch = vi.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ expected: 'response' }),
});
const result = await client.agent('test').methodName('param');
expect(result.expected).toBe('response');
expect(fetch).toHaveBeenCalledWith(
'https://test.example.com/expected/path',
expect.objectContaining({ method: 'POST' })
);
});
});
java/src/test/java/io/metadata/ai/)Unit Test:
package io.metadata.ai;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class MethodNameTest {
private AISdk client;
private AISdkHttpClient mockHttp;
@BeforeEach
void setUp() {
mockHttp = mock(AISdkHttpClient.class);
client = new AISdk.Builder()
.host("https://test.example.com")
.token("test-token")
.httpClient(mockHttp)
.build();
}
@Test
void testMethodName() throws Exception {
when(mockHttp.post(anyString(), any())).thenReturn(new ResponseModel("expected"));
ResponseModel result = client.agent("test").methodName("param");
assertEquals("expected", result.getValue());
verify(mockHttp).post("/expected/path", any());
}
}
cli/src/ or cli/tests/)Unit Test:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_method_name() {
let result = method_name("input");
assert_eq!(result, expected_output);
}
#[tokio::test]
async fn test_async_method() {
let client = TestClient::new();
let result = client.method_name("param").await.unwrap();
assert_eq!(result.field, "expected");
}
}
| SDK | Convention | Example |
|---|---|---|
| Python | test_<method>_<scenario> | test_invoke_returns_response |
| TypeScript | should <behavior> | should return response on success |
| Java | test<Method><Scenario> | testInvokeReturnsResponse |
| Rust | test_<method>_<scenario> | test_invoke_returns_response |
# All unit tests
make test-all
# Specific SDK
cd python && pytest tests/ -v
cd typescript && npm test
cd java && mvn test
cd cli && cargo test
# With coverage
cd python && pytest --cov=src/ai_sdk tests/
cd typescript && npm test -- --coverage
cd java && mvn test jacoco:report