New Jan 6, 2025

Writing Pinia Store Tests with `$subscribe` in Vue 3

The Giants All from DEV Community View Writing Pinia Store Tests with `$subscribe` in Vue 3 on dev.to

Writing Pinia Tests with $subscribe in Vue 3

This tutorial will guide you through writing tests for Pinia stores in Vue 3, especially when dealing with stores that use the $subscribe method to react to state changes. We'll use a simplified example of a useUserStore that depends on another store (useSettingsStore) and updates its state when the settings store changes.

Table of Contents

  1. Introduction
  2. Setting Up the Environment
  3. Understanding the Stores
  4. Writing the Test
    • Mocking External Dependencies
    • Creating a Test Component
    • Setting Up the Test
    • Testing the $subscribe Behaviour
    • Handling Errors
  5. Conclusion

Introduction

Pinia is the official state management library for Vue 3. It provides a simple and flexible API for managing global state in your application. When writing tests for Pinia stores, especially those that use $subscribe to react to state changes, you need to mock dependencies and simulate state changes to ensure your store behaves as expected.

In this tutorial, we'll write tests for a useUserStore that subscribes to changes in another store (useSettingsStore). We'll use vitest and @vue/test-utils for testing.

Setting Up the Environment

Before writing tests, ensure you have the following dependencies installed:

npm install vitest @vue/test-utils @pinia/testing

Understanding the Stores

useUserStore

This store depends on another store:

The useUserStore subscribes to changes in the useSettingsStore using $subscribe and updates its userPreferences state whenever the settings store changes.

export const useUserStore = defineStore('user-store', () => {
  const userPreferences = ref<UserPreferences>({ theme: 'light', notifications: true })
  const settingsStore = useSettingsStore()

const updatePreferences = () => { userPreferences.value = { theme: settingsStore.theme, notifications: settingsStore.notificationsEnabled, } }

// Subscribe to changes in the settings store settingsStore.$subscribe((_mutation, _state) => { updatePreferences() })

return { userPreferences, } })

useSettingsStore

This store manages user settings like theme and notifications.

export const useSettingsStore = defineStore('settings-store', () => {
  const theme = ref<'light' | 'dark'>('light')
  const notificationsEnabled = ref<boolean>(true)

const toggleTheme = () => { theme.value = theme.value === 'light' ? 'dark' : 'light' }

const toggleNotifications = () => { notificationsEnabled.value = !notificationsEnabled.value }

return { theme, notificationsEnabled, toggleTheme, toggleNotifications, } })

Writing the Test

Mocking External Dependencies

To test useUserStore, we need to mock external dependencies.

vi.mock('@cct/notifications', () => ({
  useNotifications: () => ({
    error: vi.fn(),
  }),
}))

Creating a Test Component

We'll create a test component that uses the stores to simulate real-world usage.

const TestComponent = defineComponent({
  setup() {
    const userStore = useUserStore()
    const settingsStore = useSettingsStore()
    return {
      userStore,
      settingsStore,
    }
  },
  template: '<div></div>',
})

Setting Up the Test

We'll use createTestingPinia to set up the test environment.

describe('useUserStore', () => {
  let wrapper: any
  let userStore: any
  let settingsStore: any

beforeEach(() => { wrapper = mount(TestComponent, { global: { plugins: [ createTestingPinia({ initialState: { 'user-store': { userPreferences: { theme: 'light', notifications: true }, }, 'settings-store': { theme: 'light', notificationsEnabled: true, }, }, createSpy: vi.fn, }), ], }, })

// Get store instances userStore = useUserStore() settingsStore = useSettingsStore() }) })

Testing the $subscribe Behavior

We'll test that the userPreferences state in useUserStore updates correctly when the settingsStore changes.

it('should update userPreferences when settingsStore changes', async () => {
  // Change the theme in the settings store
  settingsStore.toggleTheme()

// Verify the userPreferences state expect(userStore.userPreferences).toEqual({ theme: 'dark', notifications: true, })

// Toggle notifications settingsStore.toggleNotifications()

// Verify the userPreferences state expect(userStore.userPreferences).toEqual({ theme: 'dark', notifications: false, }) })

Handling Errors

We'll also test that the store handles errors gracefully.

it('should handle errors gracefully', async () => {
  // Simulate an error in the settings store
  settingsStore.theme = 'invalid-theme' as any

// Verify the userPreferences state remains unchanged expect(userStore.userPreferences).toEqual({ theme: 'light', notifications: true, }) })

Conclusion

Testing Pinia stores, especially those with $subscribe, requires careful mocking of dependencies and simulating state changes. By following this tutorial, you should be able to write robust tests for your Pinia stores in Vue 3.

For more advanced testing scenarios, refer to the official documentation for Pinia and Vitest.

Scroll to top