Compare commits

...

11 Commits

Author SHA1 Message Date
GitHub Action
dcbd653343 [automated] Apply ESLint and Oxfmt fixes 2026-04-07 01:00:31 +00:00
bymyself
e2301b630c fix: use render<C> generic and explicit RenderOptions type
Replace opaque Parameters<typeof render>[0/1] assertions with
render<C> generic call and RenderOptions<C> type annotation.

Addresses review feedback:
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10628#discussion_r3011698548
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10628#discussion_r3011696861
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10628#discussion_r3011695091
2026-04-06 17:57:25 -07:00
bymyself
46cb9fdcfb fix: correct misleading JSDoc about stubs auto-application
renderWithDefaults only merges plugins and directives, not stubs.
Updated doc to accurately describe behavior.

Addresses review feedback:
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10628#discussion_r3004203297
2026-04-06 17:57:25 -07:00
bymyself
f6aa48ecc6 fix: remove primitive UI stubs (Button, Dialog) from shared test-utils
Tests should import and register real PrimeVue components instead of
relying on centralized primitive stubs that hide integration behavior.

Addresses review feedback:
https://github.com/Comfy-Org/ComfyUI_frontend/pull/10628#discussion_r3004203300
2026-04-06 17:57:25 -07:00
Alexander Brown
409fdbd815 Merge branch 'main' into test/standardize-test-utils 2026-03-30 12:04:15 -07:00
GitHub Action
1f818ba529 [automated] Apply ESLint and Oxfmt fixes 2026-03-28 11:43:15 +00:00
bymyself
8680791f4a fix: remove unused emit declaration and eslint-disable directive 2026-03-28 04:40:10 -07:00
bymyself
c831562ec1 fix: suppress Vue ESLint rules for inline test component stubs 2026-03-28 03:39:29 -07:00
bymyself
35f79b7cd3 feat: add PrimeVue component stubs to test-utils (COMP-03) 2026-03-27 22:00:33 -07:00
GitHub Action
90a819bc87 [automated] Apply ESLint and Oxfmt fixes 2026-03-27 20:30:19 +00:00
bymyself
69239ca2d5 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)
2026-03-27 13:27:06 -07:00
2 changed files with 182 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
/* eslint-disable vue/one-component-per-file */
import { describe, expect, it } from 'vitest'
import { render, screen, stubs } 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()
})
})
describe('stubs', () => {
describe('Skeleton', () => {
it('renders with data-testid', () => {
const Wrapper = defineComponent({
setup() {
return () => h(stubs.Skeleton)
}
})
render(Wrapper)
expect(screen.getByTestId('skeleton')).toBeDefined()
})
})
})

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

@@ -0,0 +1,135 @@
/* eslint-disable vue/one-component-per-file, vue/require-prop-types */
import type { RenderOptions, 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 { defineComponent, h } from 'vue'
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: () => {}
}
/**
* PrimeVue component stubs for unit/component tests.
*
* Use via `global.stubs` in render options:
* ```ts
* render(MyComponent, { global: { stubs: { Skeleton: stubs.Skeleton } } })
* ```
*
* Or use `renderWithDefaults` which provides plugins and directives.
* Import `stubs` and pass them via `global.stubs` when needed.
*/
const SkeletonStub = defineComponent({
name: 'Skeleton',
setup() {
return () => h('div', { 'data-testid': 'skeleton' })
}
})
const TagStub = defineComponent({
name: 'Tag',
props: ['value', 'severity'],
setup(props, { slots }) {
return () =>
h('span', { 'data-testid': 'tag' }, slots.default?.() ?? props.value)
}
})
const BadgeStub = defineComponent({
name: 'Badge',
props: ['value', 'severity'],
setup(props) {
return () => h('span', { 'data-testid': 'badge' }, props.value)
}
})
const MessageStub = defineComponent({
name: 'Message',
props: ['severity', 'closable'],
setup(_, { slots }) {
return () =>
h('div', { 'data-testid': 'message', role: 'alert' }, slots.default?.())
}
})
const stubs = {
Skeleton: SkeletonStub,
Tag: TagStub,
Badge: BadgeStub,
Message: MessageStub
} as const
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<C>(component, {
global: {
...globalOptions,
plugins: [...createDefaultPlugins(), ...(globalOptions?.plugins ?? [])],
directives: {
...defaultDirectiveStubs,
...globalOptions?.directives
}
},
...rest
} as RenderOptions<C>)
return { ...result, user }
}
export { renderWithDefaults as render, screen, stubs }