0Pricing
Vue Academy · Lesson

Testing User Interactions and Events

wrapper.trigger('click'), setValue(), wrapper.vm.$emit(), async flushPromises().

Testing User Interactions and Events is a free Vue Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Simulating User Behavior

Beyond rendering, tests should mimic what a user does: clicking buttons, typing into inputs, submitting forms. @vue/test-utils wrappers expose methods to dispatch DOM events and update Vue afterward.

trigger for Click Events

wrapper.trigger("click") fires a click on the element. Because it updates the DOM, it returns a promise — await it so assertions see the result.

const button = wrapper.get("button")
await button.trigger("click")
expect(wrapper.text()).toContain("Clicked once")

Why Tests Are Async

Vue updates the DOM asynchronously. After an interaction the new state is not visible until the next tick. Awaiting the trigger promise lets the DOM settle before you assert.

it("increments on click", async () => {
  const wrapper = mount(Counter)
  await wrapper.get("button").trigger("click")
  expect(wrapper.get(".count").text()).toBe("1")
})

setValue for Inputs

To type into a field, use wrapper.setValue(value) on the input wrapper. It sets the value and dispatches an input event so v-model updates.

const input = wrapper.get("input")
await input.setValue("hello@example.com")
expect(input.element.value).toBe("hello@example.com")

Checkboxes and Selects

setValue adapts to the element: pass a boolean for checkboxes and the option value for a select.

await wrapper.get("input[type=checkbox]").setValue(true)
await wrapper.get("select").setValue("tr")

Asserting Emitted Events

Components communicate up via emitted events. wrapper.emitted() returns a record of every event the component emitted, keyed by name.

await wrapper.get("button").trigger("click")
expect(wrapper.emitted()).toHaveProperty("submit")

Inspecting Emitted Payloads

wrapper.emitted("name") returns an array of emission argument-arrays. The first emission’s first argument is emitted("name")[0][0].

await wrapper.get("button").trigger("click")
const events = wrapper.emitted("submit")
expect(events).toHaveLength(1)
expect(events[0][0]).toEqual({ email: "a@b.com" })

A Form Submit Test

Combine the pieces: fill a field, submit the form, then assert the emitted payload.

it("emits submit with the email", async () => {
  const wrapper = mount(LoginForm)
  await wrapper.get("input").setValue("a@b.com")
  await wrapper.get("form").trigger("submit.prevent")
  expect(wrapper.emitted("submit")[0][0]).toEqual({ email: "a@b.com" })
})

Async Operations in Components

Many handlers call APIs and update state when the promise resolves. The microtask may not have run by the time your assertion executes, so you must wait.

async function load() {
  loading.value = true
  data.value = await fetchData()
  loading.value = false
}

flushPromises

flushPromises from Test Utils resolves all pending microtasks (then-callbacks). Await it after triggering an async action so resolved promises and the resulting DOM updates are applied.

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

await wrapper.get("button").trigger("click")
await flushPromises()
expect(wrapper.text()).toContain("Loaded")

Putting Async Tests Together

The pattern: mount, interact, await flushPromises(), assert. Mark the test function async so you can use await throughout.

it("shows results after fetch", async () => {
  const wrapper = mount(SearchBox)
  await wrapper.get("input").setValue("vue")
  await wrapper.get("form").trigger("submit.prevent")
  await flushPromises()
  expect(wrapper.findAll("li")).toHaveLength(2)
})

Quick Check

Check your understanding of interaction testing.

Recap

You learned to test interactions and events:

  • trigger("click") fires events; await it because Vue updates async.
  • setValue sets input/checkbox/select values and fires input events for v-model.
  • wrapper.emitted() records emitted events; emitted("name")[0][0] reads the first payload.
  • For async handlers, await flushPromises() before asserting.
  • Mark tests async to use await.

Frequently asked questions

Is the “Testing User Interactions and Events” lesson free?

Yes — the full text of “Testing User Interactions and Events” is free to read here on the web, and the Vue Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Vue Academy course, upgrade to CoddyKit PRO.

What will I learn in “Testing User Interactions and Events”?

wrapper.trigger('click'), setValue(), wrapper.vm.$emit(), async flushPromises(). You practise Vue Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Vue Academy?

No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Testing User Interactions and Events” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Vue Academy lesson?

Yes. Every Vue Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Vitest Setup for Vue Projects
  2. Mounting and Querying Components
  3. Testing User Interactions and Events
  4. Mocking Composables, Stores, and APIs
← Back to Vue Academy