āļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue 3 āđƒāļ™āļ›āļĩ 2026: Vitest, Vue Test Utils āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ

āļ„āļđāđˆāļĄāļ·āļ­āļ›āļāļīāļšāļąāļ•āļīāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āđƒāļ™āļ›āļĩ 2026: āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļē Vitest, āļāļēāļĢ mount āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ”āđ‰āļ§āļĒ Vue Test Utils, āļāļēāļĢāļ—āļ”āļŠāļ­āļš composable āđāļĨāļ° Pinia store, āļāļēāļĢ mock API, āļāļēāļĢāļ§āļąāļ” coverage āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ—āļĩāđˆāļ—āļĩāļĄāļœāļđāđ‰āļ§āđˆāļēāļˆāđ‰āļēāļ‡āļ–āļēāļĄāļˆāļĢāļīāļ‡

āđ€āļ§āļīāļĢāđŒāļāđ‚āļŸāļĨāļ§āđŒāļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āļ”āđ‰āļ§āļĒ Vitest āđāļĨāļ° Vue Test Utils āđƒāļ™āļ›āļĩ 2026

āļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āļ„āļ·āļ­āđ€āļŠāđ‰āļ™āđāļšāđˆāļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢ refactor āļ”āđ‰āļ§āļĒāļ„āļ§āļēāļĄāļĄāļąāđˆāļ™āđƒāļˆāļāļąāļšāļāļēāļĢāđ€āļ”āļēāļŠāļļāđˆāļĄāļ—āļĩāđˆāđ€āļ›āļĢāļēāļ°āļšāļēāļ‡ āđāļĨāļ°āđƒāļ™āļ›āļĩ 2026 āļŠāļļāļ”āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āđ„āļ”āđ‰āļĢāļ§āļĄāļ•āļąāļ§āļāļąāļ™āļĢāļ­āļšāļŠāļ­āļ‡āđ„āļĨāļšāļĢāļēāļĢāļĩāļŦāļĨāļąāļ āđ„āļ”āđ‰āđāļāđˆ Vitest āļŠāļģāļŦāļĢāļąāļšāđ€āļ›āđ‡āļ™ test runner āđāļĨāļ° Vue Test Utils āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢ mount āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āļ„āļđāđˆāļĄāļ·āļ­āļ™āļĩāđ‰āļˆāļ°āļžāļēāđ„āļĨāđˆāļ•āļąāđ‰āļ‡āđāļ•āđˆāļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļēāļŠāļļāļ”āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­ āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđāļĨāļ° composable āļāļēāļĢ mock dependency āđ„āļ›āļˆāļ™āļ–āļķāļ‡āļāļēāļĢāļ•āļ­āļšāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļĢāļ·āđˆāļ­āļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āļ—āļĩāđˆāļ—āļĩāļĄāļœāļđāđ‰āļ§āđˆāļēāļˆāđ‰āļēāļ‡āļ–āļēāļĄāļāļąāļ™āļˆāļĢāļīāļ‡

āļŠāļļāļ”āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ—āļ”āļŠāļ­āļš Vue āļĒāļļāļ„āđƒāļŦāļĄāđˆāđƒāļ™āļ›āļĩ 2026

āļ„āļģāđāļ™āļ°āļ™āļģāļĄāļēāļ•āļĢāļāļēāļ™āļˆāļēāļāđ€āļ­āļāļŠāļēāļĢ Vue āļ„āļ·āļ­āđƒāļŠāđ‰ Vitest āļŠāļģāļŦāļĢāļąāļš unit test āđāļĨāļ° component test āđƒāļŠāđ‰ Vue Test Utils āđ€āļ›āđ‡āļ™ API āļĢāļ°āļ”āļąāļšāļĨāđˆāļēāļ‡āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢ mount āđāļĨāļ°āđƒāļŠāđ‰ Playwright āļŦāļĢāļ·āļ­ Cypress āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ—āļ”āļŠāļ­āļšāđāļšāļš end-to-end āļˆāļļāļ”āđ€āļ”āđˆāļ™āļ„āļ·āļ­ Vitest āđƒāļŠāđ‰ config āđ€āļ”āļĩāļĒāļ§āļāļąāļ™āļāļąāļš Vite āļ—āļĩāđˆāđāļ­āļ›āđƒāļŠāđ‰āļ­āļĒāļđāđˆ āļ”āļąāļ‡āļ™āļąāđ‰āļ™āđ€āļ—āļŠāļ•āđŒāļˆāļķāļ‡āļ§āļīāđˆāļ‡āļœāđˆāļēāļ™ transform pipeline āļŠāļļāļ”āđ€āļ”āļĩāļĒāļ§āļāļąāļ™āđ€āļ›āđŠāļ° āļžāļĢāđ‰āļ­āļĄ hot reload āļ—āļĩāđˆāđāļ—āļšāļˆāļ°āļ—āļąāļ™āļ—āļĩ

āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļē Vitest āļŠāļģāļŦāļĢāļąāļšāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒ Vue 3

Vitest āđƒāļŠāđ‰ pipeline āļĢāđˆāļ§āļĄāļāļąāļš Vite āļŦāļĄāļēāļĒāļ„āļ§āļēāļĄāļ§āđˆāļēāđ„āļŸāļĨāđŒ config āđ€āļžāļĩāļĒāļ‡āđ„āļŸāļĨāđŒāđ€āļ”āļĩāļĒāļ§āļ‚āļąāļšāđ€āļ„āļĨāļ·āđˆāļ­āļ™āļ—āļąāđ‰āļ‡ dev server āđāļĨāļ° test runner āļ•āļąāļ§āđ€āļĨāļ·āļ­āļ environment āļ•āđ‰āļ­āļ‡āļāļģāļŦāļ™āļ”āđ€āļ›āđ‡āļ™ jsdom āļŦāļĢāļ·āļ­ happy-dom āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰ component test āļĄāļĩ DOM āđƒāļŦāđ‰ render āļĨāļ‡āđ„āļ› āļŠāđˆāļ§āļ™āđāļŸāļĨāļ globals: true āļˆāļ°āđ€āļ›āļīāļ”āđƒāļŦāđ‰ describe, it āđāļĨāļ° expect āđƒāļŠāđ‰āļ‡āļēāļ™āđ„āļ”āđ‰āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡ import āđƒāļ™āļ—āļļāļāđ„āļŸāļĨāđŒ

vitest.config.tstypescript
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath } from 'node:url'

