{"manifest":{"name":"Table-Driven Test Generator","version":"1.0.0","description":"Generate complete Vitest/Jest/pytest table-driven tests for any function. Covers happy path, boundary values, null/undefined, async rejection, and type edge cases. Ready to run, zero placeholder text.","tags":["testing","vitest","jest","pytest","tdd","code-quality"],"standard":"agentskills.io","standard_version":"1.0","content_checksum":"54d2b0b67b2826588cc2bfadea75e21633a37f01a313d220209668ff9b106d29","bundle_checksum":null,"metadata":{},"files":[]},"files":{"SKILL.md":"# Table-Driven Test Generator\n\n> **Purpose:** Generate a complete, runnable test file for any function using table-driven tests (`it.each` / `test.each` in Vitest/Jest, parametrize in pytest). Covers: happy path, boundary values, null/undefined inputs, empty collections, async rejection, and type coercion edge cases. Output can be pasted directly into a `.test.ts` or `_test.py` file and run immediately.\n\n---\n\n## Invocation\n\n```\n/test <function-signature-and-implementation>\n```\n\n**Examples:**\n- `/test function add(a: number, b: number): number { return a + b }`\n- `/test async function fetchUser(id: string): Promise<User | null>`\n- `/test def calculate_discount(price: float, pct: float) -> float:`\n\n---\n\n## Process\n\n### Step 1: Analyze the Function\n\nIdentify:\n- **Inputs**: types, constraints, optional vs required\n- **Output**: return type, possible return values\n- **Side effects**: async operations, mutations, I/O\n- **Failure modes**: throws, returns null, rejects, etc.\n\n---\n\n### Step 2: Design Test Cases\n\nFor every function, generate tests covering:\n\n| Category | Examples |\n|----------|---------|\n| Happy path | Typical inputs, expected output |\n| Boundary — low | 0, -1, empty string, empty array |\n| Boundary — high | MAX_SAFE_INTEGER, very long string, large array |\n| Null / undefined | null, undefined, missing optional param |\n| Type edge cases | NaN, Infinity, 0.1 + 0.2 floating point |\n| Async rejection | Network error, timeout, invalid response |\n| Error path | Invalid input → throws specific error |\n| Idempotency | Same input twice → same output |\n\n---\n\n### Step 3: Write the Test File\n\n**Vitest / Jest output:**\n\n```typescript\nimport { describe, it, expect, vi } from 'vitest'\nimport { functionName } from './module'\n\ndescribe('functionName', () => {\n  it.each([\n    // [description, input1, input2, ..., expected]\n    ['happy path: typical inputs', arg1, arg2, expectedOutput],\n    ['boundary: zero value', 0, arg2, expectedForZero],\n    ['boundary: negative', -1, arg2, expectedForNegative],\n    ['null input: first arg null', null, arg2, expectedForNull],\n  ])('%s', (description, input1, input2, expected) => {\n    // Arrange\n    const input = buildInput(input1, input2)\n\n    // Act\n    const result = functionName(input1, input2)\n\n    // Assert\n    expect(result).toEqual(expected)\n  })\n\n  it('throws on invalid input', () => {\n    // Arrange + Act + Assert\n    expect(() => functionName(invalidInput)).toThrow('Expected error message')\n  })\n\n  it('handles async rejection gracefully', async () => {\n    // Arrange\n    vi.mocked(dependency).mockRejectedValue(new Error('Network error'))\n\n    // Act + Assert\n    await expect(functionName(input)).rejects.toThrow('Network error')\n  })\n})\n```\n\n**pytest output:**\n\n```python\nimport pytest\nfrom module import function_name\n\n@pytest.mark.parametrize(\"description,input_val,expected\", [\n    (\"happy path: typical input\", typical_input, expected_output),\n    (\"boundary: zero\", 0, expected_for_zero),\n    (\"boundary: negative\", -1, expected_for_neg),\n    (\"None input\", None, expected_for_none),\n])\ndef test_function_name(description, input_val, expected):\n    # Arrange + Act\n    result = function_name(input_val)\n\n    # Assert\n    assert result == expected, f\"Failed: {description}\"\n\ndef test_function_name_raises_on_invalid():\n    with pytest.raises(ValueError, match=\"Expected message\"):\n        function_name(invalid_input)\n```\n\n---\n\n## Rules\n\n- Every test must follow AAA (Arrange / Act / Assert) with comment labels\n- The table must have at least 5 rows: 1 happy path + 4 edge cases\n- Async functions must include at least one rejection test\n- No placeholder text in the output — all test values must be concrete\n- If the function has side effects (DB write, HTTP call): add a mock setup block\n- Output must be runnable as-is — the only acceptable TODO is \"fill in real mock return value\"\n- Detect framework from function syntax: TypeScript → Vitest, Python → pytest, Go → `testing.T` table tests\n\n## Playground\n\n<!DOCTYPE html><html><head><meta charset='utf-8'><style>*{box-sizing:border-box;margin:0;padding:0}body{background:#0d1117;color:#e6edf3;font-family:monospace;font-size:12px;height:100vh;display:flex;flex-direction:column;overflow:hidden}.header{background:#161b22;border-bottom:1px solid #30363d;padding:8px 14px;font-size:11px;color:#8b949e;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.title{color:#58a6ff;font-weight:bold;font-size:13px}.panels{display:flex;flex:1;overflow:hidden}.panel{flex:1;overflow:auto;padding:12px;border-right:1px solid #30363d}.panel:last-child{border-right:none}.label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}pre{white-space:pre-wrap;word-break:break-word;line-height:1.5}</style></head><body><div class='header'><span class='title'>Table-Driven Test Generator</span><span>Example · SkillSlap</span></div><div class='panels'><div class='panel'><div class='label'>Input: Go function</div><pre><span style='color:#8b949e'>func Clamp(v, min, max int) int {</span>\n<span style='color:#8b949e'>    if v &lt; min { return min }</span>\n<span style='color:#8b949e'>    if v &gt; max { return max }</span>\n<span style='color:#8b949e'>    return v</span>\n<span style='color:#8b949e'>}</span></pre></div><div class='panel'><div class='label'>Output: Table-driven tests</div><pre><span style='color:#58a6ff'>func TestClamp(t *testing.T) {</span>\n<span style='color:#8b949e'>  tests := []struct{</span>\n<span style='color:#8b949e'>    name     string</span>\n<span style='color:#8b949e'>    v,mn,mx  int</span>\n<span style='color:#8b949e'>    want     int</span>\n<span style='color:#8b949e'>  }{</span>\n<span style='color:#8b949e'>    {\"below min\", -5, 0, 10, 0},</span>\n<span style='color:#8b949e'>    {\"above max\", 15, 0, 10, 10},</span>\n<span style='color:#8b949e'>    {\"in range\",   5, 0, 10,  5},</span>\n<span style='color:#8b949e'>    {\"at min\",     0, 0, 10,  0},</span>\n<span style='color:#8b949e'>    {\"at max\",    10, 0, 10, 10},</span>\n<span style='color:#8b949e'>  }</span>\n\n<span style='color:#8b949e'>  for _, tc := range tests {</span>\n<span style='color:#8b949e'>    t.Run(tc.name, func(t *testing.T) {</span>\n<span style='color:#8b949e'>      got := Clamp(tc.v, tc.mn, tc.mx)</span>\n<span style='color:#8b949e'>      if got != tc.want {</span>\n<span style='color:#8b949e'>        t.Errorf(\"got %d want %d\",</span>\n<span style='color:#8b949e'>          got, tc.want)</span>\n<span style='color:#8b949e'>      }</span>\n<span style='color:#8b949e'>    })</span>\n<span style='color:#8b949e'>  }</span>\n<span style='color:#8b949e'>}</span></pre></div></div></body></html>"}}