Plugins & SSR

Preview — 3 of 10 questions

What is the key conceptual change when migrating a Vuex module to a Pinia store?

javascript
// BEFORE: Vuex module
const counterModule = {
  namespaced: true,
  state: () => ({ count: 0 }),
  mutations: {
    SET_COUNT(state, payload) { state.count = payload },
    INCREMENT(state) { state.count++ }
  },
  actions: {
    increment({ commit }) {
      commit('INCREMENT')
    },
    async fetchCount({ commit }) {
      const count = await api.getCount()
      commit('SET_COUNT', count)
    }
  },
  getters: {
    double: state => state.count * 2
  }
}

// AFTER: Pinia store
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  // No mutations — actions do everything
  actions: {
    increment() {
      this.count++ // Direct mutation
    },
    async fetchCount() {
      this.count = await api.getCount() // Direct mutation in async action
    }
  },
  getters: {
    double: (state) => state.count * 2
  }
})

// Component usage changes too:
// Vuex: store.dispatch('counter/increment'), store.commit('counter/SET_COUNT', 5)
// Pinia: counter.increment(), counter.count = 5 (or counter.$patch({ count: 5 }))
AReplace every mutation with an action — mutations no longer exist in Pinia
BWrap all actions in dispatch() calls using the Pinia dispatch helper
CConvert each Vuex module to a Pinia store, rename commit to $patch, and remove the mutations key
DConvert getters to computed properties and use setState instead of mutations

What does createTestingPinia from @pinia/testing provide over manual createPinia setup?

javascript
import { mount } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'
import { vi, describe, it, expect } from 'vitest'
import MyComponent from './MyComponent.vue'
import { useUserStore } from '@/stores/user'

describe('MyComponent', () => {
  it('displays user name from store', async () => {
    const wrapper = mount(MyComponent, {
      global: {
        plugins: [
          createTestingPinia({
            createSpy: vi.fn, // Use Vitest's vi.fn for spies
            initialState: {
              user: { user: { name: 'Alice', id: 1 }, isLoading: false }
            }
          })
        ]
      }
    })

    expect(wrapper.text()).toContain('Alice')
  })

  it('calls fetchUser action on mount', () => {
    const wrapper = mount(MyComponent, {
      global: {
        plugins: [createTestingPinia({ createSpy: vi.fn })]
      }
    })

    const userStore = useUserStore()
    // Actions are automatically stubbed (replaced with spies)
    expect(userStore.fetchUser).toHaveBeenCalledOnce()
  })

  it('handles action results with stubActions: false', async () => {
    const wrapper = mount(MyComponent, {
      global: {
        plugins: [createTestingPinia({
          createSpy: vi.fn,
          stubActions: false // Let real actions run (need API mocking)
        })]
      }
    })
  })
})
AIt provides a test database connection for store persistence testing
BIt creates a Pinia instance with all actions automatically mocked (replaced with empty functions/spies)
CIt generates TypeScript types for stores automatically
DIt is only useful for E2E testing, not unit testing

What information does the Pinia DevTools integration expose, and how does it work?

javascript
// What DevTools shows for each store:
// 1. Current state tree (live reactive)
// 2. All store IDs and their types
// 3. Action timeline:
//    - Action name and arguments
//    - State before and after
//    - Duration
//    - Errors if any

// Custom DevTools labels via store ID:
export const useCartStore = defineStore('cart', {
  // Store appears as "cart" in DevTools
})

// Custom timeline events in actions:
export const useUserStore = defineStore('user', () => {
  async function login(credentials) {
    // DevTools automatically captures:
    // - "login" action called with [credentials]
    // - State before: { user: null }
    // - State after: { user: { name: 'Alice' } }
    // - Duration: 234ms
  }
  return { login }
})

// State time-travel: clicking a past state in DevTools
// restores the store to that exact state
// (works because DevTools stores state snapshots)

// Trigger actions from DevTools console:
// __piniaDevtools.actions.increment()
ADevTools only show the current state — no history or action tracking
BDevTools are only available in development mode via a secret URL
CDevTools show full state tree, action history with arguments and results, state time-travel, and can trigger actions/mutations manually
DPinia DevTools are separate from Vue DevTools and require a different browser extension

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.