Agent skill

Testing

by udecode in udecode/kitcn

A skill your agent uses when writing React hook tests, encountering test failures, flaky tests, cross-file contamination, or "Hook timed out" errors - Bun test patterns with proper spy cleanup

Apache-2.0Auto-check passedTesting & QA

Install Testing

skills CLI
$ npx skills add udecode/kitcn --skill testing -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install udecode/kitcn testing --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/udecode/kitcn.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/testing .claude/skills/testing && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
testing
GitHub stars
450
Token cost
~3.2k tokens
SKILL.md length
825 words
Files
1
Skills in repo
33
Repo updated
First seen
Licence
Apache-2.0

At a glance

A skill your agent uses when writing React hook tests, encountering test failures, flaky tests, cross-file contamination, or "Hook timed out" errors - Bun test patterns with proper spy cleanup

  • Works in 4 steps: bunfig.toml → tooling/global.d.ts → tooling/test-setup.ts → …
  • Writing React hook tests
  • SKILL.md covers Overview, Setup (First-Time Installation), When to Use and Quick Reference, plus 7 more sections
  • Calls bun

What it does

Testing is an agent skill from udecode/kitcn. Use when writing React hook tests, encountering test failures, flaky tests, cross-file contamination, or "Hook timed out" errors - Bun test patterns with proper spy cleanup

Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Testing & QA, covering Failing and flaky tests and React components. The repository describes itself as: Convex + Better Auth + tRPC + Drizzle + TanStack Query + shadcn. The licence is Apache-2.0.

When your agent uses it

  • Writing React hook tests
  • Encountering test failures
  • Cross-file contamination
  • Hook timed out errors - Bun test patterns with proper spy cleanup

Example prompts

  • “Hook timed out”
  • “/testing”

Workflow steps

4 steps, taken from the step headings in SKILL.md.

  1. bunfig.toml
  2. tooling/global.d.ts
  3. tooling/test-setup.ts
  4. Dependencies

What it can do on your machine

Read from SKILL.md and the folder at commit c6010f5. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • bun

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Testing loads about 3.2k tokens when it runs. Until then it costs about 45 tokens; SKILL.md has 825 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~45
When it runs · the whole SKILL.md, loaded when a task matches
~3.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from udecode/kitcn at commit c6010f5, republished under its Apache-2.0 licence (© udecode). 825 words, ~3,163 tokens.

