本文へ移動
cccskills
無料GitHub で公開

web-testing-vue-test-utils

Vue Test Utils — mount vs shallowMount, the wrapper API, awaiting DOM updates, flushPromises, testing composables, and the global mounting options. Load when writing or reviewing tests that mount Vue components.

インストール方法を見る

含まれるファイル(7)

  • SKILL.md11.1 KB
  • examples/async.md9.3 KB
  • examples/composables.md8.4 KB
  • examples/core.md7.8 KB
  • examples/mocking.md10.2 KB
  • metadata.yaml354 B
  • reference.md6.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Vue Test Utils Patterns

Quick Guide: mount() renders a component with its children; shallowMount() stubs them all and is the exception rather than the default. Query with get() when the element must exist and find() when it may not, using data-test attributes rather than classes. Every DOM-updating method returns a promise and is awaited; anything Vue's reactivity does not track — a request, a timer — needs flushPromises() as well. A component's environment arrives through the global mounting options.

Detailed Resources:

  • examples/core.md — mounting, slots, get/find/findAll, trigger, setValue
  • examples/async.md — flushPromises, nextTick, debounced input, async setup() under Suspense
  • examples/composables.md — through a component, in isolation, and with injected dependencies
  • examples/mocking.md — the four global seams: plugins, stubs, mocks, provide — and a custom mount that composes them
  • reference.md — wrapper API tables, mounting options, emitted-event patterns, debug checklist

Which path applies

  • A component is the subject — mount it and drive the wrapper; examples/core.md.
  • A composable is the subject — mount a minimal component that calls it, so it runs inside a real setup scope; examples/composables.md. Calling a composable outside a component works only for ones that register no lifecycle hooks and inject nothing.
  • The subject has an async setup() — it must be mounted inside Suspense, or it never resolves; examples/async.md.

<critical_requirements>

Before writing Vue Test Utils code

Await every DOM-updating method — trigger(), setValue(), setProps(), setData(). Each returns a promise that resolves after Vue has flushed, so an un-awaited call leaves the assertion looking at the pre-update DOM.

Call flushPromises() after anything Vue's reactivity does not own — a request, a timer callback, a promise chain started in onMounted. Awaiting the interaction flushes Vue's queue and nothing else.

Reach for mount() first, and treat shallowMount() as the exception. Stubbing every child changes how the component behaves, so a shallow test passes for a tree that does not render.

Select with data-test attributes. Classes and ids belong to styling and move under a restyle; a data-test attribute is a stated contract that a reader can see is load-bearing.

Supply the component's environment through the global mounting options — plugins, stubs, mocks, provide. That is the seam the library gives you, and it keeps the arrangement visible at the mount rather than hidden in module-level substitution.

</critical_requirements>


Auto-detection: @vue/test-utils, mount, shallowMount, VueWrapper, DOMWrapper, wrapper.get, wrapper.find, findAll, findComponent, findAllComponents, getComponent, trigger, setValue, setProps, setData, flushPromises, emitted, enableAutoUnmount, attachTo, renderStubDefaultSlot, config.global

Applies to:

  • Mounting a Vue component and asserting on what it rendered
  • Driving clicks, typing, selection and keyboard events through the wrapper
  • Asserting on emitted events and their payloads
  • Deciding between full mount, selective stubs and shallow rendering
  • Testing a composable, in a component or in isolation
  • Supplying plugins, stubs, global properties and injected values at mount time

Handled elsewhere:

  • Test runner mechanics — the file's describe/it, the assertion API, module substitution, mock functions and fake timers all belong to whatever runs the file
  • Store design and its own test helpers — a store's testing plugin is installed through global.plugins, and how to configure it is settled by whoever owns the store
  • Route definition and navigation guards — a router installs as a plugin like any other
  • Journeys spanning navigations and a real backend — browser-driven end-to-end coverage
  • Whether the rendered result still looks right — pixel comparison against an approved image

<philosophy>

Philosophy

Vue's DOM updates are asynchronous, and the library's API is shaped around that one fact. trigger, setValue, setProps and setData all return promises for the same reason: the effect of the change is not observable on the line after it. Most flaky Vue component tests are a missing await on one of those four.

Two async queues, two tools. Awaiting a wrapper method flushes Vue's own render queue. flushPromises() drains the microtask queue, which is where a resolved request or a settled promise chain is waiting. A component that fetches on mount needs the second even though nothing was triggered.

Stubbing is a dial, not a switch. shallowMount is the far end of it — every child replaced, slots inert, integration coverage gone. Stubbing the one heavy child by name keeps the rest of the tree real and usually solves the actual problem, which is a chart library or a network call rather than depth.

</philosophy>
<patterns>

Core patterns

Pattern 1: Mounting

import { mount, shallowMount } from "@vue/test-utils";

// Default: children render, slots work, events bubble
const wrapper = mount(TodoList, {
  props: { todos: [{ id: 1, text: "Test", done: false }] },
});

