Agent skill
testing
Esposter Vitest testing conventions — describe with function refs, canonical test values, takeOne for array access, destructuring from stores/composables, and the Windows UnoCSS test-skip rule. Apply when writing .test.ts files.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/testing-esposter-esposter
SKILL.md
Testing Conventions (Vitest)
describe(functionRef, ...)— pass the function reference directly, not a string name. Only use a string when there is no importable function reference (e.g. methods on a composable's return object).- Declare
constinsidedescribe— all shared test constants (e.g.HEADER, reusable values) must be declared inside thedescribecallback scope, not at module level, so they are scoped and cleaned up correctly. expect.hasAssertions()— always include at the top of every test body.- Canonical test values — always use minimal, meaningful values:
- Boolean:
"true","false"— test both together in one test - Integer:
"0"/ number0 - Decimal:
"0.1"/ number0.1 - Negative:
"-1"/ number-1 - NaN:
String(Number.NaN) - Date (epoch):
"1970-01-01"(YYYY-MM-DD); second date:"1970-01-02" - String:
""as base value; use" "for a different value. Only use"a"when a space would be trimmed to""(making it identical to base). Never use named strings like"Alice"/"Bob". - Object keys in tests: use
""as base key," "as a second key — never use semantic names like"name"/"age". - Number diff values:
0,1,2, etc. - Non-existent / sentinel values: use
"-1"for a nonexistent string ID,-1for a nonexistent numeric ID. Never use verbose strings like"non-existent-id","nonexistent","some-id","fake-...", etc. - Entity fields: use the field name as the literal value —
const partitionKey = "partitionKey",const rowKey = "rowKey",const message = "message". Usecrypto.randomUUID()for ID fields (userId,partitionKeywhen used as a room/entity ID, route params) to match real-world UUID-based IDs. Never inline constructor args — always declare shared constants and reference them.
- Boolean:
- Date format tests — when testing all date formats, use a
for...ofloop inside a single test, converting epoch viadayjs("1970-01-01", "YYYY-MM-DD", true).format(format). Never usetest.eachfor date format iteration. - Interpolated descriptions — use template literals with enum values:
`boolean returns ${ColumnType.Boolean}`. - Human-readable names — use plain English: "integer", "decimal", "negative", "epoch date", "NaN".
- Array index access — always use
takeOne(arr, index)from@esposter/sharedinstead ofarr[index]orarr[index]?.—noUncheckedIndexedAccessmakes direct index access returnT | undefined, andtakeOnethrows on out-of-bounds while keeping the type non-nullable. - Destructure from stores and composables — always destructure return values:
const { deleteRow, undo, isUndoable } = operationsrather than callingoperations.deleteRow(...). Same for stores:const { editedItem } = storeToRefs(store)andconst { methodName } = store. This applies insidebeforeEachtoo — never chainuseX().method()inline; alwaysconst { method } = useX()first. - Cloning in tests — use
structuredClone(obj)for deep clones; useObject.assign(structuredClone(obj), { ...updates })to clone and override fields. Never use{ ...spread }syntax to clone — it creates a plain object losing the prototype. Passnew Foo({ ... })directly when a fresh instance already suffices (no need to clone or spread it). - Assertions after all assignments — put all
expectandexpectToBeDefinedcalls after all operation calls and local assignments for that phase, separated by a blank line. For multi-phase tests (e.g. undo then redo), each phase is its own block: operations +const local = reactive.value?.x, blank line, then assertions onlocal. Never interleave expects with assignments. - Always use
toStrictEqual— never usetoEqual.toStrictEqualchecks object types and class instances correctly;toEqualsilently ignores prototype differences. - Minimize per-test setup — declare shared mutable state (
source,callback,cleanup, etc.) asletvariables insidedescribe, initialize them inbeforeEach. Mount helpers should take no arguments when all state is pre-initialized. Only reassign in the test body when a test needs a different variant (e.g.callback = vi.fn(() => cleanup)for cleanup tests). - Reuse test utilities — always check
testUtils.test.tsfor existing helpers (e.g.makeDataSource,makeRow,makeColumn,makeNumberColumn,setupWithDataSource) before writing local equivalents.
Running Validation Commands
- Always run
pnpm lint,pnpm typecheck, and test commands in the background — userun_in_background: trueon the Bash tool so the main conversation is not blocked. These commands can take over 2 minutes. Continue addressing other tasks while waiting for results.
Running Tests
- Do not run tests on Windows — Vitest currently fails on Windows with
TypeError: The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received 'file:///__uno.css'. This is a known environment issue with UnoCSS + happy-dom. Write tests but skip running them; the user runs them manually.
Testing Composables with Lifecycle Hooks
Composables that use onMounted/onUnmounted require a component lifecycle to trigger. Use mountSuspended from @nuxt/test-utils/runtime with a minimal wrapper:
import type { VueWrapper } from "@vue/test-utils";
import { mountSuspended } from "@nuxt/test-utils/runtime";
describe(useMyComposable, () => {
let wrapper: VueWrapper;
const mountComposable = async () => {
wrapper = await mountSuspended(defineComponent({ render: () => h("div"), setup: () => useMyComposable() }));
};
afterEach(() => {
wrapper?.unmount();
});
test("example", async () => {
expect.hasAssertions();
await mountComposable();
await flushPromises();
// assertions...
});
});
- Always unmount in
afterEachto triggeronUnmountedcleanup - When re-mounting mid-test (e.g. to simulate offline restart), call
wrapper.unmount()beforeawait mountComposable()
Test Utility Files
Shared test helpers (factory functions, setup helpers, etc.) must live in .test.ts files, never plain .ts files. To prevent Vitest from treating the file as a test suite, add describe.todo("testUtils") at the very bottom of the file.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?