PluginBench
Skill
Official
Pass
Audit score 90

unit-test-vue-pinia

github/awesome-copilot

Write and review unit tests for Vue 3 + TypeScript + Vitest + Pinia codebases with behavior-first patterns.

What is unit-test-vue-pinia?

This skill helps you create or review unit tests for Vue components, composables, and Pinia stores. It enforces behavior-oriented testing, black-box assertions, and proper use of createTestingPinia, Vue Test Utils, and Vitest patterns to keep tests small, deterministic, and maintainable.

  • Create unit tests for Vue 3 components, composables, and Pinia stores
  • Mock Pinia stores with createTestingPinia and configure action spies, initial state, and plugins
  • Apply Vue Test Utils patterns: shallow mounting, prop/event-driven behavior, emitted event assertions
  • Write behavior-first tests that assert observable outputs (rendered text, emitted events, store state) over implementation details
  • Review existing tests for brittleness, implementation coupling, and missing coverage
  • Set up pure store unit tests with createPinia() when component rendering is not needed

How to install unit-test-vue-pinia

npx skills add https://github.com/github/awesome-copilot --skill unit-test-vue-pinia
Prerequisites
  • Vue 3 project with TypeScript
  • Vitest configured as test runner
  • Pinia store setup
  • Vue Test Utils installed
  • references/pinia-patterns.md checked into your project (recommended)
Claude Code
Cursor
Windsurf
Cline

How to use unit-test-vue-pinia

  1. 1.Identify the behavior boundary you want to test: component UI behavior, composable logic, or store state transitions
  2. 2.Choose the narrowest test style (component mount, composable setup, or pure store test) that proves that behavior
  3. 3.Set up Pinia using createTestingPinia with createSpy: vi.fn for action assertions, or createPinia() for pure store tests
  4. 4.Trigger behavior through public inputs: props, form updates, button clicks, emitted child events, or store API calls
  5. 5.Assert observable outputs first: rendered text, emitted events, callback calls, and store state changes
  6. 6.Name the test to describe the behavior, not the implementation; note any remaining coverage gaps

Use cases

Good for
  • Create a new test suite for a Vue component that dispatches Pinia store actions and asserts emitted events
  • Review a test that directly accesses wrapper.vm and refactor it to use DOM or event assertions
  • Set up a test for a composable that depends on multiple Pinia stores with seeded initial state
  • Write tests for a form component that updates store state and validates user input behavior
  • Verify that a component correctly calls a store action with the right payload when a button is clicked
Who it's for
  • Vue 3 + TypeScript developers writing unit tests
  • QA engineers reviewing test coverage and test quality
  • Teams using Vitest and Pinia in their Vue codebases
  • Developers transitioning from implementation-coupled to behavior-oriented testing

unit-test-vue-pinia FAQ

When should I use createTestingPinia vs. createPinia?

Use createTestingPinia when you need stubbed dependent stores, seeded test doubles, or action spies. Use createPinia() for pure store unit tests that validate state transitions and action behavior without component rendering.

Should I always use createSpy: vi.fn in createTestingPinia?

Use createSpy: vi.fn when action spy assertions are part of your test intent. Omit it if the test only needs state seeding or action stubbing without inspecting generated spies.

Is it wrong to access wrapper.vm in a test?

Accessing wrapper.vm should be exceptional. Prefer DOM assertions, emitted event assertions, prop assertions, or store-level assertions. Only use wrapper.vm when no reasonable public input/output assertion can express the behavior.

How do I test a component that emits an event with a payload?

Trigger the behavior (e.g., button click), then assert the emitted event and payload: expect(wrapper.emitted('submit')?.[0]?.[0]).toBe(expectedValue).

Should I test implementation details like internal state or private methods?

No. Test only observable behavior: rendered output, emitted events, store state changes, and side effects. Avoid assertions on private/internal implementation details.

Full instructions (SKILL.md)

Source of truth, from github/awesome-copilot.


name: unit-test-vue-pinia category: testing description: 'Write and review unit tests for Vue 3 + TypeScript + Vitest + Pinia codebases. Use when creating or updating tests for components, composables, and stores; mocking Pinia with createTestingPinia; applying Vue Test Utils patterns; and enforcing black-box assertions over implementation details.'

unit-test-vue-pinia

Use this skill to create or review unit tests for Vue components, composables, and Pinia stores. Keep tests small, deterministic, and behavior-first.

Workflow

  1. Identify the behavior boundary first: component UI behavior, composable behavior, or store behavior.
  2. Choose the narrowest test style that can prove that behavior.
  3. Set up Pinia with the least powerful option that still covers the scenario.
  4. Drive the test through public inputs such as props, form updates, button clicks, emitted child events, and store APIs.
  5. Assert observable outputs and side effects before considering any instance-level assertion.
  6. Return or review tests with clear behavior-oriented names and note any remaining coverage gaps.

