---
description: 
globs: **/*.test.ts,**/__test__/components/**/*.ts,**/__test__/store/**/*.ts,**/__test__/mocks/**/*.ts
alwaysApply: false
---

## Vue Component Testing Best Practices
- This is a Nuxt.js app but we are testing with vitest outside of the Nuxt environment
- Nuxt is currently set to auto import so some vue files may need compute or ref imported
- Use pnpm when running termical commands and stay within the web directory.
- The directory for tests is located under `web/__test__` when running test just run `pnpm test`

### Setup
- Use `mount` from Vue Test Utils for component testing
- Stub complex child components that aren't the focus of the test
- Mock external dependencies and services

```typescript
import { mount } from '@vue/test-utils';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { createTestingPinia } from '@pinia/testing'
import { useSomeStore } from '@/stores/myStore'
import YourComponent from '~/components/YourComponent.vue';

// Mock dependencies
vi.mock('~/helpers/someHelper', () => ({
  SOME_CONSTANT: 'mocked-value',
}));

describe('YourComponent', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });
  
  it('renders correctly', () => {
    const wrapper = mount(YourComponent, {
      global: {
        plugins: [createTestingPinia()],
        stubs: {
          // Stub child components when needed
          ChildComponent: true,
        },
      },
    });

    const store = useSomeStore() // uses the testing pinia!
    // state can be directly manipulated
    store.name = 'my new name'

    // actions are stubbed by default, meaning they don't execute their code by default.
    // See below to customize this behavior.
    store.someAction()

    expect(store.someAction).toHaveBeenCalledTimes(1)
    
    // Assertions on components
    expect(wrapper.text()).toContain('Expected content');
  });
});
```

### Testing Patterns
- Test component behavior and output, not implementation details
- Verify that the expected elements are rendered
- Test component interactions (clicks, inputs, etc.)
- Check for expected prop handling and event emissions
- Use `createTestingPinia()` for mocking stores in components

### Finding Elements
- Use semantic queries like `find('button')` or `find('[data-test="id"]')` but prefer not to use data test ID's
- Find components with `findComponent(ComponentName)`
- Use `findAll` to check for multiple elements

### Assertions
- Assert on rendered text content with `wrapper.text()`
- Assert on element attributes with `element.attributes()`
- Verify element existence with `expect(element.exists()).toBe(true)`
- Check component state through rendered output

### Component Interaction
- Trigger events with `await element.trigger('click')`
- Set input values with `await input.setValue('value')`
- Test emitted events with `wrapper.emitted()`

### Mocking
- Mock external services and API calls
- Prefer not using mocks whenever possible
- Use `vi.mock()` for module-level mocks
- Specify return values for component methods with `vi.spyOn()`
- Reset mocks between tests with `vi.clearAllMocks()`
- Frequently used mocks are stored under `web/test/mocks`

### Async Testing
- Use `await nextTick()` for DOM updates
- Use `flushPromises()` for more complex promise chains
- Always await async operations before making assertions

## Store Testing with Pinia

### Basic Setup
- When testing Store files use `createPinia` and `setActivePinia`

```typescript
import { createPinia, setActivePinia } from 'pinia';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { useYourStore } from '~/store/your-store';

// Mock declarations must be at top level due to hoisting
const mockDependencyFn = vi.fn();

// Module mocks must use factory functions
vi.mock('~/store/dependency', () => ({
  useDependencyStore: () => ({
    someMethod: mockDependencyFn,
    someProperty: 'mockValue'
  })
}));

describe('Your Store', () => {
  let store: ReturnType<typeof useYourStore>;

  beforeEach(() => {
    setActivePinia(createPinia());
    store = useYourStore();
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.resetAllMocks();
  });

  it('tests some action', () => {
    store.someAction();
    expect(mockDependencyFn).toHaveBeenCalled();
  });
});
```

### Important Guidelines
1. **Store Initialization**
   - Use `createPinia()` instead of `createTestingPinia()` for most cases
   - Only use `createTestingPinia` if you specifically need its testing features
   - Let stores initialize with their natural default state instead of forcing initial state
   - Do not mock the store we're actually testing in the test file. That's why we're using `createPinia()`

2. **Vue Reactivity**
   - Ensure Vue reactivity imports are added to original store files as they may be missing because Nuxt auto import was turned on
   - Don't rely on Nuxt auto-imports in tests

   ```typescript
   // Required in store files, even with Nuxt auto-imports
   import { computed, ref, watchEffect } from 'vue';
   ```

3. **Mocking Best Practices**
   - Place all mock declarations at the top level
   - Use factory functions for module mocks to avoid hoisting issues
   
   ```typescript
   // ❌ Wrong - will cause hoisting issues
   const mockFn = vi.fn();
   vi.mock('module', () => ({ method: mockFn }));

   // ✅ Correct - using factory function
   vi.mock('module', () => {
     const mockFn = vi.fn();
     return { method: mockFn };
   });
   ```

4. **Testing Actions**
   - Test action side effects and state changes
   - Verify actions are called with correct parameters
   - Mock external dependencies appropriately
   
   ```typescript
   it('should handle action correctly', () => {
     store.yourAction();
     expect(mockDependencyFn).toHaveBeenCalledWith(
       expectedArg1,
       expectedArg2
     );
     expect(store.someState).toBe(expectedValue);
   });
   ```

5. **Common Pitfalls**
   - Don't mix mock declarations and module mocks incorrectly
   - Avoid relying on Nuxt's auto-imports in test environment
   - Clear mocks between tests to ensure isolation
   - Remember that `vi.mock()` calls are hoisted

### Testing State & Getters
- Test computed properties by accessing them directly
- Verify state changes after actions
- Test getter dependencies are properly mocked

```typescript
it('computes derived state correctly', () => {
  store.setState('new value');
  expect(store.computedValue).toBe('expected result');
});
```

### Testing Complex Interactions
- Test store interactions with other stores
- Verify proper error handling
- Test async operations completely

```typescript
it('handles async operations', async () => {
  const promise = store.asyncAction();
  expect(store.status).toBe('loading');
  await promise;
  expect(store.status).toBe('success');
});
```

### Testing Actions
- Verify actions are called with the right parameters
- Test action side effects if not stubbed
- Override specific action implementations when needed

```typescript
// Test action calls
store.yourAction(params);
expect(store.yourAction).toHaveBeenCalledWith(params);

// Test with real implementation
const pinia = createTestingPinia({
  createSpy: vi.fn,
  stubActions: false,
});
```

### Testing State & Getters
- Set initial state for focused testing
- Test computed properties by accessing them directly
- Verify state changes by updating the store

