{"id":"1244879e-f05f-47c1-8697-af95dc56eaa3","shortId":"N2F6Vh","kind":"skill","title":"Unit Test Writer","tagline":"Generates comprehensive unit tests for any function or module with edge cases.","description":"# Unit Test Writer\n\n## What this skill does\n\nThis skill directs the agent to write a thorough unit test suite for a given function, class, or module. It systematically identifies happy paths, edge cases, error paths, and boundary conditions — then writes tests in your chosen framework (Jest, Vitest, Mocha, etc.) with proper mocking where needed.\n\nUse this when you have a function that needs test coverage or when you want to verify your implementation handles edge cases you might not have thought of.\n\n## How to use\n\n### Claude Code / Cline\n\nCopy this file to `.agents/skills/unit-test-writer/SKILL.md` in your project root.\n\nThen ask the agent:\n- *\"Write unit tests for `src/utils/formatCurrency.ts` using the Unit Test Writer skill.\"*\n- *\"Use the Unit Test Writer skill to generate Vitest tests for this function.\"*\n\nPaste the function code into the chat, or reference the file path.\n\n### Cursor\n\nAdd the instructions from the \"Prompt / Instructions\" section below to your `.cursorrules`, or paste them into the Cursor AI pane before asking for tests.\n\n### Codex\n\nPaste your function and the instructions below into the Codex chat. Specify your test framework explicitly (Jest, Vitest, etc.) since Codex does not infer it from the project.\n\n## The Prompt / Instructions for the Agent\n\nWhen asked to write unit tests, follow these steps:\n\n1. **Read the code.** Understand the function's:\n   - Inputs (types, shapes, constraints)\n   - Outputs (return type, side effects)\n   - Dependencies (external calls, imports that may need mocking)\n   - Error conditions (what throws, what returns null/undefined)\n\n2. **Identify test cases in this order:**\n   - **Happy path** — typical valid inputs that produce the expected output\n   - **Boundary values** — min/max numbers, empty strings, empty arrays, zero\n   - **Type coercions** — what happens with `null`, `undefined`, `0`, `\"\"`, `false`\n   - **Error paths** — inputs that should throw or return an error state\n   - **Async edge cases** (if async) — resolved values, rejected promises, race conditions\n   - **Mocked dependencies** — external calls (API, DB, filesystem) must be mocked; never make real calls in unit tests\n\n3. **Structure the test file:**\n   - One `describe` block per function or class\n   - Nested `describe` blocks for logical groups (e.g., `describe('when user is not logged in', ...)`)\n   - Test names must read as complete sentences: `it('returns null when input is an empty array')`\n   - Keep each test focused — one assertion per test when possible, or one concept per test\n\n4. **Mocking rules:**\n   - Use `jest.mock()` / `vi.mock()` for module-level mocks\n   - Use `jest.spyOn()` / `vi.spyOn()` for spying on methods without replacing the module\n   - Always restore mocks in `afterEach` or use `clearMocks: true` in config\n   - Mock at the boundary — mock the imported module, not internal implementation details\n\n5. **Output format:**\n\n```typescript\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; // or jest equivalents\nimport { functionUnderTest } from '../path/to/module';\n\n// Mock external dependencies\nvi.mock('../path/to/dependency', () => ({\n  someFunction: vi.fn(),\n}));\n\ndescribe('functionUnderTest', () => {\n  beforeEach(() => {\n    vi.clearAllMocks();\n  });\n\n  describe('happy path', () => {\n    it('returns the expected result for valid input', () => {\n      // arrange\n      // act\n      // assert\n    });\n  });\n\n  describe('edge cases', () => {\n    it('returns null when input is an empty array', () => { ... });\n    it('handles zero correctly', () => { ... });\n  });\n\n  describe('error handling', () => {\n    it('throws TypeError when input is not a string', () => { ... });\n  });\n});\n```\n\n6. **After writing the tests**, list any cases you could not cover and why (e.g., untestable private methods, missing type information).\n\n## Example\n\n**Input to Agent:**\n> \"Use the Unit Test Writer skill to write Vitest tests for this function:\n>\n> ```typescript\n> export function parsePriceString(price: string): number {\n>   if (!price || typeof price !== 'string') throw new TypeError('price must be a string');\n>   const cleaned = price.replace(/[$,\\s]/g, '');\n>   const num = parseFloat(cleaned);\n>   if (isNaN(num)) throw new RangeError(`Cannot parse price from \"${price}\"`);\n>   return num;\n> }\n> ```\"\n\n**Output from Agent:**\n```typescript\nimport { describe, it, expect } from 'vitest';\nimport { parsePriceString } from '../utils/parsePriceString';\n\ndescribe('parsePriceString', () => {\n  describe('happy path', () => {\n    it('parses a plain number string', () => {\n      expect(parsePriceString('9.99')).toBe(9.99);\n    });\n\n    it('strips dollar signs', () => {\n      expect(parsePriceString('$19.99')).toBe(19.99);\n    });\n\n    it('strips commas from large numbers', () => {\n      expect(parsePriceString('$1,299.00')).toBe(1299);\n    });\n\n    it('strips leading and trailing whitespace', () => {\n      expect(parsePriceString('  $5.00  ')).toBe(5);\n    });\n  });\n\n  describe('edge cases', () => {\n    it('handles zero', () => {\n      expect(parsePriceString('$0.00')).toBe(0);\n    });\n\n    it('handles a string with only a dollar sign as invalid', () => {\n      expect(() => parsePriceString('$')).toThrow(RangeError);\n    });\n  });\n\n  describe('error handling', () => {\n    it('throws TypeError when price is not a string', () => {\n      expect(() => parsePriceString(null as any)).toThrow(TypeError);\n    });\n\n    it('throws TypeError when price is undefined', () => {\n      expect(() => parsePriceString(undefined as any)).toThrow(TypeError);\n    });\n\n    it('throws TypeError when price is an empty string', () => {\n      expect(() => parsePriceString('')).toThrow(TypeError);\n    });\n\n    it('throws RangeError when string contains no numeric characters', () => {\n      expect(() => parsePriceString('abc')).toThrow(RangeError);\n    });\n  });\n});\n```\n\n## Notes\n\n- Always specify your test framework. The skill defaults to Vitest syntax, but will adapt to Jest, Mocha, or others on request.\n- If the function has many external dependencies, ask the agent to list the mocks it would need before writing the full suite.\n- This skill writes the test file only — it does not modify the source file.\n- For very large modules, ask for tests one exported function at a time.","tags":["unit","test","writer","openagentskills","notysoty","agent-skills","claude","claude-code","claude-skills","cline","cursor","llm"],"capabilities":["skill","source-notysoty","skill-unit-test-writer","topic-agent-skills","topic-claude","topic-claude-code","topic-claude-skills","topic-cline","topic-cursor","topic-llm","topic-llm-skills","topic-skills"],"categories":["openagentskills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/Notysoty/openagentskills/unit-test-writer","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add Notysoty/openagentskills","source_repo":"https://github.com/Notysoty/openagentskills","install_from":"skills.sh"}},"qualityScore":"0.454","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (6,288 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:25.427Z","embedding":null,"createdAt":"2026-05-18T13:20:47.614Z","updatedAt":"2026-05-18T19:13:25.427Z","lastSeenAt":"2026-05-18T19:13:25.427Z","tsv":"'/g':565 '/path/to/dependency':454 '/path/to/module':449 '/utils/parsepricestring':596 '0':287,655 '0.00':653 '1':222,630 '1299':633 '19.99':619,621 '2':254 '299.00':631 '3':328 '4':385 '5':430,644 '5.00':642 '6':503 '9.99':610,612 'abc':728 'act':473 'adapt':745 'add':154 'aftereach':411,440 'agent':27,116,212,527,585,762 'agents/skills/unit-test-writer/skill.md':108 'ai':172 'alway':407,732 'api':315 'arrang':472 'array':278,369,486 'ask':114,175,214,760,793 'assert':375,474 'async':300,304 'beforeeach':439,459 'block':335,342 'boundari':52,271,421 'call':241,314,324 'cannot':576 'case':15,48,91,257,302,477,510,647 'charact':725 'chat':147,189 'chosen':59 'class':39,339 'claud':101 'clean':562,569 'clearmock':414 'cline':103 'code':102,144,225 'codex':178,188,199 'coercion':281 'comma':624 'complet':359 'comprehens':5 'concept':382 'condit':53,248,310 'config':417 'const':561,566 'constraint':233 'contain':722 'copi':104 'correct':490 'could':512 'cover':514 'coverag':80 'cursor':153,171 'cursorrul':165 'db':316 'default':739 'depend':239,312,452,759 'describ':334,341,347,435,457,461,475,491,588,597,599,645,671 'detail':429 'direct':25 'dollar':615,663 'e.g':346,517 'edg':14,47,90,301,476,646 'effect':238 'empti':275,277,368,485,711 'equival':445 'error':49,247,289,298,492,672 'etc':64,197 'exampl':524 'expect':269,437,467,590,608,617,628,640,651,667,683,697,713,726 'explicit':194 'export':542,797 'extern':240,313,451,758 'fals':288 'file':106,151,332,780,788 'filesystem':317 'focus':373 'follow':219 'format':432 'framework':60,193,736 'full':773 'function':10,38,76,140,143,181,228,337,540,543,755,798 'functionundertest':447,458 'generat':4,135 'given':37 'group':345 'handl':89,488,493,649,657,673 'happen':283 'happi':45,261,462,600 'identifi':44,255 'implement':88,428 'import':242,424,434,446,587,593 'infer':202 'inform':523 'input':230,265,291,365,471,482,498,525 'instruct':156,160,184,209 'intern':427 'invalid':666 'isnan':571 'jest':61,195,444,747 'jest.mock':389 'jest.spyon':397 'keep':370 'larg':626,791 'lead':636 'level':394 'list':508,764 'log':352 'logic':344 'make':322 'mani':757 'may':244 'method':402,520 'might':93 'min/max':273 'miss':521 'mocha':63,748 'mock':67,246,311,320,386,395,409,418,422,450,766 'modifi':785 'modul':12,41,393,406,425,792 'module-level':392 'must':318,356,557 'name':355 'need':69,78,245,769 'nest':340 'never':321 'new':554,574 'note':731 'null':285,363,480,685 'null/undefined':253 'num':567,572,582 'number':274,547,606,627 'numer':724 'one':333,374,381,796 'order':260 'other':750 'output':234,270,431,583 'pane':173 'pars':577,603 'parsefloat':568 'parsepricestr':544,594,598,609,618,629,641,652,668,684,698,714,727 'past':141,167,179 'path':46,50,152,262,290,463,601 'per':336,376,383 'plain':605 'possibl':379 'price':545,549,551,556,578,580,678,694,708 'price.replace':563 'privat':519 'produc':267 'project':111,206 'promis':308 'prompt':159,208 'proper':66 'race':309 'rangeerror':575,670,719,730 'read':223,357 'real':323 'refer':149 'reject':307 'replac':404 'request':752 'resolv':305 'restor':408 'result':468 'return':235,252,296,362,465,479,581 'root':112 'rule':387 'section':161 'sentenc':360 'shape':232 'side':237 'sign':616,664 'sinc':198 'skill':21,24,127,133,533,738,776 'skill-unit-test-writer' 'somefunct':455 'sourc':787 'source-notysoty' 'specifi':190,733 'spi':400 'src/utils/formatcurrency.ts':121 'state':299 'step':221 'string':276,502,546,552,560,607,659,682,712,721 'strip':614,623,635 'structur':329 'suit':34,774 'syntax':742 'systemat':43 'test':2,7,17,33,56,79,119,125,131,137,177,192,218,256,327,331,354,372,377,384,507,531,537,735,779,795 'thorough':31 'thought':96 'throw':250,294,495,553,573,675,691,705,718 'time':801 'tobe':611,620,632,643,654 'topic-agent-skills' 'topic-claude' 'topic-claude-code' 'topic-claude-skills' 'topic-cline' 'topic-cursor' 'topic-llm' 'topic-llm-skills' 'topic-skills' 'tothrow':669,688,702,715,729 'trail':638 'true':415 'type':231,236,280,522 'typeerror':496,555,676,689,692,703,706,716 'typeof':550 'typescript':433,541,586 'typic':263 'undefin':286,696,699 'understand':226 'unit':1,6,16,32,118,124,130,217,326,530 'untest':518 'use':70,100,122,128,388,396,413,528 'user':349 'valid':264,470 'valu':272,306 'verifi':86 'vi':438 'vi.clearallmocks':460 'vi.fn':456 'vi.mock':390,453 'vi.spyon':398 'vitest':62,136,196,442,536,592,741 'want':84 'whitespac':639 'without':403 'would':768 'write':29,55,117,216,505,535,771,777 'writer':3,18,126,132,532 'zero':279,489,650","prices":[{"id":"9f587865-6a85-4f2b-b1e7-627dac53646e","listingId":"1244879e-f05f-47c1-8697-af95dc56eaa3","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"Notysoty","category":"openagentskills","install_from":"skills.sh"},"createdAt":"2026-05-18T13:20:47.614Z"}],"sources":[{"listingId":"1244879e-f05f-47c1-8697-af95dc56eaa3","source":"github","sourceId":"Notysoty/openagentskills/unit-test-writer","sourceUrl":"https://github.com/Notysoty/openagentskills/tree/main/skills/unit-test-writer","isPrimary":false,"firstSeenAt":"2026-05-18T13:20:47.614Z","lastSeenAt":"2026-05-18T19:13:25.427Z"}],"details":{"listingId":"1244879e-f05f-47c1-8697-af95dc56eaa3","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"Notysoty","slug":"unit-test-writer","github":{"repo":"Notysoty/openagentskills","stars":8,"topics":["agent-skills","claude","claude-code","claude-skills","cline","cursor","llm","llm-skills","skills"],"license":"mit","html_url":"https://github.com/Notysoty/openagentskills","pushed_at":"2026-03-28T06:50:19Z","description":"A  community-driven library of reusable AI agent skills for Claude Code, Cursor, Codex, Cline, and more.","skill_md_sha":"e520752ce8d87553673ea8ea730f1eab621a53a7","skill_md_path":"skills/unit-test-writer/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/Notysoty/openagentskills/tree/main/skills/unit-test-writer"},"layout":"multi","source":"github","category":"openagentskills","frontmatter":{"name":"Unit Test Writer","description":"Generates comprehensive unit tests for any function or module with edge cases."},"skills_sh_url":"https://skills.sh/Notysoty/openagentskills/unit-test-writer"},"updatedAt":"2026-05-18T19:13:25.427Z"}}