Agent skill
td-integration-test
Write integration tests for the td-sync admin API using the TestHarness in internal/api/testharness_test.go. Use when asked to write, add, or fix integration tests for admin API endpoints (server, users, projects, events, snapshots, CORS, auth). The harness provides a real HTTP server, fluent state builder, and assertion helpers. Tests go in internal/api/admin_integration_test.go.
Install this agent skill to your Project
npx add-skill https://github.com/marcus/td/tree/main/.claude/skills/td-integration-test
SKILL.md
td-sync Admin API Integration Tests
Write integration tests in internal/api/admin_integration_test.go using the harness in internal/api/testharness_test.go. Tests run against a real HTTP server on a random port with isolated temp databases.
Quick Start Pattern
func TestIntegration_DescriptiveName(t *testing.T) {
t.Parallel()
h := newTestHarness(t)
state := h.Build().
WithUser("user@test.com").
WithAdmin("admin@test.com", "admin:read:server,sync").
WithProject("proj1", "user@test.com").
WithEvents("proj1", "user@test.com", 5).
Done()
token := state.AdminToken("admin@test.com")
pid := state.ProjectID("proj1")
var resp adminEventsResponse
h.DoJSON("GET", fmt.Sprintf("/v1/admin/projects/%s/events", pid), token, nil, &resp)
if len(resp.Data) != 5 {
t.Fatalf("expected 5 events, got %d", len(resp.Data))
}
}
Harness API
See references/harness-api.md for the complete API reference with all method signatures and detailed usage notes.
Core
newTestHarness(t, ...func(*Config)) *TestHarness-- real HTTP server, isolated DB, auto-cleanuph.Do(method, path, token, body) *http.Response-- real HTTP request (caller closes body)h.DoJSON(method, path, token, body, &out) *http.Response-- request + JSON decode (fatals on 4xx/5xx)
State Builder
h.Build().
WithUser(email). // sync-scoped key
WithAdmin(email, scopes). // admin key with scopes
WithProject(name, ownerEmail). // via API (owner must exist)
WithMember(projectName, email, role). // "owner"/"writer"/"reader"
WithEvents(projectName, userEmail, count).// cycles issues/logs/comments
WithSnapshot(projectName). // triggers snapshot build
WithAuthEvents(count). // inserts directly to DB
WithRateLimitEvents(count). // inserts directly to DB
Done() // -> *TestState
Ordering matters: create users before projects, projects before members/events/snapshots.
State Accessors
state.UserToken(email), state.UserID(email), state.AdminToken(email), state.ProjectID(name), state.Harness()
Assertions
AssertStatus(t, resp, 200)-- checks status, prints body on failureAssertErrorResponse(t, resp, 403, "insufficient_admin_scope")-- checks status + error codeReadJSON[T](t, resp) T-- generic JSON decodeAssertPaginated[T](t, resp, count, hasMore) PaginatedResponse[T]-- checks paginated listAssertCORSHeaders(t, resp, origin)/AssertNoCORSHeaders(t, resp)h.AssertRequiresAdminScope(t, method, path, wrongToken)-- 403 + error code check
Admin Scopes
| Scope | Endpoints |
|---|---|
admin:read:server |
server/overview, server/config, rate-limit-violations, users, users/{id}, users/{id}/keys, auth/events |
admin:read:projects |
projects, projects/{id}, projects/{id}/members, sync/status, sync/cursors |
admin:read:events |
projects/{id}/events, projects/{id}/events/{seq}, entity-types |
admin:read:snapshots |
projects/{id}/snapshot/meta, projects/{id}/snapshot/query |
admin:export |
projects/{id}/events/export |
Response Types
Internal types accessible from test files in package api:
serverOverviewResponse-- server overviewserverConfigResponse-- server configadminEventsResponse--{Data []adminEvent, HasMore bool}adminEvent-- single event:ServerSeq,EntityType,EntityID,ActionType,PayloadadminSyncStatusResponse--{EventCount, LastServerSeq, LastEventTime}adminCursorEntry--{ClientID, LastEventID, LastSyncAt, DistanceFromHead}serverdb.AdminProject-- project:ID, Name, MemberCount, EventCountserverdb.AdminUser-- user:ID, Email, IsAdmin, ProjectCountserverdb.AdminProjectMember--{UserID, Email, Role}
Rules
- Always
t.Parallel()-- each harness is isolated - Test name prefix:
TestIntegration_ - Config overrides via opts:
newTestHarness(t, func(cfg *Config) { cfg.CORSAllowedOrigins = []string{"https://x.com"} }) - First user created is auto-admin; consume with
h.CreateUser("first@test.com")when testing non-admin denial - CORS tests need manual
http.NewRequestsinceDodoesn't support custom headers - Run tests:
go test -v -run TestIntegration ./internal/api/
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
td-task-management
Task management for AI agents across context windows. Use when agents need to track work, log progress, hand off state, and maintain context across sessions. Includes workflows for single-issue focus, multi-issue work sessions, and structured handoffs. Essential for AI-assisted development where context windows reset between sessions.
create-prompt
Create prompts for sidecar workspaces. Covers prompt structure (name, ticketMode, body), template variables (ticket with fallbacks), config file locations (global vs project), and scope overrides. Use when creating or modifying prompts in sidecar config files.
merge-strategy
Git merge strategies, conflict resolution approaches, merge vs rebase recommendations, and branch integration patterns in sidecar. Covers pull strategy menu, direct merge workflow, squash merge, commit message templates, configurable defaults, and protected branches. Use when working on git merge features or making decisions about merge strategies.
keyboard-shortcuts
Reference for keyboard shortcut implementation, keybinding registration, shortcut parity with vim and other TUI tools, and the complete shortcut assignment table across all sidecar plugins. Use when adding or modifying keyboard shortcuts, checking shortcut assignments, resolving key conflicts, or assessing alignment with vim conventions.
profile-memory
Profile memory usage in sidecar using Go pprof, system tools, and heap analysis. Covers identifying memory leaks, goroutine leaks, file descriptor accumulation, and CPU profiling. Use when investigating memory issues, profiling performance, debugging memory leaks, or diagnosing unresponsive plugins.
create-theme
Create custom color themes for Sidecar, including base theme selection, color overrides, gradient borders, tab styles, per-project themes, community themes, and programmatic theme registration. Use when creating or modifying themes, adjusting UI appearance, or debugging color/style issues. See references/palette-reference.md for the full color palette with all keys and per-theme values.
Didn't find tool you were looking for?