mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 21:54:50 +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,71 +1,51 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { nextTick } from 'vue'
|
||||
import { fireEvent, render, screen } from '@testing-library/vue'
|
||||
import type { ComponentProps } from 'vue-component-type-helpers'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import BaseThumbnail from '@/components/templates/thumbnails/BaseThumbnail.vue'
|
||||
|
||||
type ComponentInstance = InstanceType<typeof BaseThumbnail> & {
|
||||
error: boolean
|
||||
}
|
||||
|
||||
vi.mock('@vueuse/core', () => ({
|
||||
useEventListener: vi.fn()
|
||||
}))
|
||||
|
||||
describe('BaseThumbnail', () => {
|
||||
const mountThumbnail = (props = {}, slots = {}) => {
|
||||
return mount(BaseThumbnail, {
|
||||
props,
|
||||
function renderThumbnail(
|
||||
props: Partial<ComponentProps<typeof BaseThumbnail>> = {}
|
||||
) {
|
||||
return render(BaseThumbnail, {
|
||||
props: props as ComponentProps<typeof BaseThumbnail>,
|
||||
slots: {
|
||||
default: '<img src="/test.jpg" alt="test" />',
|
||||
...slots
|
||||
default: '<img src="/test.jpg" alt="test" />'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
it('renders slot content', () => {
|
||||
const wrapper = mountThumbnail()
|
||||
expect(wrapper.find('img').exists()).toBe(true)
|
||||
renderThumbnail()
|
||||
expect(screen.getByAltText('test')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('applies hover zoom with correct style', () => {
|
||||
const wrapper = mountThumbnail({ isHovered: true })
|
||||
const contentDiv = wrapper.find('.transform-gpu')
|
||||
expect(contentDiv.attributes('style')).toContain('transform')
|
||||
expect(contentDiv.attributes('style')).toContain('scale')
|
||||
renderThumbnail({ isHovered: true })
|
||||
const contentDiv = screen.getByTestId('thumbnail-content')
|
||||
expect(contentDiv).toHaveStyle({ transform: 'scale(1.04)' })
|
||||
})
|
||||
|
||||
it('applies custom hover zoom value', () => {
|
||||
const wrapper = mountThumbnail({ hoverZoom: 10, isHovered: true })
|
||||
const contentDiv = wrapper.find('.transform-gpu')
|
||||
expect(contentDiv.attributes('style')).toContain('scale(1.1)')
|
||||
renderThumbnail({ hoverZoom: 10, isHovered: true })
|
||||
const contentDiv = screen.getByTestId('thumbnail-content')
|
||||
expect(contentDiv).toHaveStyle({ transform: 'scale(1.1)' })
|
||||
})
|
||||
|
||||
it('does not apply scale when not hovered', () => {
|
||||
const wrapper = mountThumbnail({ isHovered: false })
|
||||
const contentDiv = wrapper.find('.transform-gpu')
|
||||
expect(contentDiv.attributes('style')).toBeUndefined()
|
||||
renderThumbnail({ isHovered: false })
|
||||
const contentDiv = screen.getByTestId('thumbnail-content')
|
||||
expect(contentDiv).not.toHaveAttribute('style')
|
||||
})
|
||||
|
||||
it('shows error state when image fails to load', async () => {
|
||||
const wrapper = mountThumbnail()
|
||||
const vm = wrapper.vm as ComponentInstance
|
||||
|
||||
// Manually set error since useEventListener is mocked
|
||||
vm.error = true
|
||||
await nextTick()
|
||||
|
||||
expect(
|
||||
wrapper.find('img[src="/assets/images/default-template.png"]').exists()
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('applies transition classes to content', () => {
|
||||
const wrapper = mountThumbnail()
|
||||
const contentDiv = wrapper.find('.transform-gpu')
|
||||
expect(contentDiv.classes()).toContain('transform-gpu')
|
||||
expect(contentDiv.classes()).toContain('transition-transform')
|
||||
expect(contentDiv.classes()).toContain('duration-1000')
|
||||
expect(contentDiv.classes()).toContain('ease-out')
|
||||
renderThumbnail()
|
||||
const img = screen.getByAltText('test')
|
||||
await fireEvent.error(img)
|
||||
expect(screen.getByRole('img')).toHaveAttribute(
|
||||
'src',
|
||||
'/assets/images/default-template.png'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user