Claude Skills for JavaScript: Review and Test Templates
Reusable Claude skills for JavaScript cover async code review, module boundary checks, and test coverage planning. Lessons saved in fenbs carry project-specific patterns from one session to the next.
Updated 5 min read
Claude skills for JavaScript are saved prompt instructions that apply consistent review criteria to async code, module structure, and test coverage. Call them by name in a Claude Project instead of retyping the JavaScript-specific checklist each session.
Tools like fenbs store the project conventions and lessons from past bugs. A connected assistant that reads those before running a skill applies your team's actual standards rather than generic JavaScript advice.
Why JavaScript needs its own review criteria
JavaScript has a distinct set of failure modes that a general code review prompt does not check for specifically. Unhandled Promise rejections can crash a Node.js process silently. Async functions that mix callback patterns with await produce confusing error behavior. Implicit type coercions in comparisons are a persistent source of logic bugs.
Module structure problems show up differently than in statically typed languages. Internal helper functions accidentally exported create coupling that is hard to remove later. Circular imports are easy to introduce and hard to find without tooling. A module that does too many things creates a testing surface that grows without bounds.
The skills below cover three areas: async and Promise handling, module boundary review, and test coverage planning. Each targets the JavaScript-specific failure modes rather than general code quality, which most linters and type checkers already cover. You can link them in a short workflow: review async, review module boundary, plan tests, then write.
A skill for reviewing async JavaScript
Async bugs are among the hardest to reproduce in JavaScript. A floating Promise, one that is never awaited or caught, can fail silently in production while tests pass. This skill checks for the most common async mistakes before a change reaches review.
Review the following JavaScript code for async and Promise issues.
Code:
{{paste the relevant functions or module}}
Check each item and mark Pass, Fail, or Not applicable:
Promise handling:
- [ ] All Promises are awaited, returned, or explicitly handled
- [ ] No floating Promises (Promise calls with no await and no .catch)
- [ ] Rejection handlers are present in all async paths
- [ ] Promise.all is used for parallel independent operations, not sequential awaits
async/await patterns:
- [ ] No mixing of callbacks and await in the same function
- [ ] Error boundaries (try/catch) are at the right level
- [ ] async functions do not return void where the caller expects a value
- [ ] Loops use for...of with await, not forEach with async
Race conditions:
- [ ] State mutations inside async functions are safe under concurrent calls
- [ ] No assumption that async operations complete in a fixed order
For each Fail, write one sentence on the problem and one sentence on how to fix it.
End with: Safe to ship: Yes | No | With changes.The forEach with async check is one of the most commonly missed. array.forEach(async item => { ... }) does not wait for the async callbacks to complete. The outer function returns before any of the Promises resolve, which means errors are swallowed and results are lost. Using for...of with await is the correct pattern.
The race condition check requires more context than the others. If the function is called from one place, concurrent calls may not be a real risk. If it is called from an event handler or an API endpoint that can fire rapidly, concurrent state mutations are worth examining.
A skill for reviewing module boundaries
Module boundary problems in JavaScript often appear as unwanted coupling. An internal helper function that gets exported becomes part of the public API before anyone intended it to be. Other modules start importing it. When it needs to change, those imports become a source of breakage.
Circular dependencies are a second common problem. Module A imports from module B, and module B imports from module A. In CommonJS this often works until it does not, because of load-order effects. In ESM it fails earlier and more explicitly. Neither situation is easy to fix after the dependency graph grows.
Review the module boundary of the following JavaScript change.
Module name: {{file path or module name}}
Exports (list the named and default exports):
{{paste the export statements}}
Imports of this module in other files (if known):
{{paste any import statements from other files, or write "unknown"}}
Check:
- [ ] Exports represent the module's public API, not its implementation details
- [ ] No internal helper functions exported without a clear reason
- [ ] No circular dependencies introduced (A imports B, B imports A)
- [ ] The module's single responsibility is clear from its exports
- [ ] No side effects on import (no code running at module evaluation time without intent)
For each issue: Location | Problem (one sentence) | Suggested fix (one sentence).
End with: Boundary is clean: Yes | No | With changes.The side effects on import check matters most in shared utility modules. A module that starts a timer, opens a connection, or modifies global state when it is first imported creates problems for test isolation. Tests that import the module trigger the side effect, which makes them harder to run in isolation.
A skill for planning test coverage
A test coverage planning skill helps you think through what to test before writing a single line of test code. This is more valuable than it sounds. Without a plan, tests tend to cover the happy path and the scenarios the developer thought of during writing. The edge cases that actually cause bugs are the ones that are easy to overlook.
For JavaScript, async tests deserve their own section in the plan. A test that uses done callbacks or wraps everything in runBlocking may not correctly capture async failure paths. Modern test frameworks like Vitest and Jest support async/await in test functions directly, which is clearer and catches more failure modes.
Plan test coverage for the following JavaScript change.
Change description: {{what the change does}}
Function or module under test: {{name and brief description}}
External dependencies: {{APIs, databases, timers, events it touches}}
Output:
Unit tests (pure functions, no dependencies):
- Function: [name] | Case: [description] | Expected: [outcome]
Async tests:
- Case: [description] | Setup: [mocks or stubs needed] | Expected: [outcome]
- Include: success path, rejection path, timeout if applicable
Edge cases:
- [empty inputs, null, undefined, boundary values, concurrent calls]
Mocking strategy:
- [what to mock and why]
Tests to check in regression:
- [existing test files or suites likely affected]The mocking strategy section is worth reading carefully. Over-mocking is a common test quality problem: tests pass because all the interesting behavior is mocked away, not because the code works. If the mocking strategy section shows that nearly everything is mocked, the tests may be testing the mock rather than the code.
Keep your JavaScript skills and project patterns in one place
Save the async review, module boundary, and test coverage skills in fenbs Skills and prompts. Add the project's async conventions and module structure rules as Decisions and rules. Lessons from past async bugs let the next review check the exact failure modes your codebase has already encountered.
Create a free accountFree for one person · No credit card · Works with Claude, ChatGPT, Cursor and more
How lessons improve the skills over time
After a bug reaches production, record what the review missed and which pattern caused it. If a floating Promise caused a silent failure, add a lesson: "The async review skill missed a floating Promise in an event handler callback. Check all async callbacks in event listeners explicitly." The next review looks for it.
Lessons also apply to the test coverage skill. If a test plan missed a concurrent call edge case that caused a race condition in production, record that. The next test planning session for similar code includes concurrent call cases without prompting. Over time the skills become tuned to the failure modes your codebase actually encounters, not the ones that appear in generic checklists.
How to do this with fenbs
- Create a free account and add a project for the JavaScript codebase or team.
- Add each skill to Skills and prompts: "Async review", "Module boundary review", "Test coverage plan".
- Add the project's async conventions and module structure rules as Decisions and rules.
- Connect Claude over MCP from Integrations. Ask Claude to read the conventions before running a review skill.
- After each bug, add a lesson: what the review missed, which pattern caused it, what to check next time.
fenbs does not connect to your CI pipeline or test runner. It stores the skills and the accumulated lessons that make each review better than the last. For the general skill writing process, see how to create a Claude skill. For how skills fit with Projects and Artifacts, see Claude Projects vs Skills vs Artifacts. See Claude skills for project management for using skills across a team.