AgentSkillsCN

testing

在编辑 test_*、*.test.*,或 *_test.py 文件,或使用 pytest/jest 框架时加载。提供适用于 Python 与 TypeScript 项目的测试模式。

SKILL.md
--- frontmatter
name: testing
description: Load when editing test_*, *.test.*, or *_test.py files, or working with pytest/jest frameworks. Provides testing patterns for Python and TypeScript projects.

Testing

Merged Skills

  • pytest: Python testing with async support
  • jest: TypeScript/React component testing
  • e2e: End-to-end integration testing

⚠️ Critical Gotchas

CategoryPatternSolution
Async fixturesFixture not asyncUse @pytest.fixture with async def
Over-mockingEverything mockedOnly mock at service boundaries
Flaky testsRandom failuresAdd pytest.mark.flaky or fix race condition
E2E timingTests fail intermittentlyUse explicit waits, not sleep()
Shared stateTests affect each otherFresh setup each test, isolate state
Wrong levelUnit test for integrationMatch test type to what you're testing

Rules

RulePattern
Test behaviorTest what it does, not how
Isolate testsNo shared state between tests
Fast firstRun API/UI tests before E2E
Meaningful namesDescribe expected behavior in test name
E2E confirmsOnly run E2E after API+UI pass
Mock boundariesMock external services, not internal logic

Avoid

❌ Bad✅ Good
Testing implementationTesting behavior
Shared stateFresh setup each test
Mock everythingMock boundaries only
E2E for unit logicE2E for user flows
time.sleep() in E2EExplicit waits
Generic test namestest_create_script_returns_201

Testing Hierarchy

LevelTargetWhenCommand
1. APIBackend endpointsAfter API changespytest backend/tests/api/
2. UIComponents, pagesAfter frontend changesnpm test
3. E2EFull flowFinal confirmationpytest backend/tests/e2e/ -m e2e

Patterns

python
# Pattern 1: API test with async client
class TestScriptAPI:
    async def test_create_script_returns_201(self, client):
        response = await client.post("/api/scripts/", json={"name": "test"})
        assert response.status_code == 201
        assert response.json()["id"] is not None

    async def test_list_scripts_returns_all(self, client, sample_scripts):
        response = await client.get("/api/scripts/")
        assert len(response.json()) == len(sample_scripts)

# Pattern 2: Async fixture
@pytest.fixture
async def sample_scripts(db_session):
    scripts = [Script(name=f"script_{i}") for i in range(3)]
    db_session.add_all(scripts)
    await db_session.commit()
    return scripts
tsx
// Pattern 3: React component test
it('renders script list correctly', () => {
  render(<ScriptList scripts={mockScripts} />);
  expect(screen.getAllByTestId('script-item')).toHaveLength(3);
});

it('calls onRun when run button clicked', () => {
  const onRun = jest.fn();
  render(<ScriptCard script={mockScript} onRun={onRun} />);
  fireEvent.click(screen.getByRole('button', { name: /run/i }));
  expect(onRun).toHaveBeenCalledWith(mockScript.id);
});
python
# Pattern 4: E2E test with full flow
@pytest.mark.e2e
class TestScriptWorkflow:
    """Final confirmation: full user flow"""
    
    async def test_create_run_delete_script(self, e2e_client):
        # Create
        create_resp = await e2e_client.post("/api/scripts/", json={"name": "E2E Test"})
        script_id = create_resp.json()["id"]
        
        # Run
        run_resp = await e2e_client.post(f"/api/scripts/{script_id}/run")
        assert run_resp.json()["status"] == "completed"
        
        # Delete
        delete_resp = await e2e_client.delete(f"/api/scripts/{script_id}")
        assert delete_resp.status_code == 204

Commands

TaskCommand
API testscd backend && pytest tests/api/ -v
UI testscd frontend && npm test
E2E testscd backend && pytest tests/e2e/ -v -m e2e
All testspytest && npm test && pytest -m e2e
Single filepytest tests/test_specific.py -v
With coveragepytest --cov=app tests/