// Every child stubbed - reach for this only when depth itself is the problem
const shallow = shallowMount(TodoList, { props: { todos: [] } });

// Usually better than shallow: stub the one child that misbehaves
const selective = mount(Dashboard, {
  global: { stubs: { HeavyChartWidget: { template: "<div />" } } },
});

Full code: examples/core.md

Pattern 2: Querying the Wrapper

get* throws with a useful message when the element is missing; find* returns an empty wrapper you then check with .exists(). The same split applies to getComponent / findComponent.

const input = wrapper.get('[data-test="search-input"]'); // must exist
expect(wrapper.find('[data-test="error"]').exists()).toBe(false); // may not exist
expect(wrapper.findAll('[data-test="result"]')).toHaveLength(3);

expect(wrapper.getComponent(ChildComponent).props("message")).toBe("Hello");

Using find() where get() was meant is the quiet failure: the empty wrapper satisfies nothing, and the assertion after it reports a confusing type error rather than "element not found".

Full code: examples/core.md

Pattern 3: Interaction and Emitted Events

await wrapper.get('[data-test="email"]').setValue("test@example.com");
await wrapper.get('[data-test="form"]').trigger("submit.prevent");

expect(wrapper.emitted("submit")).toBeTruthy();
expect(wrapper.emitted("submit")![0]).toEqual([{ email: "test@example.com" }]);

emitted() accumulates across the whole test, so index into it rather than asserting on the array as a whole after several interactions.

Full code: examples/core.md

Pattern 4: flushPromises for Untracked Async

import { mount, flushPromises } from "@vue/test-utils";

const wrapper = mount(UserProfile, { props: { userId: 1 } });

expect(wrapper.find('[data-test="loading"]').exists()).toBe(true);

await flushPromises(); // the request settles, then Vue re-renders

expect(wrapper.get('[data-test="user-name"]').text()).toBe("John Doe");

flushPromises() drains microtasks only. A setTimeout needs the runner's fake timers advanced first, and then flushPromises() for whatever the callback started.

Full code: examples/async.md

Pattern 5: Testing Composables

Mount a component whose only job is to call the composable, so lifecycle hooks and inject work as they do in production.

function withSetup<T>(composable: () => T) {
  let result!: T;
  const wrapper = mount(
    defineComponent({ setup: () => ((result = composable()), () => null) }),
  );
  return { result, unmount: () => wrapper.unmount() };
}

const { result, unmount } = withSetup(() =>
  useLocalStorage("draft", "initial"),
);

Where the composable is inseparable from its UI, render a small template around it and assert on the DOM instead — the reactivity is then covered rather than assumed.

Full code: examples/composables.md

Pattern 6: The global Mounting Options

Four seams, each for a different kind of dependency, all set at the mount and all settable project-wide through config.global.

mount(Component, {
  global: {
    plugins: [
      /* anything installed with app.use() - a store, a router, an i18n instance */
    ],
    stubs: { RouterLink: true, HeavyChart: { template: "<div />" } },
    mocks: { $t: (key: string) => key }, // global properties the template reads
    provide: { [THEME_KEY]: { theme: ref("light") } }, // what an ancestor would provide
  },
});

Wrap these in a custom mount once, so a test states only what makes it different.

Full code: examples/mocking.md

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • A trigger(), setValue(), setProps() or setData() without await — the assertion reads the DOM before Vue has flushed, so the test passes or fails by timing
  • No flushPromises() after a request resolves — the loading branch is still rendered when the assertion runs
  • setData() on a component written with the Composition API — it only reaches an Options API data() function, so the call silently changes nothing
  • A component with an async setup() mounted directly instead of inside Suspense — it never resolves and the wrapper stays on the fallback
  • isVisible() without attachTo: document.body — the element is not in a rendered document, so visibility cannot be computed correctly
  • trigger("click") on a disabled element — the browser drops it, and so does the library; that is correct behaviour rather than a bug to work around

Surprising behaviour:

  • shallowMount stubs every child including ones from a component library, so a test can pass against a tree that renders nothing
  • find() returns an empty wrapper rather than throwing, which turns a missing element into a confusing error one line later
  • emitted() accumulates for the lifetime of the wrapper — asserting a length after several interactions counts all of them
  • setValue() applies only to <input>, <textarea> and <select>; on anything else it is a no-op
  • trigger() already awaits nextTick, so an extra await nextTick() after it is redundant
  • Reaching into wrapper.vm to call a method or read state couples the test to the implementation; drive the component through the DOM instead
  • A wrapper mounted with attachTo stays in the document until unmounted — register enableAutoUnmount once rather than remembering per test

</red_flags>

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

日本語の概要は準備中です。原文の説明を表示しています。

agents-inc/skills242026年9月8日 更新

agents-inc のスキルをすべて見る

このスキルの問題を報告する