Agent Skillsstacklok/toolhive-studio › testing-api-assertions

testing-api-assertions

GitHub

用于前端测试中验证 API 请求断言的 Skill。通过 recordRequests() 捕获并检查 POST/PUT/DELETE 等写操作的 URL、方法和载荷,确保后端状态变更正确触发,不适用于 GET 读操作。

.codex/skills/testing-api-assertions/SKILL.md stacklok/toolhive-studio

Trigger Scenarios

验证创建资源的 API 调用 验证更新或删除资源的 API 调用 测试涉及后端副作用的表单提交或操作

Install

npx skills add stacklok/toolhive-studio --skill testing-api-assertions -g -y
More Options

Non-standard path

npx skills add https://github.com/stacklok/toolhive-studio/tree/main/.codex/skills/testing-api-assertions -g -y

Use without installing

npx skills use stacklok/toolhive-studio@testing-api-assertions

指定 Agent (Claude Code)

npx skills add stacklok/toolhive-studio --skill testing-api-assertions -a claude-code -g -y

安装 repo 全部 skill

npx skills add stacklok/toolhive-studio --all -g -y

预览 repo 内 skill

npx skills add stacklok/toolhive-studio --list

SKILL.md

Frontmatter
{
    "name": "testing-api-assertions",
    "description": "Verify API requests in tests. Use when testing that correct API calls are made for create, update, or delete operations. Use when testing mutations, form submissions, or actions with backend side effects."
}

Testing API Assertions

Verify that your code sends the correct API requests for operations with side effects.

When to Use Request Assertions

DO use for operations with side effects:

  • Creating resources (POST)
  • Updating resources (PUT/PATCH)
  • Deleting resources (DELETE)
  • Any mutation that changes backend state

DON'T use for read operations:

  • Fetching data (GET)
  • For these, just verify the component displays the data correctly
  • The mock API is not stateful, so verifying GET requests adds no value

recordRequests()

Use recordRequests() to capture all API requests made during a test:

import { recordRequests } from '@/common/mocks/node'

it('creates a group with correct payload', async () => {
  const rec = recordRequests()

  // ... perform action that triggers API call ...
  await userEvent.click(screen.getByRole('button', { name: /create/i }))

  // Find the request
  const request = rec.recordedRequests.find(
    (r) => r.method === 'POST' && r.pathname === '/api/v1beta/groups'
  )

  // Assert it was made with correct data
  expect(request).toBeDefined()
  expect(request?.payload).toEqual({ name: 'my-group' })
})

Recorded Request Shape

Each recorded request contains:

{
  pathname: '/api/v1beta/groups',      // URL path
  method: 'POST',                       // HTTP method
  payload: { name: 'my-group' },        // Parsed JSON body (if present)
  search: { filter: 'active' },         // Query parameters
}

Common Patterns

Verify POST payload

const rec = recordRequests()

// ... trigger create action ...

const createRequest = rec.recordedRequests.find(
  (r) => r.method === 'POST' && r.pathname === '/api/v1beta/workloads'
)
expect(createRequest?.payload).toMatchObject({
  name: 'my-server',
  group: 'default',
})

Verify DELETE was called

const rec = recordRequests()

// ... trigger delete action ...

const deleteRequest = rec.recordedRequests.find(
  (r) =>
    r.method === 'DELETE' && r.pathname === '/api/v1beta/workloads/my-server'
)
expect(deleteRequest).toBeDefined()

Verify request order

const rec = recordRequests()

// ... trigger actions ...

const postRequests = rec.recordedRequests.filter((r) => r.method === 'POST')
const groupIndex = postRequests.findIndex((r) => r.pathname.includes('/groups'))
const workloadIndex = postRequests.findIndex((r) =>
  r.pathname.includes('/workloads')
)

// Group must be created before workload
expect(groupIndex).toBeLessThan(workloadIndex)

Verify request count

const rec = recordRequests()

// ... trigger batch action ...

const deleteRequests = rec.recordedRequests.filter(
  (r) =>
    r.method === 'DELETE' && r.pathname.startsWith('/api/v1beta/workloads/')
)
expect(deleteRequests).toHaveLength(3)

Important Notes

  • recordRequests() clears previous recordings when called
  • Call it at the start of your test, before triggering actions
  • Each test starts fresh - recordings don't persist between tests
  • Use toMatchObject() for partial matching when payload has extra fields

When NOT to Use This

For read operations (GET) where you need to verify query parameters are sent correctly, don't use recordRequests(). Instead, use conditional overrides that return different data based on params, then verify the UI shows the expected data. See testing-api-overrides skill.

This approach is more robust because it tests actual user-facing behavior.

Related Skills

  • testing-with-api-mocks - Auto-generated mocks and fixture basics
  • testing-api-overrides - Conditional responses for testing filters/params (read operations)

Version History

  • 12a6ab3 Current 2026-08-20 10:47

Same Skill Collection

.claude/skills/bug-fix-tdd/SKILL.md
.claude/skills/deep-links/SKILL.md
.claude/skills/security-vuln-remediation/SKILL.md
.claude/skills/skill-creator/SKILL.md
.claude/skills/skill-editor/SKILL.md
.claude/skills/testing-api-assertions/SKILL.md
.claude/skills/testing-api-overrides/SKILL.md
.claude/skills/testing-with-api-mocks/SKILL.md
.codex/skills/bug-fix-tdd/SKILL.md
.codex/skills/deep-links/SKILL.md
.codex/skills/security-vuln-remediation/SKILL.md
.codex/skills/skill-creator/SKILL.md
.codex/skills/skill-editor/SKILL.md
.codex/skills/testing-api-overrides/SKILL.md
.codex/skills/testing-with-api-mocks/SKILL.md
.cursor/skills/bug-fix-tdd/SKILL.md
.cursor/skills/deep-links/SKILL.md
.cursor/skills/security-vuln-remediation/SKILL.md
.cursor/skills/skill-creator/SKILL.md
.cursor/skills/skill-editor/SKILL.md
.cursor/skills/testing-api-assertions/SKILL.md
.cursor/skills/testing-api-overrides/SKILL.md
.cursor/skills/testing-with-api-mocks/SKILL.md

Metadata

Files
0
Version
2bb19e5
Hash
2f2b537b
Indexed
2026-08-20 10:47

Главная - Вики-сайт
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-23 06:45
浙ICP备14020137号-1