Download SKILL.mdSave it as .claude/skills/testing/SKILL.md (or your agent's skills folder).
name
testing
description
Use when writing React hook tests, encountering test failures, flaky tests, cross-file contamination, or "Hook timed out" errors - Bun test patterns with proper spy cleanup

Bun Testing Patterns

Overview

Bun's test runner provides Jest-compatible API with TypeScript support and fast execution. Critical: Test globals (describe, it, expect, mock, spyOn, beforeEach, afterEach) are available globally via tooling/global.d.ts - no imports needed. mock.module() is process-global - use spyOn() instead.

Setup (First-Time Installation)

1. bunfig.toml
toml
[test]
# Preload scripts execute BEFORE any test file
preload = ["./tooling/test-setup.ts"]

# Coverage exclusions
coveragePathIgnorePatterns = [
  "node_modules/**",
  "**/*.d.ts",
]
2. tooling/global.d.ts
typescript
/// <reference types="bun-types/test-globals" />

declare var mock: typeof import("bun:test").mock;
declare var spyOn: typeof import("bun:test").spyOn;
3. tooling/test-setup.ts
typescript
import { afterEach, expect, mock, spyOn } from "bun:test";
import { GlobalRegistrator } from "@happy-dom/global-registrator";
import * as matchers from "@testing-library/jest-dom/matchers";
import { cleanup } from "@testing-library/react";

// Make mock and spyOn globally available
(globalThis as any).mock = mock;
(globalThis as any).spyOn = spyOn;

// Register DOM globals synchronously
GlobalRegistrator.register();

// Ensure document.body exists
if (global.document && !global.document.body) {
  const body = global.document.createElement("body");
  global.document.documentElement.appendChild(body);
}

// Extend Bun's expect with Testing Library matchers
expect.extend(matchers);

// Cleanup after each test
afterEach(() => {
  cleanup();
});
4. Dependencies
bash
bun add -d @happy-dom/global-registrator @testing-library/react @testing-library/jest-dom

When to Use

  • Writing new tests for React hooks
  • Debugging test failures, especially when tests pass individually but fail in full suite
  • Fixing cross-file contamination ("test passes alone, fails with others")
  • Encountering "Hook timed out", race conditions, or flaky tests

Quick Reference

PatternUse CaseExample
No imports neededTest globalsdescribe, it, expect, mock, spyOn are global
toMatchObject(array)Array partial matchChecks properties exist, allows extras
toEqual()Exact matchValidates complete structure
expect(val as any)Type mismatchCast actual value, not expected
mock() not jest.fn()Create mock functionBun test API
spyOn() + afterEachMock with cleanupAlways spy.mockRestore()
renderHook() + act()Test hooksWrap state changes in act()
void act()Prevent warningsUse with sync click/change events
ReturnType<typeof mock>Type mock variableslet mockFn: ReturnType<typeof mock>
ReturnType<typeof spyOn>Type spy variableslet spy: ReturnType<typeof spyOn>

Core Patterns

Test File Structure
typescript
// NO bun:test imports needed - globals are available
import { act, renderHook } from "@testing-library/react";
import * as apiModule from "@/lib/api"; // Import as namespace for spyOn

describe("HookName", () => {
  let mockFunction: ReturnType<typeof mock>;
  let functionSpy: ReturnType<typeof spyOn>;

  beforeEach(() => {
    mockFunction = mock();
    functionSpy = spyOn(apiModule, "functionName").mockImplementation(
      mockFunction
    );
    mockFunction.mockResolvedValue(defaultResponse);
  });

  afterEach(() => {
    // CRITICAL: Always restore spies
    functionSpy.mockRestore();
  });

  it("should do something", async () => {
    // Test implementation
  });
});
Avoiding Cross-File Contamination

Problem: mock.module() is process-global. If fileA.test.ts uses mock.module('@/lib/api'), it contaminates fileB.test.ts.

Solution: Use spyOn() instead of mock.module().

❌ WRONG - Causes Cross-Contamination
typescript
// This globally mocks the module for ALL test files
mock.module("@/lib/api", () => ({
  fetchData: mock(),
}));
✅ CORRECT - File-Scoped Mocking
typescript
import * as apiModule from "@/lib/api";

describe("MyHook", () => {
  let mockFetchData: ReturnType<typeof mock>;
  let fetchDataSpy: ReturnType<typeof spyOn>;

  beforeEach(() => {
    mockFetchData = mock();
    fetchDataSpy = spyOn(apiModule, "fetchData").mockImplementation(
      mockFetchData
    );
    mockFetchData.mockResolvedValue({ data: "test" });
  });

  afterEach(() => {
    fetchDataSpy.mockRestore();
  });

  it("fetches data", async () => {
    const { result } = renderHook(() => useMyHook());

    await act(async () => {
      await result.current.fetch();
    });

    expect(mockFetchData).toHaveBeenCalled();
  });
});

Key differences:

  1. Import module as namespace: import * as apiModule from './api'
  2. Create spies in beforeEach: spyOn(apiModule, 'function')
  3. Always mockRestore() in afterEach
  4. Use mock variables in assertions: expect(mockFn) not expect(apiModule.fn)
When mock.module() Is Allowed

Use mock.module() only for infrastructure every test needs, configured in a preload, or for a module that will never be imported as real code elsewhere in the same Bun process. It mutates process-global module state and may preserve unmocked real exports while overriding only returned keys. The result can look real while a few exports are poisoned.

Do not solve one contaminated test by lowering global concurrency, changing CI, or adding runtime dependency-indirection files solely for tests. Prefer a lower-level contract, a file-scoped spy, or a different integration harness.

mockReset() Destroys Implementations

mockReset() clears calls and the implementation. Restore defaults immediately:

typescript
const fetchValue = mock(async () => "default");

beforeEach(() => {
  fetchValue.mockReset();
  fetchValue.mockResolvedValue("default");
});

Use mockClear() when only call history should reset.

Module-Scope Environment Values Need Fresh Imports

If a subject reads an environment flag at module scope, changing the mock after the static import cannot affect it. Set a mutable environment mock first, then dynamically import the subject. Add a deterministic cache-busting import query only when Bun otherwise reuses the module. Avoid random cache keys in committed tests when an incrementing case id works.

Reproducing Order-Dependent Failures

If a test passes alone and fails in the suite, run likely contaminators before the victim in one command:

bash
bun test likely-contaminator.test.ts victim.test.ts

Record the minimal ordering that fails. Inspect module keys, critical function types, and resolved default values behind a temporary opt-in debug flag. Remove debug output after the owner is proven.

Testing React Hooks
typescript
import { act, renderHook } from "@testing-library/react";

it("updates state correctly", async () => {
  const { result } = renderHook(() => useCustomHook());

  await act(async () => {
    await result.current.fetchData();
  });

  expect(result.current.data).toEqual(expectedData);
  expect(result.current.loading).toBe(false);
});

// Use void to prevent unused promise warnings
void act(() => getByText("button").click());

Custom wrapper pattern for context providers:

typescript
const createWrapper = (props) => ({ children }: any) => (
  <Provider {...props}>{children}</Provider>
);

const wrapper = createWrapper({ value: 'test' });
const { result } = renderHook(() => useCustomHook(), { wrapper });
Testing Async Errors
typescript
it("handles async errors", async () => {
  mockFetch.mockRejectedValue(new Error("Network error"));

  const { result } = renderHook(() => useCustomHook());

  await act(async () => {
    try {
      await result.current.fetchData();
    } catch (error) {
      expect(error).toEqual(new Error("Failed to load"));
    }
  });

  expect(result.current.error).toBe("Failed to load");
});
Matcher Selection
typescript
// ✅ Array partial matching
expect(children).toMatchObject([{ text: "one" }, { text: "two" }]);

// ✅ Exact matching
expect(result).toEqual({ data: "test" });

// ✅ Cast actual value for type mismatches
expect(node as any).toEqual({ text: "one" });

// ❌ Don't cast expected value
expect(children).toEqual([{ text: "one" }] as any);

// ❌ Don't use toMatchObject() for single objects (won't catch extra props)
expect(node).toMatchObject({ text: "one" });

Running Tests

bash
# Run all tests
bun test

# Run specific file
bun test src/hooks/useMyHook.test.ts

# Watch mode
bun test --watch

# Coverage
bun test --coverage

# Bail on first failure
bun test --bail
Show full SKILL.md (331 more words)Show less

Common Mistakes

MistakeProblemFix
Importing from bun:testUnnecessary, globals availableRemove imports
Using mock.module()Cross-file contaminationUse spyOn() + afterEach cleanup
Forgetting afterEach cleanupSpies persist across testsAlways spy.mockRestore()
Direct import for spyOnCan't spy on named exportsimport * as module
Forgetting act()React warnings, flaky testsWrap state changes in act()
jest.fn() / jest.MockWrong frameworkUse mock() and ReturnType<typeof mock>
No type for mocksType errors, autocomplete failsReturnType<typeof mock>

Debugging Test Failures

Test passes alone, fails in suite

Symptom: bun test file.test.ts passes, bun test fails.

Cause: Cross-file contamination from mock.module().

Fix:

  1. Search for mock.module() calls
  2. Refactor to spyOn() pattern with afterEach cleanup
"Expected to be called but it was not called"

Cause: Wrong mock variable or wrong function name.

Fix:

  1. Verify spy setup: spyOn(module, 'correctFunctionName')
  2. Check assertions use mock variable: expect(mockFn) not expect(module.fn)
"Hook timed out after 5000ms"

Cause: Missing await, unresolved promise.

Fix:

  1. Ensure all async operations are awaited
  2. Check mock returns resolved promises: mockResolvedValue()
  3. Increase timeout if needed: it('name', fn, 10000)

Red Flags - Cross-Contamination Risk

  • Using mock.module() outside of preload scripts
  • Importing modules directly instead of as namespace for spyOn
  • Missing afterEach() with mockRestore() calls
  • Tests passing individually but failing in full suite

All indicate cross-file contamination. Refactor to spyOn pattern.

Implementation Checklist

For each new hook test file:

  • NO imports from bun:test - globals are available
  • Import renderHook, act from @testing-library/react when testing hooks
  • Import modules as namespace for spyOn: import * as module
  • Declare mock variables with ReturnType<typeof mock>
  • Declare spy variables with ReturnType<typeof spyOn>
  • Create spies in beforeEach with spyOn(module, 'fn')
  • Set default mock return values in beforeEach
  • CRITICAL: Restore spies in afterEach with spy.mockRestore()
  • Wrap React state changes in act()
  • Use mock variables in assertions, not module functions
  • Verify tests pass both individually and in full suite

TDD Workflow

  1. Red: Write failing test for hook behavior
  2. Green: Implement minimal code to pass test
  3. Refactor: Clean up implementation
  4. Repeat: Add next test case

© udecode, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/testing of udecode/kitcn.

Open the folder on GitHubat commit c6010f5

Compare with similar skills

Testing next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Testing compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Testing this skilludecode/kitcn450—~3.2kAutomated safety check: PassApache-2.0
Testingredis/RedisInsight8.9k—~3.3kAutomated safety check: PassCustom licence
Appbuilder Testingadobe/skills196—~2.8kAutomated safety check: PassApache-2.0
Swig Testswig/swig6.3k—~2.3kAutomated safety check: PassCustom licence
Triage CI FailureDataDog/datadog-agent3.8k—~2.3kAutomated safety check: PassApache-2.0
Dynamo Jira TicketDynamoDS/Dynamo2k—~1.1kAutomated safety check: PassApache-2.0

Similar skills

  • Testing

    redis/RedisInsight

    Official

    Unit/integration testing standards for RedisInsight using Jest and Testing Library: test structure, the renderComponent helper, faker for test data, mocking patterns, and waitFor instead of fixed…

    8.9k GitHub stars~3.3k tokensUpdated 3 days ago
    Testing & QAAuto-check passed
  • Appbuilder Testing

    adobe/skills

    Generate and run tests for Adobe App Builder actions and UI components.

    196 GitHub stars~2.8k tokensUpdated today
    Testing & QAAuto-check passed
  • Swig Test

    swig/swig

    Run SWIG test suite for specific languages. An agent skill from swig/swig.

    6.3k GitHub stars~2.3k tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Triage CI Failure

    DataDog/datadog-agent

    Official

    Classify a failed CI as either caused by an active incident, flakiness, or a true code regression.

    3.8k GitHub stars~2.3k tokensUpdated today
    Testing & QAAuto-check passed
  • Dynamo Jira Ticket

    DynamoDS/Dynamo

    Create structured Jira tickets for Dynamo from bug reports, failing tests, or feature requests.

    2k GitHub stars~1.1k tokensUpdated today
    Testing & QAAuto-check passed
  • Fix Ready PRs

    fastrepl/anarlog

    Inspect every open non-draft PR for CI failures and unresolved Cursor Bugbot findings, then fix them on the existing PR branches.

    9.5k GitHub stars~1.4k tokensUpdated today
    Testing & QAAuto-check passed

More from udecode/kitcn

All 33 skills in this repo
  • Walkthrough

    udecode/kitcn

    Create a short annotated visual walkthrough from real final-state screenshots or rendered artifacts.

    450 GitHub stars~1.6k tokensUpdated 6 days ago
    Auto-check passed
  • Avoid Feature Creep

    udecode/kitcn

    Prevent feature creep when building software, apps, and AI-powered products.

    450 GitHub stars~2.7k tokensUpdated 6 days ago
    Auto-check passed
  • Changeset Resolve

    udecode/kitcn

    Repair an unreleased .changeset/.md file so it matches the real branch delta against main.

    450 GitHub stars~922 tokensUpdated 6 days ago
    Auto-check passed
  • Audit newer Convex npm releases against kitcn. An agent skill from udecode/kitcn.

    450 GitHub stars~1.8k tokensUpdated 6 days ago
    Auto-check passed
  • Jotai X

    udecode/kitcn

    A skill your agent uses when working with Jotai X stores (createAtomStore), accessing state in components or callbacks, persisting state to cookies or localStorage

    450 GitHub stars~3.7k tokensUpdated 6 days ago
    Auto-check passed
  • Linear Backlog

    udecode/kitcn

    Run a scoped Linear backlog autonomously as a sequence of maximal safe parallel batches by composing orchestrator, autogoal, and task.

    450 GitHub stars~3.1k tokensUpdated 6 days ago
    Auto-check passed

Categories

Questions about Testing

What does Testing do?

A skill your agent uses when writing React hook tests, encountering test failures, flaky tests, cross-file contamination, or "Hook timed out" errors - Bun test patterns with proper spy cleanup. Testing is an agent skill from udecode/kitcn.

When should I use Testing?

Testing fits situations like: writing React hook tests; encountering test failures; cross-file contamination; hook timed out errors - Bun test patterns with proper spy cleanup.

How do I install Testing in Claude Code?

Run `npx skills add udecode/kitcn --skill testing -a claude-code`. Or copy the skill folder (.agents/skills/testing in udecode/kitcn) into .claude/skills/testing in your project. Claude Code loads it when a task matches its description.

How do I install Testing in Codex?

Run `npx skills add udecode/kitcn --skill testing -a codex`. Or copy the skill folder (.agents/skills/testing in udecode/kitcn) into .agents/skills/testing in your project. Codex loads it when a task matches its description.

Can I use Testing in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add udecode/kitcn --skill testing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/testing, .gemini/skills/testing, .github/skills/testing and .opencode/skills/testing in your project.

What does Testing need to run?

Going by SKILL.md and its folder, Testing needs the command-line tools its instructions call (bun).

Does Testing access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Testing safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Testing use?

Testing is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Testing use?

About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Testing?

Skills that share tags, products or a category with Testing: Testing (redis/RedisInsight, 8.9k stars), Appbuilder Testing (adobe/skills, 196 stars), Swig Test (swig/swig, 6.3k stars) and Triage CI Failure (DataDog/datadog-agent, 3.8k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Testing?

udecode (a GitHub organization) maintains it in udecode/kitcn, which has 450 GitHub stars. The repository holds 33 skills in this directory. The repository was last updated on October 1, 2026.

Source: udecode/kitcn on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.