Core Rules

  • Test one behavior per test.
  • Assert observable input/output behavior first (rendered text, emitted events, callback calls, store state changes).
  • Avoid implementation-coupled assertions.
  • Access wrapper.vm only in exceptional cases when there is no reasonable DOM, prop, emit, or store-level assertion.
  • Prefer explicit setup in beforeEach() and reset mocks every test.
  • Use checked-in reference material in references/pinia-patterns.md as the local source of truth for standard Pinia test setups.

Pinia Testing Approach

Use references/pinia-patterns.md first, then fall back to Pinia's testing cookbook when the checked-in examples do not cover the case.

Default pattern for component tests

Use createTestingPinia as a global plugin while mounting. Prefer createSpy: vi.fn as the default for consistency and easier action-spy assertions.

const wrapper = mount(ComponentUnderTest, {
	global: {
		plugins: [
			createTestingPinia({
				createSpy: vi.fn,
			}),
		],
	},
});

By default, actions are stubbed and spied. Use stubActions: true (default) when the test only needs to verify whether an action was called (or not called).

Accepted minimal Pinia setups

The following are also valid and should not be flagged as incorrect:

  • createTestingPinia({}) when the test does not assert Pinia action spy behavior.
  • createTestingPinia({ initialState: ... }) or createTestingPinia({ stubActions: ... }) without createSpy, when the test only needs state seeding or action stubbing behavior and does not inspect generated spies.
  • setActivePinia(createTestingPinia(...)) in store/composable-focused tests (without mounting a component) when mocking/seeding dependent stores is needed.

Use createSpy: vi.fn when action spy assertions are part of the test intent.

Execute real actions only when needed

Use stubActions: false only when the test must validate the action's real behavior and side effects. Do not switch it on by default for simple "was called" assertions.

const wrapper = mount(ComponentUnderTest, {
	global: {
		plugins: [
			createTestingPinia({
				createSpy: vi.fn,
				stubActions: false,
			}),
		],
	},
});

Seed store state with initialState

const wrapper = mount(ComponentUnderTest, {
	global: {
		plugins: [
			createTestingPinia({
				createSpy: vi.fn,
				initialState: {
					counter: { n: 20 },
					user: { name: "Leia Organa" },
				},
			}),
		],
	},
});

Add Pinia plugins through createTestingPinia

const wrapper = mount(ComponentUnderTest, {
	global: {
		plugins: [
			createTestingPinia({
				createSpy: vi.fn,
				plugins: [myPiniaPlugin],
			}),
		],
	},
});

Getter override pattern for edge cases

const pinia = createTestingPinia({ createSpy: vi.fn });
const store = useCounterStore(pinia);

store.double = 999;
// @ts-expect-error test-only reset of overridden getter
store.double = undefined;

Pure store unit tests

Prefer pure store tests with createPinia() when the goal is to validate store state transitions and action behavior without component rendering. Use createTestingPinia() only when you need stubbed dependent stores, seeded test doubles, or action spies.

beforeEach(() => {
	setActivePinia(createPinia());
});

it("increments", () => {
	const counter = useCounterStore();
	counter.increment();
	expect(counter.n).toBe(1);
});

Vue Test Utils Approach

Follow Vue Test Utils guidance: https://test-utils.vuejs.org/guide/

  • Mount shallow by default for focused unit tests.
  • Mount full component trees only when integration behavior is the subject.
  • Drive behavior through props, user-like interactions, and emitted events.
  • Prefer findComponent(...).vm.$emit(...) for child stub events instead of touching parent internals.
  • Use nextTick only when updates are async.
  • Assert emitted events and payloads with wrapper.emitted(...).
  • Access wrapper.vm only when no DOM assertion, emitted event assertion, prop assertion, or store-level assertion can express the behavior. Treat it as an exception and keep the assertion narrowly scoped.

Key Testing Snippets

Emit and assert payload:

await wrapper.find("button").trigger("click");
expect(wrapper.emitted("submit")?.[0]?.[0]).toBe("Mango Mission");

Update input and assert output:

await wrapper.find("input").setValue("Agent Violet");
await wrapper.find("form").trigger("submit");
expect(wrapper.emitted("save")?.[0]?.[0]).toBe("Agent Violet");

Test Writing Workflow

  1. Identify the behavior boundary to test.
  2. Build minimal fixture data (only fields needed by that behavior).
  3. Configure Pinia and required test doubles.
  4. Trigger behavior through public inputs.
  5. Assert public outputs and side effects.
  6. Refactor test names to describe behavior, not implementation.

Constraints and Safety

  • Do not test private/internal implementation details.
  • Do not overuse snapshots for dynamic UI behavior.
  • Do not assert every field in large objects if only one behavior matters.
  • Keep fake data deterministic; avoid random values.
  • Do not claim a Pinia setup is wrong when it is one of the accepted minimal setups above.
  • Do not rewrite working tests toward deeper mounting or real actions unless the behavior under test requires that extra surface area.
  • Flag missing test coverage, brittle selectors, and implementation-coupled assertions explicitly during review.

Output Contract

  • For create or update, return the finished test code plus a short note describing the selected Pinia strategy.
  • For review, return concrete findings first, then missing coverage or brittleness risks.
  • When the safest choice is ambiguous, state the assumption that drove the chosen test setup.

References