mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 13:41:59 +00:00
test: migrate 8 hard-case component tests from VTU to VTL (Phase 3) (#10493)
## Summary Phase 3 of the VTL migration: migrate 8 hard-case component tests from @vue/test-utils to @testing-library/vue (68 tests). Stacked on #10490. ## Changes - **What**: Migrate SignInForm, CurrentUserButton, NodeSearchBoxPopover, BaseThumbnail, JobAssetsList, SelectionToolbox, QueueOverlayExpanded, PackVersionSelectorPopover from VTU to VTL - **`wrapper.vm` elimination**: 13 instances across 4 files (5 in SignInForm, 3 in CurrentUserButton, 3 in PackVersionSelectorPopover, 2 in BaseThumbnail) replaced with user interactions or removed - **`vm.$emit()` on stubs**: Interactive stubs with `setup(_, { emit })` expose buttons or closure-based emit functions (QueueOverlayExpanded, NodeSearchBoxPopover, JobAssetsList) - **Removed**: 6 change-detector/redundant tests, 3 `@ts-expect-error` annotations, `PackVersionSelectorVM` interface, `getVM` helper - **BaseThumbnail**: Removed `useEventListener` mock — real event handler attaches, `fireEvent.error(img)` triggers error state ## Review Focus - Interactive stub patterns: `JobAssetsListStub` and `NodeSearchBoxStub` use closure-based emit functions to trigger parent event handlers without `vm.$emit` - SignInForm form submission test fills PrimeVue Form fields via `userEvent.type` and submits via button click (replaces `vm.onSubmit()` direct call) - CurrentUserButton Popover stub tracks open/close state reactively - JobAssetsList: file-level `eslint-disable` for `no-container`/`no-node-access`/`prefer-user-event` since stubs lack ARIA roles and hover tests need `fireEvent` ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10493-test-migrate-8-hard-case-component-tests-from-VTU-to-VTL-Phase-3-32e6d73d365081f88097df634606d7e3) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { render, screen } from '@testing-library/vue'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { defineComponent } from 'vue'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { JobListItem } from '@/composables/queue/useJobList'
|
||||
@@ -25,61 +27,79 @@ const JobFiltersBarStub = {
|
||||
template: '<div />'
|
||||
}
|
||||
|
||||
const JobAssetsListStub = {
|
||||
name: 'JobAssetsList',
|
||||
template: '<div class="job-assets-list-stub" />'
|
||||
const testJob: JobListItem = {
|
||||
id: 'job-1',
|
||||
title: 'Job 1',
|
||||
meta: 'meta',
|
||||
state: 'pending'
|
||||
}
|
||||
|
||||
const JobAssetsListStub = defineComponent({
|
||||
name: 'JobAssetsList',
|
||||
setup(_, { emit }) {
|
||||
return {
|
||||
triggerCancel: () => emit('cancel-item', testJob),
|
||||
triggerDelete: () => emit('delete-item', testJob),
|
||||
triggerView: () => emit('view-item', testJob)
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="job-assets-list-stub">
|
||||
<button data-testid="stub-cancel" @click="triggerCancel()" />
|
||||
<button data-testid="stub-delete" @click="triggerDelete()" />
|
||||
<button data-testid="stub-view" @click="triggerView()" />
|
||||
</div>
|
||||
`
|
||||
})
|
||||
|
||||
const JobContextMenuStub = {
|
||||
template: '<div />'
|
||||
}
|
||||
|
||||
const createJob = (): JobListItem => ({
|
||||
id: 'job-1',
|
||||
title: 'Job 1',
|
||||
meta: 'meta',
|
||||
state: 'pending'
|
||||
})
|
||||
const defaultProps = {
|
||||
headerTitle: 'Jobs',
|
||||
queuedCount: 1,
|
||||
selectedJobTab: 'All' as const,
|
||||
selectedWorkflowFilter: 'all' as const,
|
||||
selectedSortMode: 'mostRecent' as const,
|
||||
displayedJobGroups: [],
|
||||
hasFailedJobs: false
|
||||
}
|
||||
|
||||
const mountComponent = () =>
|
||||
mount(QueueOverlayExpanded, {
|
||||
props: {
|
||||
headerTitle: 'Jobs',
|
||||
queuedCount: 1,
|
||||
selectedJobTab: 'All',
|
||||
selectedWorkflowFilter: 'all',
|
||||
selectedSortMode: 'mostRecent',
|
||||
displayedJobGroups: [],
|
||||
hasFailedJobs: false
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
QueueOverlayHeader: QueueOverlayHeaderStub,
|
||||
JobFiltersBar: JobFiltersBarStub,
|
||||
JobAssetsList: JobAssetsListStub,
|
||||
JobContextMenu: JobContextMenuStub
|
||||
}
|
||||
}
|
||||
})
|
||||
const stubs = {
|
||||
QueueOverlayHeader: QueueOverlayHeaderStub,
|
||||
JobFiltersBar: JobFiltersBarStub,
|
||||
JobAssetsList: JobAssetsListStub,
|
||||
JobContextMenu: JobContextMenuStub
|
||||
}
|
||||
|
||||
describe('QueueOverlayExpanded', () => {
|
||||
it('renders JobAssetsList', () => {
|
||||
const wrapper = mountComponent()
|
||||
expect(wrapper.find('.job-assets-list-stub').exists()).toBe(true)
|
||||
const { container } = render(QueueOverlayExpanded, {
|
||||
props: defaultProps,
|
||||
global: { stubs }
|
||||
})
|
||||
// eslint-disable-next-line testing-library/no-container, testing-library/no-node-access
|
||||
expect(container.querySelector('.job-assets-list-stub')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('re-emits list item actions from JobAssetsList', async () => {
|
||||
const wrapper = mountComponent()
|
||||
const job = createJob()
|
||||
const jobAssetsList = wrapper.findComponent({ name: 'JobAssetsList' })
|
||||
const user = userEvent.setup()
|
||||
const onCancelItem = vi.fn<(item: JobListItem) => void>()
|
||||
const onDeleteItem = vi.fn<(item: JobListItem) => void>()
|
||||
const onViewItem = vi.fn<(item: JobListItem) => void>()
|
||||
|
||||
jobAssetsList.vm.$emit('cancel-item', job)
|
||||
jobAssetsList.vm.$emit('delete-item', job)
|
||||
jobAssetsList.vm.$emit('view-item', job)
|
||||
await wrapper.vm.$nextTick()
|
||||
render(QueueOverlayExpanded, {
|
||||
props: { ...defaultProps, onCancelItem, onDeleteItem, onViewItem },
|
||||
global: { stubs }
|
||||
})
|
||||
|
||||
expect(wrapper.emitted('cancelItem')?.[0]).toEqual([job])
|
||||
expect(wrapper.emitted('deleteItem')?.[0]).toEqual([job])
|
||||
expect(wrapper.emitted('viewItem')?.[0]).toEqual([job])
|
||||
await user.click(screen.getByTestId('stub-cancel'))
|
||||
await user.click(screen.getByTestId('stub-delete'))
|
||||
await user.click(screen.getByTestId('stub-view'))
|
||||
|
||||
expect(onCancelItem).toHaveBeenCalledWith(testJob)
|
||||
expect(onDeleteItem).toHaveBeenCalledWith(testJob)
|
||||
expect(onViewItem).toHaveBeenCalledWith(testJob)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user