All skills
hyf0 avatar

/vue-testing-best-practices

@bc922e4 official
by hyf0hyf0/vue-skills2.9k stars
167

Use for Vue.js testing. Covers Vitest, Vue Test Utils, component testing, mocking, testing patterns, and Playwright for E2E testing.

Use this Skill: https://skilld.dev/gh/hyf0/vue-skills/vue-testing-best-practices

This session only. Nothing lands on disk.

referencetesting-component-blackbox-approach.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Test Components Using Blackbox Approach - Focus on Behavior Not Implementation

Impact: HIGH - Tests that rely on implementation details (internal state, private methods, component structure) break during refactoring even when functionality remains correct. This leads to false negatives and high test maintenance burden.

Follow Kent C. Dodds' testing philosophy: "The more your tests resemble how your software is used, the more confidence they can give you."

Task Checklist

  • Test what the component does, not how it does it
  • Query elements by user-visible attributes (text, role, testid)
  • Simulate user interactions (click, type) rather than calling methods directly
  • Assert on rendered output, emitted events, and visible state changes
  • Avoid accessing component internal state or private methods
  • Use data-testid attributes for elements without semantic meaning

Incorrect:

import { mount } from '@vue/test-utils'
import Counter from './Counter.vue'

// BAD: Testing implementation details
test('counter increments', async () => {
  const wrapper = mount(Counter)

  // Accessing internal state directly
  expect(wrapper.vm.count).toBe(0)

  // Calling internal method instead of simulating user action
  wrapper.vm.increment()

  // Checking internal state instead of visible output
  expect(wrapper.vm.count).toBe(1)
})

// BAD: Testing component structure
test('has increment button', () => {
  const wrapper = mount(Counter)

  // Testing implementation detail - what if button becomes an anchor?
  expect(wrapper.find('button').exists()).toBe(true)
})

Correct:

import { mount } from '@vue/test-utils'
import Counter from './Counter.vue'

// CORRECT: Testing behavior like a user would
test('counter displays updated value after clicking increment', async () => {
  const wrapper = mount(Counter, {
    props: { max: 10 }
  })

  // Assert initial visible state
  expect(wrapper.find('[data-testid="counter-value"]').text()).toContain('0')

  // Simulate user action
  await wrapper.find('[data-testid="increment-button"]').trigger('click')

  // Assert visible result
  expect(wrapper.find('[data-testid="counter-value"]').text()).toContain('1')
})

// CORRECT: Testing emitted events (public API)
test('emits change event with new value when incremented', async () => {
  const wrapper = mount(Counter)

  await wrapper.find('[data-testid="increment-button"]').trigger('click')

  expect(wrapper.emitted('change')).toHaveLength(1)
  expect(wrapper.emitted('change')[0]).toEqual([1])
})

Using @testing-library/vue for Better Blackbox Tests

import { render, screen, fireEvent } from '@testing-library/vue'
import Counter from './Counter.vue'

// Testing Library encourages accessible, user-centric queries
test('increments counter on button click', async () => {
  render(Counter)

  // Query by role - how screen readers see it
  const button = screen.getByRole('button', { name: /increment/i })
  const display = screen.getByText('0')

  await fireEvent.click(button)

  expect(screen.getByText('1')).toBeInTheDocument()
})

What to Test vs What Not to Test

DO Test (Public Interface)

// Props affect rendered output
test('shows title from props', () => {
  const wrapper = mount(Card, {
    props: { title: 'Hello World' }
  })
  expect(wrapper.text()).toContain('Hello World')
})

// Slots render correctly
test('renders slot content', () => {
  const wrapper = mount(Card, {
    slots: { default: '<p>Slot content</p>' }
  })
  expect(wrapper.text()).toContain('Slot content')
})

// Emitted events
test('emits close event when X clicked', async () => {
  const wrapper = mount(Modal)
  await wrapper.find('[data-testid="close-button"]').trigger('click')
  expect(wrapper.emitted('close')).toBeTruthy()
})

DON'T Test (Implementation Details)

// Don't test internal computed properties
// Don't test internal methods
// Don't test component options/setup internals
// Don't test that specific child components are rendered (unless critical)
// Don't rely exclusively on snapshot tests for correctness

Reference

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides standard documentation, configuration guidelines, and best practices for testing Vue 3 applications with Vitest, Vue Test Utils, and Playwright. No security vulnerabilities or malicious patterns were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    1/12 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at bc922e4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 8 months ago
version
1.0.0
author
github.com/vuejs-ai
  • Vue
  • Testing
  • vitest
  • vue-test-utils
  • playwright
  • e2e-testing
  • composables
  • pinia
  • component-testing
  • mocking

README badge

README badge for hyf0/vue-skills/vue-testing-best-practices

Covers Vue 3 testing patterns and infrastructure with Vitest, Vue Test Utils, and Playwright, including component testing, composables, Pinia integration, and E2E testing. Addresses common gotchas like async race conditions, lifecycle hook testing, and Suspense components.

Generated from the current SKILL.md.

Does this skill cover unit testing, component testing, and E2E testing?
Yes. It covers unit testing with Vitest, component testing with Vue Test Utils, composables testing with helper wrappers, and E2E testing with Playwright.
What testing framework does this skill recommend for Vue 3?
Vitest is recommended for unit and component testing. Playwright is recommended for end-to-end testing.
Does this address Pinia store testing?
Yes. The skill includes guidance on setting up Pinia stores in tests and resolving injection Symbol errors.
Does this cover testing async components and Suspense?
Yes. It includes patterns for testing components with async setup, Suspense boundaries, and defineAsyncComponent.
Does this address flaky tests caused by race conditions?
Yes. The skill covers async/await patterns and flushing promises to handle race conditions and intermittent test failures.

Generated from the current SKILL.md. These answers refresh after source changes.