export default defineConfig({
  plugins: [vue()],
  test: {
    // jsdom provides document/window so components can mount
    environment: 'jsdom',
    // expose describe/it/expect globally
    globals: true,
    // run this before each test file (matchers, cleanup)
    setupFiles: ['./tests/setup.ts'],
    // only pick up *.spec.ts and *.test.ts files
    include: ['**/*.{test,spec}.ts'],
  },
  resolve: {
    alias: {
      // mirror the @ alias used across the app
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
})

āļŠāļģāļŦāļĢāļąāļš Vitest 3 config āļ”āđ‰āļēāļ™āļšāļ™āđƒāļŠāđ‰āļ‡āļēāļ™āđ„āļ”āđ‰āļ—āļąāļ™āļ—āļĩāļŦāļĨāļąāļ‡āļ•āļīāļ”āļ•āļąāđ‰āļ‡ vitest, @vue/test-utils, @vitejs/plugin-vue āđāļĨāļ° jsdom āđāļĨāļ°āđ€āļ™āļ·āđˆāļ­āļ‡āļˆāļēāļ alias āļŠāļ°āļ—āđ‰āļ­āļ™ config āļ‚āļ­āļ‡āļ•āļąāļ§āđāļ­āļ› āļāļēāļĢ import āđāļšāļš @/composables/useCart āļˆāļķāļ‡āļ–āļđāļ resolve āđ€āļŦāļĄāļ·āļ­āļ™āļāļąāļ™āļ—āļąāđ‰āļ‡āđƒāļ™āđ€āļ—āļŠāļ•āđŒāđāļĨāļ°āđƒāļ™āđ‚āļ›āļĢāļ”āļąāļāļŠāļąāļ™

āļāļēāļĢ mount āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ”āđ‰āļ§āļĒ Vue Test Utils

Vue Test Utils āđ€āļ›āļīāļ”āļˆāļļāļ”āđ€āļ‚āđ‰āļēāđƒāļŠāđ‰āļ‡āļēāļ™āļŠāļ­āļ‡āļ—āļēāļ‡ āđ„āļ”āđ‰āđāļāđˆ mount āļ—āļĩāđˆ render āļ•āđ‰āļ™āđ„āļĄāđ‰āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļąāđ‰āļ‡āļŦāļĄāļ” āđāļĨāļ° shallowMount āļ—āļĩāđˆāđāļ—āļ™āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļĨāļđāļāļ”āđ‰āļ§āļĒ stub āļŠāļģāļŦāļĢāļąāļš unit test āļŠāđˆāļ§āļ™āđƒāļŦāļāđˆāļ„āļ§āļĢāđ€āļĨāļ·āļ­āļ mount āđ€āļžāļĢāļēāļ°āļĄāļąāļ™āļ—āļ”āļŠāļ­āļšāļžāļĪāļ•āļīāļāļĢāļĢāļĄāļāļēāļĢ render āļ‚āļ­āļ‡āļˆāļĢāļīāļ‡ āļ„āđˆāļē wrapper āļ—āļĩāđˆāļ„āļ·āļ™āļāļĨāļąāļšāļĄāļēāļˆāļ°āļĄāļĩāļ•āļąāļ§āļŠāđˆāļ§āļĒāļ„āđ‰āļ™āļŦāļēāļ­āļĒāđˆāļēāļ‡ find, get āđāļĨāļ° text āđƒāļŦāđ‰āđƒāļŠāđ‰āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļĨāļąāļžāļ˜āđŒāļ—āļĩāđˆ render āļ­āļ­āļāļĄāļē

PriceTag.spec.tstypescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import PriceTag from '@/components/PriceTag.vue'

describe('PriceTag', () => {
  it('formats the amount as currency', () => {
    const wrapper = mount(PriceTag, {
      // props are passed through the mounting options
      props: { amount: 4200, currency: 'EUR' },
    })

    // get() throws if the selector is missing, unlike find()
    expect(wrapper.get('[data-test="price"]').text()).toBe('₮42.00')
  })

  it('applies a discount class when on sale', () => {
    const wrapper = mount(PriceTag, {
      props: { amount: 4200, currency: 'EUR', onSale: true },
    })

    // classes() returns the array of applied CSS classes
    expect(wrapper.get('[data-test="price"]').classes()).toContain('price--sale')
  })
})

āļāļēāļĢāđ€āļˆāļēāļ°āđ„āļ›āļ—āļĩāđˆ element āļœāđˆāļēāļ™āđāļ­āļ•āļ—āļĢāļīāļšāļīāļ§āļ•āđŒ data-test āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āđƒāļŠāđ‰ CSS class āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāļ—āļ™āļ—āļēāļ™āļāļ§āđˆāļē āđ€āļžāļĢāļēāļ°āļāļēāļĢāļ›āļĢāļąāļšāļŠāđ„āļ•āļĨāđŒāļ‚āļ­āļ‡ .price--sale āļˆāļ°āđ„āļĄāđˆāļ—āļģāđƒāļŦāđ‰ selector āļžāļąāļ‡ āļĄāļĩāđ€āļžāļĩāļĒāļ‡āļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļˆāļĢāļīāļ‡āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™āļ—āļĩāđˆāļ—āļģāđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāļĨāđ‰āļĄ āļāļēāļĢāđāļĒāļāļŠāđˆāļ§āļ™āđāļšāļšāļ™āļĩāđ‰āđ€āļ›āđ‡āļ™āđāļ™āļ§āļ„āļīāļ”āļ—āļĩāđˆāļžāļšāļ‹āđ‰āļģ āđ† āđƒāļ™āļāļēāļĢāđ€āļ‚āļĩāļĒāļ™āđ€āļ—āļŠāļ•āđŒ Vue āļ—āļĩāđˆāļ”āļđāđāļĨāļĢāļąāļāļĐāļēāļ‡āđˆāļēāļĒ

āļāļēāļĢāļ—āļ”āļŠāļ­āļš user event āđāļĨāļ° event āļ—āļĩāđˆāļ–āļđāļ emit

āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļĩāđˆāļĄāļĩāļāļēāļĢāđ‚āļ•āđ‰āļ•āļ­āļšāļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļĄāļĩāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļ§āđˆāļēāļˆāļ°āđ€āļāļīāļ”āļ­āļ°āđ„āļĢāļ‚āļķāđ‰āļ™āļŦāļĨāļąāļ‡āļāļēāļĢāļ„āļĨāļīāļāļŦāļĢāļ·āļ­āļāļēāļĢāļžāļīāļĄāļžāđŒ Vue Test Utils āļ„āļ·āļ™āļ„āđˆāļē promise āļˆāļēāļ trigger āđāļĨāļ°āļāļēāļĢ await āļĄāļąāļ™āļˆāļ° flush āļ„āļīāļ§ reactivity āļ‚āļ­āļ‡ Vue āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰ DOM āļŠāļ°āļ—āđ‰āļ­āļ™āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• āļŠāđˆāļ§āļ™āļ•āļąāļ§āļŠāđˆāļ§āļĒ emitted āļˆāļ°āļšāļąāļ™āļ—āļķāļāļ—āļļāļ custom event āļ—āļĩāđˆāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļĒāļīāļ‡āļ­āļ­āļāļĄāļē āļ‹āļķāđˆāļ‡āđ€āļ›āđ‡āļ™āļ§āļīāļ˜āļĩāļ•āļĢāļ§āļˆāļŠāļ­āļšāļŠāļąāļāļāļēāļĢāļ°āļŦāļ§āđˆāļēāļ‡ parent āļāļąāļš child

SearchBar.spec.tstypescript
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import SearchBar from '@/components/SearchBar.vue'

describe('SearchBar', () => {
  it('emits search with the typed query', async () => {
    const wrapper = mount(SearchBar)

    // setValue writes to the input and fires an input event
    await wrapper.get('input').setValue('vitest')
    // awaiting trigger flushes the reactivity queue before assertions
    await wrapper.get('[data-test="submit"]').trigger('click')

    // emitted() returns a record of every event and its payloads
    const events = wrapper.emitted('search')
    expect(events).toHaveLength(1)
    // events[0] is the first emission, [0] its first argument
    expect(events![0][0]).toBe('vitest')
  })
})
āļ­āļĒāđˆāļēāļĨāļ·āļĄ await āļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• DOM āđ€āļŠāļĄāļ­

Vue āļĢāļ§āļĄāļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• reactive āđ€āļ‚āđ‰āļēāļ”āđ‰āļ§āļĒāļāļąāļ™āđāļšāļš asynchronous āļāļēāļĢāļĨāļ·āļĄ await āļāļēāļĢāđ€āļĢāļĩāļĒāļ trigger āļŦāļĢāļ·āļ­ setValue āļ„āļ·āļ­āļŠāļēāđ€āļŦāļ•āļļāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”āļ‚āļ­āļ‡āđ€āļ—āļŠāļ•āđŒ Vue āļ—āļĩāđˆāļœāļĨāļĨāļąāļžāļ˜āđŒāđ„āļĄāđˆāđāļ™āđˆāļ™āļ­āļ™ āđ€āļžāļĢāļēāļ°āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļˆāļ°āļ—āļģāļ‡āļēāļ™āļāđˆāļ­āļ™āļ—āļĩāđˆ DOM āļˆāļ° re-render āļˆāļķāļ‡āļ­āđˆāļēāļ™āļ„āđˆāļēāļ—āļĩāđˆāļĒāļąāļ‡āđ„āļĄāđˆāļ­āļąāļ›āđ€āļ”āļ• āļŦāļēāļāļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™ state āđ€āļāļīāļ”āļ‚āļķāđ‰āļ™āļ™āļ­āļāļ•āļąāļ§āļŠāđˆāļ§āļĒ event āđƒāļŦāđ‰ import nextTick āļˆāļēāļ vue āđāļĨāđ‰āļ§ await nextTick() āļāđˆāļ­āļ™āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨ

āļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue composable āđāļšāļšāđāļĒāļāļ­āļīāļŠāļĢāļ°

Composable āļ—āļĩāđˆāđƒāļŠāđ‰āđ€āļžāļĩāļĒāļ‡ reactivity API (ref, computed, watch) āđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āļĄāļĩāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāđ€āļĨāļĒ āđ€āļžāļĢāļēāļ°āļĄāļąāļ™āļ„āļ·āļ­āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ˜āļĢāļĢāļĄāļ”āļēāļ—āļĩāđˆāļ„āļ·āļ™ reactive state āļ­āļ­āļāļĄāļē āļ”āļąāļ‡āļ™āļąāđ‰āļ™āļāļēāļĢāđ€āļĢāļĩāļĒāļāđƒāļŠāđ‰āđ‚āļ”āļĒāļ•āļĢāļ‡āđāļĨāđ‰āļ§āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļšāļ™ .value āļāđ‡āđ€āļžāļĩāļĒāļ‡āļžāļ­ āļ™āļĩāđˆāļ„āļ·āļ­āļ§āļīāļ˜āļĩāļ—āļĩāđˆāđ€āļĢāđ‡āļ§āļ—āļĩāđˆāļŠāļļāļ”āđāļĨāļ°āđ€āļˆāļēāļ°āļˆāļ‡āļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āļāļēāļĢāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļ•āļĢāļĢāļāļ°āļ—āļēāļ‡āļ˜āļļāļĢāļāļīāļˆ āđāļĨāļ°āđ€āļ‚āđ‰āļēāļāļąāļ™āđ„āļ”āđ‰āļ”āļĩāļāļąāļšāđāļžāļ•āđ€āļ—āļīāļĢāđŒāļ™āđƒāļ™composable āļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļ‚āļ­āļ‡ Vue 3

useCart.spec.tstypescript
import { describe, it, expect } from 'vitest'
import { useCart } from '@/composables/useCart'

describe('useCart', () => {
  it('tracks total price as items change', () => {
    // composables using only ref/computed run without mounting
    const { items, total, addItem } = useCart()

    expect(total.value).toBe(0)

    addItem({ id: 1, price: 1500, qty: 2 })
    // computed total recalculates synchronously on state change
    expect(total.value).toBe(3000)

    addItem({ id: 2, price: 500, qty: 1 })
    expect(items.value).toHaveLength(2)
    expect(total.value).toBe(3500)
  })
})

Composable āļ—āļĩāđˆāļžāļķāđˆāļ‡āļžāļē lifecycle hook āļ­āļĒāđˆāļēāļ‡ onMounted āđ€āļ›āđ‡āļ™āļ‚āđ‰āļ­āļĒāļāđ€āļ§āđ‰āļ™ āđ€āļžāļĢāļēāļ°āļĄāļąāļ™āļ•āđ‰āļ­āļ‡āļ—āļģāļ‡āļēāļ™āļ āļēāļĒāđƒāļ™ instance āļ‚āļ­āļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āļ§āļīāļ˜āļĩāđāļāđ‰āļ—āļĩāđˆāļ™āļīāļĒāļĄāđƒāļŠāđ‰āļ„āļ·āļ­āļŠāļĢāđ‰āļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ•āļąāļ§āļŠāđˆāļ§āļĒāđ€āļĨāđ‡āļ āđ† āļ—āļĩāđˆāđ€āļĢāļĩāļĒāļ composable āđƒāļ™ setup āđāļĨāđ‰āļ§āđ€āļ›āļīāļ”āļœāļĨāļĨāļąāļžāļ˜āđŒāļ­āļ­āļāļĄāļē āļˆāļēāļāļ™āļąāđ‰āļ™āļˆāļķāļ‡ mount āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ•āļąāļ§āļŠāđˆāļ§āļĒāļ™āļąāđ‰āļ™āļ”āđ‰āļ§āļĒ Vue Test Utils

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Vue.js / Nuxt.js āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļāļēāļĢ mock āļāļēāļĢāđ€āļĢāļĩāļĒāļ API āļ”āđ‰āļ§āļĒ vi.mock

āļ„āļģāļ‚āļ­āļœāđˆāļēāļ™āđ€āļ„āļĢāļ·āļ­āļ‚āđˆāļēāļĒāļˆāļĢāļīāļ‡āļ—āļģāđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāļŠāđ‰āļēāđāļĨāļ°āđ„āļĄāđˆāļ„āļ‡āđ€āļŠāđ‰āļ™āļ„āļ‡āļ§āļē Vitest āļˆāļķāļ‡āđāļ—āļ™āļ—āļĩāđˆāđ‚āļĄāļ”āļđāļĨāļ”āđ‰āļ§āļĒ vi.mock āđāļĨāļ°āļŠāļĢāđ‰āļēāļ‡āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ spy āļ”āđ‰āļ§āļĒ vi.fn āđāļžāļ•āđ€āļ—āļīāļĢāđŒāļ™āļ”āđ‰āļēāļ™āļĨāđˆāļēāļ‡āļˆāļ° mock āđ‚āļĄāļ”āļđāļĨāļ—āļĩāđˆāļŦāđˆāļ­ fetch āđ„āļ§āđ‰ āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰ composable āļ—āļĩāđˆāļāļģāļĨāļąāļ‡āļ—āļ”āļŠāļ­āļšāđ„āļ”āđ‰āļĢāļąāļšāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļ„āļ§āļšāļ„āļļāļĄāđ„āļ”āđ‰āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļĒāļīāļ‡āđ„āļ›āļ—āļĩāđˆāđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒāđ€āļĨāļĒ

useProducts.spec.tstypescript
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useProducts } from '@/composables/useProducts'
import { getProducts } from '@/api/products'

// replace the whole module with mocked exports
vi.mock('@/api/products', () => ({
  getProducts: vi.fn(),
}))

describe('useProducts', () => {
  beforeEach(() => {
    // reset call history between tests to avoid leakage
    vi.mocked(getProducts).mockReset()
  })

  it('exposes fetched products and clears loading', async () => {
    // define what the mocked API returns for this test
    vi.mocked(getProducts).mockResolvedValue([
      { id: 1, name: 'Keyboard' },
    ])

    const { products, loading, load } = useProducts()
    await load()

    expect(getProducts).toHaveBeenCalledOnce()
    expect(loading.value).toBe(false)
    expect(products.value[0].name).toBe('Keyboard')
  })
})

āļāļēāļĢ mock āļ—āļĩāđˆāļ‚āļ­āļšāđ€āļ‚āļ•āļ‚āļ­āļ‡āđ‚āļĄāļ”āļđāļĨāļŠāđˆāļ§āļĒāđƒāļŦāđ‰āļ•āļĢāļĢāļāļ°āļ āļēāļĒāđƒāļ™āļ‚āļ­āļ‡ composable āđ„āļĄāđˆāļ–āļđāļāđāļ•āļ°āļ•āđ‰āļ­āļ‡ āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆāđƒāļŦāđ‰āđāļ•āđˆāļĨāļ°āđ€āļ—āļŠāļ•āđŒāļ„āļ§āļšāļ„āļļāļĄ response āļ‚āļ­āļ‡ API āđ„āļ”āđ‰āđ€āļ•āđ‡āļĄāļ—āļĩāđˆ āļĢāļ§āļĄāļ–āļķāļ‡āđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļ—āļĩāđˆāđ€āļāļīāļ” error āļ”āđ‰āļ§āļĒ āļāļēāļĢāđ€āļĢāļĩāļĒāļ mockRejectedValue āđāļ—āļ™āļˆāļ°āļ—āļģāđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāđ€āļžāļĩāļĒāļ‡āļ•āļąāļ§āđ€āļ”āļĩāļĒāļ§āļŠāļēāļĄāļēāļĢāļ–āļ•āļĢāļ§āļˆāļŠāļ­āļšāđ„āļ”āđ‰āļ§āđˆāļēāđ€āļĄāļ·āđˆāļ­āđ€āļāļīāļ”āļ„āļ§āļēāļĄāļĨāđ‰āļĄāđ€āļŦāļĨāļ§ state āļ‚āļ­āļ‡ error āļˆāļ°āļ–āļđāļāļ•āļąāđ‰āļ‡āļ„āđˆāļēāđāļĨāļ° spinner āļˆāļ°āļŦāļĒāļļāļ”āļŦāļĄāļļāļ™

āļāļēāļĢāļ—āļ”āļŠāļ­āļš Pinia store āđƒāļ™āļ›āļĩ 2026

Store āđ€āļāđ‡āļš state āļ—āļĩāđˆāđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļ™āļ‚āđ‰āļēāļĄāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āđāļĨāļ°āđāļžāđ‡āļāđ€āļāļˆāļ—āļēāļ‡āļāļēāļĢ @pinia/testing āļ—āļģāđƒāļŦāđ‰āļ—āļ”āļŠāļ­āļšāđ„āļ”āđ‰āļ•āļĢāļ‡āđ„āļ›āļ•āļĢāļ‡āļĄāļē āđ‚āļ”āļĒāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ createTestingPinia āļˆāļ° stub āļ—āļļāļ action āđ„āļ§āđ‰ āļ”āļąāļ‡āļ™āļąāđ‰āļ™ component test āļˆāļķāļ‡āļŠāļēāļĄāļēāļĢāļ–āļĒāļ·āļ™āļĒāļąāļ™āđ„āļ”āđ‰āļ§āđˆāļēāļĄāļĩāļāļēāļĢ dispatch action āļ­āļ­āļāđ„āļ›āđ‚āļ”āļĒāđ„āļĄāđˆāļ•āđ‰āļ­āļ‡āļĢāļąāļ™ side effect āļ‚āļ­āļ‡āļĄāļąāļ™ āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļ—āļ”āļŠāļ­āļš Pinia āđāļ™āļ°āļ™āļģāđāļ™āļ§āļ—āļēāļ‡āļ™āļĩāđ‰āļŠāļģāļŦāļĢāļąāļšāđ€āļ—āļŠāļ•āđŒāļĢāļ°āļ”āļąāļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ

CheckoutButton.spec.tstypescript
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'
import CheckoutButton from '@/components/CheckoutButton.vue'
import { useCartStore } from '@/stores/cart'

describe('CheckoutButton', () => {
  it('dispatches checkout on click', async () => {
    const wrapper = mount(CheckoutButton, {
      global: {
        plugins: [
          // vi.fn spies on actions instead of executing them
          createTestingPinia({ createSpy: vi.fn }),
        ],
      },
    })

    const store = useCartStore()
    await wrapper.get('[data-test="checkout"]').trigger('click')

    // the action is stubbed, so only the dispatch is asserted
    expect(store.checkout).toHaveBeenCalledOnce()
  })
})

āļŦāļēāļāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ•āļĢāļĢāļāļ°āļ‚āļ­āļ‡ store āđ€āļ­āļ‡āđāļ—āļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļāļēāļĢāļœāļŠāļēāļ™āđ€āļ‚āđ‰āļēāļāļąāļšāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āđƒāļŦāđ‰āļŠāđˆāļ‡ stubActions: false āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰ action āļ—āļģāļ‡āļēāļ™āļ•āļēāļĄāļ›āļāļ•āļī āđāļĨāđ‰āļ§āļˆāļķāļ‡āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļšāļ™ state āļ—āļĩāđˆāđ„āļ”āđ‰ āļāļēāļĢāđāļĒāļāļĢāļ°āļŦāļ§āđˆāļēāļ‡āđ€āļ—āļŠāļ•āđŒāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļ—āļĩāđˆ stub action āļāļąāļšāđ€āļ—āļŠāļ•āđŒ store āļ—āļĩāđˆāđƒāļŠāđ‰ action āļˆāļĢāļīāļ‡ āļŠāđˆāļ§āļĒāđƒāļŦāđ‰āđāļ•āđˆāļĨāļ° suite āđ‚āļŸāļāļąāļŠāļ­āļĒāļđāđˆāļāļąāļšāļ„āļ§āļēāļĄāļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāđ€āļžāļĩāļĒāļ‡āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§

āļāļēāļĢāļĢāļąāļ™āđ€āļ—āļŠāļ•āđŒāđƒāļ™ watch mode āđāļĨāļ°āļāļēāļĢāļ§āļąāļ” coverage

Vitest āļĄāļēāļžāļĢāđ‰āļ­āļĄ watch mode āļ—āļĩāđˆāļĢāļąāļ™āļ‹āđ‰āļģāđ€āļ‰āļžāļēāļ°āđ€āļ—āļŠāļ•āđŒāļ—āļĩāđˆāđ„āļ”āđ‰āļĢāļąāļšāļœāļĨāļāļĢāļ°āļ—āļšāļˆāļēāļāđ„āļŸāļĨāđŒāļ—āļĩāđˆāđ€āļžāļīāđˆāļ‡āļšāļąāļ™āļ—āļķāļ āļ‹āļķāđˆāļ‡āļĒāđˆāļ™āļĢāļ­āļš feedback āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļāļēāļĢāļžāļąāļ’āļ™āļēāđƒāļŦāđ‰āđ€āļŦāļĨāļ·āļ­āđ€āļžāļĩāļĒāļ‡āđ€āļŠāļĩāđ‰āļĒāļ§āļ§āļīāļ™āļēāļ—āļĩ āļŠāđˆāļ§āļ™āļāļēāļĢāļĢāļēāļĒāļ‡āļēāļ™ coverage āļĄāļĩāļĄāļēāđƒāļŦāđ‰āđƒāļ™āļ•āļąāļ§āļœāđˆāļēāļ™ provider @vitest/coverage-v8 āđāļĨāļ°āļœāļŠāļēāļ™āđ€āļ‚āđ‰āļēāļāļąāļš pipeline āļ‚āļ­āļ‡ continuous integration āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ€āļĢāļĩāļĒāļšāļĢāđ‰āļ­āļĒ āđ‚āļ”āļĒāđ€āļ—āļŠāļ•āđŒāļ—āļĩāđˆāļĨāđ‰āļĄāđ€āļŦāļĨāļ§āļŦāļĢāļ·āļ­ coverage āļ—āļĩāđˆāļ–āļ”āļ–āļ­āļĒāļĨāļ‡āļŠāļēāļĄāļēāļĢāļ–āļšāļĨāđ‡āļ­āļāļāļēāļĢ merge āđ„āļ”āđ‰

vitest.config.ts (coverage section)typescript
export default defineConfig({
  test: {
    coverage: {
      // v8 is the fastest provider and needs no instrumentation step
      provider: 'v8',
      reporter: ['text', 'html', 'lcov'],
      // fail CI when a threshold drops below the target
      thresholds: {
        statements: 80,
        branches: 75,
        functions: 80,
      },
      // exclude generated and config files from the report
      exclude: ['**/*.config.ts', '**/types/**'],
    },
  },
})

āļāļēāļĢāļĢāļąāļ™ vitest āđ€āļžāļĩāļĒāļ‡āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§āļˆāļ°āđ€āļĢāļīāđˆāļĄ watch mode āļšāļ™āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļ—āđ‰āļ­āļ‡āļ–āļīāđˆāļ™ āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆ vitest run --coverage āļˆāļ°āļĢāļąāļ™āđāļšāļšāļœāđˆāļēāļ™āļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§āļ‹āļķāđˆāļ‡āđ€āļŦāļĄāļēāļ°āļāļąāļš CI āļāļēāļĢāļāļģāļŦāļ™āļ” threshold āļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™āđ€āļ›āļĨāļĩāđˆāļĒāļ™ coverage āļˆāļēāļāļ•āļąāļ§āđ€āļĨāļ‚āđ„āļ§āđ‰āļ­āļ§āļ”āđƒāļŦāđ‰āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™āļ”āđˆāļēāļ™āļ„āļļāļ“āļ āļēāļžāļ—āļĩāđˆāļšāļąāļ‡āļ„āļąāļšāđƒāļŠāđ‰āļˆāļĢāļīāļ‡ āđ€āļžāļĢāļēāļ° pull request āļ—āļĩāđˆāļ—āļģāđƒāļŦāđ‰ branch coverage āļ•āļāļĨāļ‡āļ•āđˆāļģāļāļ§āđˆāļē 75 āđ€āļ›āļ­āļĢāđŒāđ€āļ‹āđ‡āļ™āļ•āđŒāļˆāļ°āļĨāđ‰āļĄāđ€āļŦāļĨāļ§āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī āļ‹āļķāđˆāļ‡āļāļĢāļ°āļ•āļļāđ‰āļ™āđƒāļŦāđ‰āļœāļđāđ‰āļžāļąāļ’āļ™āļēāļ—āļ”āļŠāļ­āļšāđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļ—āļĩāđˆāļ•āļąāļ§āđ€āļ­āļ‡āđ€āļžāļīāđˆāļĄāđ€āļ‚āđ‰āļēāļĄāļē āđ„āļĄāđˆāđƒāļŠāđˆāđ€āļžāļĩāļĒāļ‡āđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļ—āļĩāđˆāļ—āļļāļāļ­āļĒāđˆāļēāļ‡āļĢāļēāļšāļĢāļ·āđˆāļ™āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđ€āļĢāļ·āđˆāļ­āļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļžāļĢāđ‰āļ­āļĄāļ„āļģāļ•āļ­āļš

āļ„āļģāļ–āļēāļĄāđ€āļĢāļ·āđˆāļ­āļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ›āļĢāļēāļāļāđƒāļ™āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Vue āļĢāļ°āļ”āļąāļš senior āđ€āļāļ·āļ­āļšāļ—āļļāļāļ„āļĢāļąāđ‰āļ‡ āđ€āļžāļĢāļēāļ°āļĄāļąāļ™āđ€āļœāļĒāđƒāļŦāđ‰āđ€āļŦāđ‡āļ™āļ§āđˆāļēāļœāļđāđ‰āļŠāļĄāļąāļ„āļĢāļ„āļīāļ”āđ€āļĢāļ·āđˆāļ­āļ‡āļāļēāļĢāļ”āļđāđāļĨāļĢāļąāļāļĐāļēāđ‚āļ„āđ‰āļ”āļ­āļĒāđˆāļēāļ‡āđ„āļĢ āļ„āļģāļ•āļ­āļšāļ”āđ‰āļēāļ™āļĨāđˆāļēāļ‡āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāđāļ™āļ§āļ„āļīāļ”āļ—āļĩāđˆāļ–āļđāļāļ–āļēāļĄāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ” āđāļĨāļ°āļŠāļļāļ”āļ„āļģāļ–āļēāļĄāļ‰āļšāļąāļšāđ€āļ•āđ‡āļĄāļĄāļĩāđƒāļŦāđ‰āļāļķāļāđƒāļ™āđ‚āļĄāļ”āļđāļĨāļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue

āļ„āļ§āļĢāđƒāļŠāđ‰ shallowMount āđāļ—āļ™ mount āđ€āļĄāļ·āđˆāļ­āđƒāļ”? āđ€āļĨāļ·āļ­āļāđƒāļŠāđ‰ shallowMount āđ€āļĄāļ·āđˆāļ­āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ render āļĨāļđāļāļ—āļĩāđˆāļŦāļ™āļąāļāļŦāļĢāļ·āļ­āļ–āļđāļāļ—āļ”āļŠāļ­āļšāđ„āļ§āđ‰āđāļĨāđ‰āļ§ āđāļĨāļ°āđ€āļ—āļŠāļ•āđŒāļŠāļ™āđƒāļˆāđ€āļžāļĩāļĒāļ‡āļ•āļĢāļĢāļāļ°āļ‚āļ­āļ‡ parent āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™ āļāļēāļĢ stub āļĨāļđāļāļˆāļ°āđāļĒāļ unit āđƒāļŦāđ‰āļ­āļīāļŠāļĢāļ°āđāļĨāļ°āđ€āļĢāđˆāļ‡āļāļēāļĢ render āđƒāļŦāđ‰āđ€āļĢāđ‡āļ§āļ‚āļķāđ‰āļ™ āđāļĨāļāļāļąāļšāļāļēāļĢāļ—āļĩāđˆāđ„āļĄāđˆāđ„āļ”āđ‰āļ•āļĢāļ§āļˆāļŠāļ­āļšāļāļēāļĢāļœāļŠāļēāļ™āļˆāļĢāļīāļ‡āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ

Vue Test Utils āļˆāļąāļ”āļāļēāļĢāļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ•āđāļšāļš asynchronous āļ­āļĒāđˆāļēāļ‡āđ„āļĢ? Vue āļ™āļģāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡ reactive āđ„āļ›āđƒāļŠāđ‰āđƒāļ™ tick āļ–āļąāļ”āđ„āļ› āļ•āļąāļ§āļŠāđˆāļ§āļĒ event āļ­āļĒāđˆāļēāļ‡ trigger āđāļĨāļ° setValue āļ„āļ·āļ™ promise āļ—āļĩāđˆ resolve āļŦāļĨāļąāļ‡āļˆāļēāļ DOM āļ­āļąāļ›āđ€āļ”āļ•āđāļĨāđ‰āļ§ āļ”āļąāļ‡āļ™āļąāđ‰āļ™āļāļēāļĢ await āļĄāļąāļ™āļāđ‡āđ€āļžāļĩāļĒāļ‡āļžāļ­ āļŠāđˆāļ§āļ™ state āļ—āļĩāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ™āļ­āļāļ•āļąāļ§āļŠāđˆāļ§āļĒāđ€āļŦāļĨāđˆāļēāļ™āļąāđ‰āļ™ āđƒāļŦāđ‰āđƒāļŠāđ‰ await nextTick() āđ€āļžāļ·āđˆāļ­āļšāļąāļ‡āļ„āļąāļšāđƒāļŦāđ‰āļ„āļīāļ§ flush āļāđˆāļ­āļ™āļ—āļĩāđˆāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļˆāļ°āļ—āļģāļ‡āļēāļ™

find āļāļąāļš get āļ•āđˆāļēāļ‡āļāļąāļ™āļ­āļĒāđˆāļēāļ‡āđ„āļĢ? find āļ„āļ·āļ™ wrapper āđ€āļ›āļĨāđˆāļēāđ€āļĄāļ·āđˆāļ­āđ„āļĄāđˆāļĄāļĩ element āļ•āļĢāļ‡āļāļąāļ™āđāļĨāļ°āļˆāļ°āđ„āļĄāđˆ throw āļ‹āļķāđˆāļ‡āđ€āļŦāļĄāļēāļ°āļāļąāļšāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāđāļšāļš expect(wrapper.find('.error').exists()).toBe(false) āļŠāđˆāļ§āļ™ get āļˆāļ° throw āļ—āļąāļ™āļ—āļĩāđ€āļĄāļ·āđˆāļ­āđ„āļĄāđˆāļžāļš element āļ—āļģāđƒāļŦāđ‰āđ€āļ›āđ‡āļ™āļ•āļąāļ§āđ€āļĨāļ·āļ­āļāļ—āļĩāđˆāļ”āļĩāļāļ§āđˆāļēāđ€āļĄāļ·āđˆāļ­āļ„āļēāļ”āļ§āđˆāļē element āļ™āļąāđ‰āļ™āļ•āđ‰āļ­āļ‡āļĄāļĩāļ­āļĒāļđāđˆ āđāļĨāļ°āļāļēāļĢāļŦāļēāļĒāđ„āļ›āļ‚āļ­āļ‡āļĄāļąāļ™āļ„āļ·āļ­āļ„āļ§āļēāļĄāļĨāđ‰āļĄāđ€āļŦāļĨāļ§āļ—āļĩāđˆāđāļ—āđ‰āļˆāļĢāļīāļ‡

āļ—āļģāđ„āļĄāļˆāļķāļ‡āļ„āļ§āļĢāđƒāļŠāđ‰āđāļ­āļ•āļ—āļĢāļīāļšāļīāļ§āļ•āđŒ data-test āđāļ—āļ™ class selector? āļŠāļ·āđˆāļ­ class āđ€āļ›āļĨāļĩāđˆāļĒāļ™āđ„āļ›āļ•āļēāļĄāļŠāđ„āļ•āļĨāđŒāđāļĨāļ°āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡ āļ”āļąāļ‡āļ™āļąāđ‰āļ™āđ€āļ—āļŠāļ•āđŒāļ—āļĩāđˆ query āļˆāļēāļāļĄāļąāļ™āļˆāļķāļ‡āļžāļąāļ‡āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđāļāđ‰āđ„āļ‚āđ€āļŠāļīāļ‡āļ„āļ§āļēāļĄāļŠāļ§āļĒāļ‡āļēāļĄ āļāļēāļĢāđƒāļŠāđ‰ hook data-test āđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ°āļˆāļ°āđāļŠāļ”āļ‡āđ€āļˆāļ•āļ™āļēāļ‚āļ­āļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™āđāļĨāļ°āļ­āļĒāļđāđˆāļĢāļ­āļ”āļœāđˆāļēāļ™āļāļēāļĢ refactor āļŠāđˆāļ§āļĒāļĨāļ” false negative

āļˆāļ°āļ—āļ”āļŠāļ­āļš composable āļ—āļĩāđˆāļžāļķāđˆāļ‡āļžāļē onMounted āļ­āļĒāđˆāļēāļ‡āđ„āļĢ? lifecycle hook āļˆāļ°āļ—āļģāļ‡āļēāļ™āđ€āļ‰āļžāļēāļ°āļ āļēāļĒāđƒāļ™ instance āļ‚āļ­āļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āļ”āļąāļ‡āļ™āļąāđ‰āļ™āļˆāļķāļ‡āđ€āļĢāļĩāļĒāļ composable āđ‚āļ”āļĒāļ•āļĢāļ‡āđ„āļĄāđˆāđ„āļ”āđ‰ āđ€āļ—āļ„āļ™āļīāļ„āļĄāļēāļ•āļĢāļāļēāļ™āļ„āļ·āļ­āļŠāļĢāđ‰āļēāļ‡āļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ harness āđāļšāļšāđƒāļŠāđ‰āđāļĨāđ‰āļ§āļ—āļīāđ‰āļ‡āļ—āļĩāđˆāđ€āļĢāļĩāļĒāļ composable āđƒāļ™ setup āđāļĨāļ°āđ€āļ›āļīāļ”āļ„āđˆāļēāļ—āļĩāđˆāļ„āļ·āļ™āļ­āļ­āļāļĄāļē āļˆāļēāļāļ™āļąāđ‰āļ™āļˆāļķāļ‡ mount harness āļ™āļąāđ‰āļ™āļ”āđ‰āļ§āļĒ Vue Test Utils āđāļĨāđ‰āļ§āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļœāđˆāļēāļ™ wrapper āļ§āļīāļ˜āļĩāļ™āļĩāđ‰āļ—āļģāđƒāļŦāđ‰āļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­ reactivity āđāļĨāļ° lifecycle āļĒāļąāļ‡āļ„āļ‡āļŠāļĄāļšāļđāļĢāļ“āđŒāđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆāļĒāļąāļ‡āđāļĒāļāļ•āļĢāļĢāļāļ°āļ—āļĩāđˆāļāļģāļĨāļąāļ‡āļ—āļ”āļŠāļ­āļšāđƒāļŦāđ‰āļ­āļīāļŠāļĢāļ° āļ„āļģāļ–āļēāļĄāđ€āļŠāļīāļ‡āđāļ™āļ§āļ„āļīāļ”āđāļĨāļ°āđ€āļŠāļīāļ‡āđ€āļ‚āļĩāļĒāļ™āđ‚āļ„āđ‰āļ”āđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄāļĢāļ§āļšāļĢāļ§āļĄāđ„āļ§āđ‰āđƒāļ™āļ„āļđāđˆāļĄāļ·āļ­āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Vue.js āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™

āļšāļ—āļŠāļĢāļļāļ›

āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļēāļāļēāļĢāļ—āļ”āļŠāļ­āļš Vue āļ—āļĩāđˆāđ€āļŠāļ·āđˆāļ­āļ–āļ·āļ­āđ„āļ”āđ‰āđƒāļ™āļ›āļĩ 2026 āļŠāļĢāļļāļ›āļĨāļ‡āđ€āļŦāļĨāļ·āļ­āļ—āļēāļ‡āđ€āļĨāļ·āļ­āļāļ—āļĩāđˆāļžāļīāļˆāļēāļĢāļ“āļēāļ­āļĒāđˆāļēāļ‡āļ•āļąāđ‰āļ‡āđƒāļˆāđ„āļĄāđˆāļāļĩāđˆāļ‚āđ‰āļ­:

  • āļĢāļąāļ™ Vitest āļ”āđ‰āļ§āļĒ environment: 'jsdom' āđāļĨāļ°āļ›āļĨāļąāđŠāļāļ­āļīāļ™ Vue āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāđƒāļŠāđ‰ transform pipeline āļ‚āļ­āļ‡ Vite āļŠāļļāļ”āđ€āļ”āļĩāļĒāļ§āļāļąāļšāļ•āļąāļ§āđāļ­āļ›āđ€āļ›āđŠāļ°
  • āđ€āļĨāļ·āļ­āļ mount āļĄāļēāļāļāļ§āđˆāļē shallowMount āđ€āļ§āđ‰āļ™āđāļ•āđˆāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒāļĨāļđāļāļˆāļ°āļŦāļ™āļąāļāļŦāļĢāļ·āļ­āļ–āļđāļāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāđ„āļ§āđ‰āđāļĨāđ‰āļ§āļ—āļĩāđˆāļ­āļ·āđˆāļ™
  • await trigger, setValue āđāļĨāļ° nextTick āđ€āļŠāļĄāļ­āļāđˆāļ­āļ™āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨ āđ€āļžāļ·āđˆāļ­āļāļģāļˆāļąāļ”āđ€āļ—āļŠāļ•āđŒāļ—āļĩāđˆāļœāļĨāļĨāļąāļžāļ˜āđŒāđ„āļĄāđˆāđāļ™āđˆāļ™āļ­āļ™āđāļĨāļ°āļ‚āļķāđ‰āļ™āļāļąāļšāļˆāļąāļ‡āļŦāļ§āļ°āđ€āļ§āļĨāļē
  • āļ—āļ”āļŠāļ­āļš composable āļ—āļĩāđˆāđƒāļŠāđ‰āđ€āļžāļĩāļĒāļ‡ reactivity API āļ”āđ‰āļ§āļĒāļāļēāļĢāđ€āļĢāļĩāļĒāļāļĄāļąāļ™āđ‚āļ”āļĒāļ•āļĢāļ‡āđāļĨāļ°āļĒāļ·āļ™āļĒāļąāļ™āļœāļĨāļšāļ™ .value
  • mock āļ—āļĩāđˆāļ‚āļ­āļšāđ€āļ‚āļ•āļ‚āļ­āļ‡āđ‚āļĄāļ”āļđāļĨāļ”āđ‰āļ§āļĒ vi.mock āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļžāļĪāļ•āļīāļāļĢāļĢāļĄāđ€āļ„āļĢāļ·āļ­āļ‚āđˆāļēāļĒāļ„āļ‡āđ€āļŠāđ‰āļ™āļ„āļ‡āļ§āļēāđāļĨāļ°āļ—āļ”āļŠāļ­āļšāđ€āļŠāđ‰āļ™āļ—āļēāļ‡ error āđ„āļ”āđ‰
  • āđƒāļŠāđ‰ createTestingPinia({ createSpy: vi.fn }) āļŠāļģāļŦāļĢāļąāļšāđ€āļ—āļŠāļ•āđŒāļ„āļ­āļĄāđ‚āļžāđ€āļ™āļ™āļ•āđŒ āđāļĨāļ° stubActions: false āđ€āļĄāļ·āđˆāļ­āļ•āđ‰āļ­āļ‡āļ—āļ”āļŠāļ­āļšāļ•āļĢāļĢāļāļ°āļ‚āļ­āļ‡ store
  • query element āļœāđˆāļēāļ™āđāļ­āļ•āļ—āļĢāļīāļšāļīāļ§āļ•āđŒ data-test āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āđ€āļ—āļŠāļ•āđŒāļĨāđ‰āļĄāđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļˆāļĢāļīāļ‡āđ€āļ›āļĨāļĩāđˆāļĒāļ™ āđ„āļĄāđˆāđƒāļŠāđˆāđ€āļžāļĢāļēāļ°āļāļēāļĢāļ›āļĢāļąāļšāļŠāđ„āļ•āļĨāđŒ

āđ€āļĄāļ·āđˆāļ­āđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļāđāļžāļ•āđ€āļ—āļīāļĢāđŒāļ™āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰ āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļˆāļ°āļāļĨāļēāļĒāđ€āļ›āđ‡āļ™āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­āļ­āļ­āļāđāļšāļšāļĄāļēāļāļāļ§āđˆāļēāļ āļēāļĢāļ° āļ—āļĩāđˆāļ„āļ­āļĒāļ”āļąāļāļˆāļąāļš regression āļāđˆāļ­āļ™āļˆāļ°āļŦāļĨāļļāļ”āđ„āļ›āļ–āļķāļ‡āđ‚āļ›āļĢāļ”āļąāļāļŠāļąāļ™ āļŠāļģāļĢāļ§āļˆāđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļāļēāļĢāđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ Vue āđāļĨāļ° Nuxt āļ‰āļšāļąāļšāđ€āļ•āđ‡āļĄāđ€āļžāļ·āđˆāļ­āļŠāļĢāđ‰āļēāļ‡āļ—āļąāļāļĐāļ°āļ—āļĩāđˆāļžāļĢāđ‰āļ­āļĄāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ•āđˆāļ­āđ„āļ›

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āđāļ—āđ‡āļ

#vue
#testing
#vitest
#vue-test-utils
#interview

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

Vue 3 Composables Advanced Patterns

Vue 3 Composables āļ‚āļąāđ‰āļ™āļŠāļđāļ‡: āļĢāļđāļ›āđāļšāļšāļāļēāļĢāđƒāļŠāđ‰āļ‹āđ‰āļģāđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™ 2026

āļ„āļđāđˆāļĄāļ·āļ­ Vue 3 Composables āļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ: āļĢāļđāļ›āđāļšāļšāļāļēāļĢāđƒāļŠāđ‰āļ‹āđ‰āļģ āļāļēāļĢāļˆāļąāļ”āļāļēāļĢ Async āļāļēāļĢ Inject Dependencies āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļŸāļ­āļĢāđŒāļĄ āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒāļ‡āļēāļ™āđ€āļ—āļ„āļ™āļīāļ„āļ›āļĩ 2026

āđāļœāļ™āļ āļēāļžāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš state management Vue 3 Pinia āļāļąāļš Vuex

Vue 3 Pinia vs Vuex: State Management āļŠāļĄāļąāļĒāđƒāļŦāļĄāđˆāđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ 2026

āļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒāđ€āļ›āļĢāļĩāļĒāļšāđ€āļ—āļĩāļĒāļš Pinia āļāļąāļš Vuex: āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄ, TypeScript, Composition API, āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž, āļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāļĒāđ‰āļēāļĒ āđāļĨāļ°āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ Vue state management 2026

Nuxt 4 directory structure migration guide

Nuxt 4 āđƒāļ™āļ›āļĩ 2026: āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđ„āļ”āđ€āļĢāļāļ—āļ­āļĢāļĩāđƒāļŦāļĄāđˆāđāļĨāļ°āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļĒāđ‰āļēāļĒāļˆāļēāļ Nuxt 3

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļĒāđ‰āļēāļĒāļˆāļēāļ Nuxt 3 āđ„āļ›āļĒāļąāļ‡ Nuxt 4 āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđ„āļ”āđ€āļĢāļāļ—āļ­āļĢāļĩ app/ āđƒāļŦāļĄāđˆ singleton data fetching, shallow reactivity āđāļĨāļ°āļāļēāļĢāđāļĒāļāļšāļĢāļīāļšāļ— TypeScript āļžāļĢāđ‰āļ­āļĄāļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”āļˆāļĢāļīāļ‡