ProvenPin Install

Vue 3 + Pinia store and component tests with @pinia/testing (Vitest): working versions (tested 2026-10-15)

Test a Pinia setup store directly and a Vue 3 component that uses it with @vue/test-utils and createTestingPinia (stubbed actions, initial state), on jsdom.

passed4 passed · 0 failed2026-10-15 13:26 UTC
Status
passed
Last passed
2026-10-15 13:26 UTC
Tests
4 / 4
Language
TypeScript
Runtime
node v22.23.3
pinned versions7
vue@3.5.44pinia@4.1.0@types/node@24.19.2vitest@5.0.4@pinia/testing@2.0.2@vue/test-utils@2.5.1jsdom@30.1.3
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38741369695

The code

Exactly the files that passed. Your agent can pull them with get_recipe("vue-pinia-testing") (install), or see them on GitHub.

package.json
{
  "name": "vue-pinia-testing",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "vitest run --reporter=default --reporter=json --outputFile=test-report.json"
  },
  "dependencies": {
    "vue": "3.5.44",
    "pinia": "4.1.0"
  },
  "devDependencies": {
    "@types/node": "24.19.2",
    "vitest": "5.0.4",
    "@pinia/testing": "2.0.2",
    "@vue/test-utils": "2.5.1",
    "jsdom": "30.1.3"
  }
}
vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({ test: { environment: "jsdom" } });
src/cart.ts
import { defineStore } from "pinia";
import { computed, ref } from "vue";

export const useCart = defineStore("cart", () => {
  const items = ref<{ sku: string; price: number; qty: number }[]>([]);
  const total = computed(() => items.value.reduce((n, i) => n + i.price * i.qty, 0));
  function add(sku: string, price: number) {
    const hit = items.value.find((i) => i.sku === sku);
    if (hit) hit.qty++; else items.value.push({ sku, price, qty: 1 });
  }
  async function checkout(api: (items: unknown) => Promise<string>) {
    const id = await api(items.value);
    items.value = [];
    return id;
  }
  return { items, total, add, checkout };
});
src/CartBadge.ts
import { defineComponent, h } from "vue";
import { useCart } from "./cart";

// Render function instead of an SFC so the recipe needs no Vite Vue plugin.
export const CartBadge = defineComponent({
  setup() {
    const cart = useCart();
    return () => h("div", [
      h("span", { "data-test": "total" }, `$${cart.total}`),
      h("button", { onClick: () => cart.add("mug", 10) }, "Add mug"),
    ]);
  },
});
test/cart.test.ts
import { describe, it, expect, beforeEach, vi } from "vitest";
import { setActivePinia, createPinia } from "pinia";
import { createTestingPinia } from "@pinia/testing";
import { mount } from "@vue/test-utils";
import { useCart } from "../src/cart";
import { CartBadge } from "../src/CartBadge";

describe("store", () => {
  beforeEach(() => setActivePinia(createPinia())); // fresh store per test
  it("adds and totals", () => {
    const cart = useCart();
    cart.add("mug", 10); cart.add("mug", 10); cart.add("tee", 25);
    expect(cart.total).toBe(45);
  });
  it("checkout clears items", async () => {
    const cart = useCart();
    cart.add("mug", 10);
    expect(await cart.checkout(async () => "ord_1")).toBe("ord_1");
    expect(cart.items).toEqual([]);
  });
});

describe("component", () => {
  it("renders from initial state with stubbed actions", async () => {
    const w = mount(CartBadge, { global: { plugins: [createTestingPinia({ createSpy: vi.fn, initialState: { cart: { items: [{ sku: "tee", price: 25, qty: 2 }] } } })] } });
    expect(w.get("[data-test=total]").text()).toBe("$50");
    await w.get("button").trigger("click");
    expect(useCart().add).toHaveBeenCalledWith("mug", 10);
    expect(w.get("[data-test=total]").text()).toBe("$50"); // actions are stubbed
  });
  it("real actions with stubActions: false", async () => {
    const w = mount(CartBadge, { global: { plugins: [createTestingPinia({ createSpy: vi.fn, stubActions: false })] } });
    await w.get("button").trigger("click");
    expect(w.get("[data-test=total]").text()).toBe("$10");
  });
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.