test: add standardized test-utils with Pinia + i18n defaults

Recreates src/utils/test-utils.ts (removed in #10471) as the canonical
shared render wrapper for VTL component tests.

Provides:
- renderWithDefaults(): auto-configures Pinia (stubActions: false),
  vue-i18n (English), and common directive stubs (tooltip)
- Optional userEvent instance (opt out via setupUser: false)
- Re-exports screen from @testing-library/vue

Eliminates duplicated createTestingPinia + createI18n boilerplate
across 97+ test files.

Part of: COMP-02 (standardize Pinia store test mocking patterns)
This commit is contained in:
bymyself
2026-03-27 13:27:06 -07:00
parent e809d74192
commit 69239ca2d5
2 changed files with 114 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest'
import { render, screen } from '@/utils/test-utils'
import { defineComponent, h } from 'vue'
const TestButton = defineComponent({
props: { label: { type: String, required: true } },
setup(props) {
return () => h('button', { 'data-testid': 'test-btn' }, props.label)
}
})
describe('test-utils', () => {
it('renders a component with default plugins', () => {
render(TestButton, { props: { label: 'Click me' } })
expect(screen.getByTestId('test-btn')).toHaveTextContent('Click me')
})
it('provides a userEvent instance by default', () => {
const { user } = render(TestButton, { props: { label: 'Click' } })
expect(user).toBeDefined()
})
it('allows opting out of userEvent', () => {
const { user } = render(TestButton, {
props: { label: 'Click' },
setupUser: false
})
expect(user).toBeUndefined()
})
})

82
src/utils/test-utils.ts Normal file
View File

@@ -0,0 +1,82 @@
import type { RenderResult } from '@testing-library/vue'
import type { ComponentMountingOptions } from '@vue/test-utils'
import { createTestingPinia } from '@pinia/testing'
import { render, screen } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import { createI18n } from 'vue-i18n'
import enMessages from '@/locales/en/main.json'
/**
* Creates the default set of Vue plugins for component tests.
*
* - Pinia with `stubActions: false` (actions execute, but are spied)
* - vue-i18n with English locale
*
* Pass additional plugins via the `plugins` option in `renderWithDefaults`.
*/
function createDefaultPlugins() {
return [
createTestingPinia({ stubActions: false }),
createI18n({
legacy: false,
locale: 'en',
messages: { en: enMessages }
})
]
}
/**
* Common directive stubs for components that use PrimeVue/custom directives.
* Prevents "Failed to resolve directive" warnings in test output.
*/
const defaultDirectiveStubs: Record<string, () => void> = {
tooltip: () => {}
}
type RenderWithDefaultsResult = RenderResult & {
user: ReturnType<typeof userEvent.setup> | undefined
}
/**
* Renders a Vue component with standard test infrastructure pre-configured:
* - Pinia testing store (actions execute but are spied)
* - vue-i18n with English messages
* - Common directive stubs (tooltip)
* - Optional userEvent instance
*
* @example
* ```ts
* import { render, screen } from '@/utils/test-utils'
*
* it('renders button text', async () => {
* const { user } = render(MyComponent, { props: { label: 'Click' } })
* expect(screen.getByRole('button')).toHaveTextContent('Click')
* await user!.click(screen.getByRole('button'))
* })
* ```
*/
function renderWithDefaults<C>(
component: C,
options?: ComponentMountingOptions<C> & { setupUser?: boolean }
): RenderWithDefaultsResult {
const { setupUser = true, global: globalOptions, ...rest } = options ?? {}
const user = setupUser ? userEvent.setup() : undefined
const result = render(component as Parameters<typeof render>[0], {
global: {
plugins: [...createDefaultPlugins(), ...(globalOptions?.plugins ?? [])],
stubs: globalOptions?.stubs,
directives: {
...defaultDirectiveStubs,
...globalOptions?.directives
}
},
...rest
} as Parameters<typeof render>[1])
return { ...result, user }
}
export { renderWithDefaults as render, screen }