mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-26 09:19:43 +00:00
[fix] Make gallery navigation buttons visible on mobile devices (#3953)
This commit is contained in:
177
src/components/sidebar/tabs/queue/ResultGallery.spec.ts
Normal file
177
src/components/sidebar/tabs/queue/ResultGallery.spec.ts
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import PrimeVue from 'primevue/config'
|
||||||
|
import Galleria from 'primevue/galleria'
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
import { createApp, nextTick } from 'vue'
|
||||||
|
|
||||||
|
import type { NodeId } from '@/schemas/comfyWorkflowSchema'
|
||||||
|
import type { ResultItemImpl } from '@/stores/queueStore'
|
||||||
|
|
||||||
|
import ResultGallery from './ResultGallery.vue'
|
||||||
|
|
||||||
|
type MockResultItem = Partial<ResultItemImpl> & {
|
||||||
|
filename: string
|
||||||
|
subfolder: string
|
||||||
|
type: string
|
||||||
|
nodeId: NodeId
|
||||||
|
mediaType: string
|
||||||
|
id?: string
|
||||||
|
url?: string
|
||||||
|
isImage?: boolean
|
||||||
|
isVideo?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ResultGallery', () => {
|
||||||
|
// Mock ComfyImage and ResultVideo components
|
||||||
|
const mockComfyImage = {
|
||||||
|
name: 'ComfyImage',
|
||||||
|
template: '<div class="mock-comfy-image" data-testid="comfy-image"></div>',
|
||||||
|
props: ['src', 'contain', 'alt']
|
||||||
|
}
|
||||||
|
|
||||||
|
const mockResultVideo = {
|
||||||
|
name: 'ResultVideo',
|
||||||
|
template:
|
||||||
|
'<div class="mock-result-video" data-testid="result-video"></div>',
|
||||||
|
props: ['result']
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sample gallery items - using mock instances with only required properties
|
||||||
|
const mockGalleryItems: MockResultItem[] = [
|
||||||
|
{
|
||||||
|
filename: 'image1.jpg',
|
||||||
|
subfolder: 'outputs',
|
||||||
|
type: 'output',
|
||||||
|
nodeId: '123' as NodeId,
|
||||||
|
mediaType: 'images',
|
||||||
|
isImage: true,
|
||||||
|
isVideo: false,
|
||||||
|
url: 'image1.jpg',
|
||||||
|
id: '1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
filename: 'image2.jpg',
|
||||||
|
subfolder: 'outputs',
|
||||||
|
type: 'output',
|
||||||
|
nodeId: '456' as NodeId,
|
||||||
|
mediaType: 'images',
|
||||||
|
isImage: true,
|
||||||
|
isVideo: false,
|
||||||
|
url: 'image2.jpg',
|
||||||
|
id: '2'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const app = createApp({})
|
||||||
|
app.use(PrimeVue)
|
||||||
|
|
||||||
|
// Create mock elements for Galleria to find
|
||||||
|
document.body.innerHTML = `
|
||||||
|
<div id="app"></div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// Clean up any elements added to body
|
||||||
|
document.body.innerHTML = ''
|
||||||
|
vi.restoreAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
const mountGallery = (props = {}) => {
|
||||||
|
return mount(ResultGallery, {
|
||||||
|
global: {
|
||||||
|
plugins: [PrimeVue],
|
||||||
|
components: {
|
||||||
|
Galleria,
|
||||||
|
ComfyImage: mockComfyImage,
|
||||||
|
ResultVideo: mockResultVideo
|
||||||
|
},
|
||||||
|
stubs: {
|
||||||
|
teleport: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
allGalleryItems: mockGalleryItems as unknown as ResultItemImpl[],
|
||||||
|
activeIndex: 0,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
attachTo: document.getElementById('app') || undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders Galleria component with correct props', async () => {
|
||||||
|
const wrapper = mountGallery()
|
||||||
|
|
||||||
|
await nextTick() // Wait for component to mount
|
||||||
|
|
||||||
|
const galleria = wrapper.findComponent(Galleria)
|
||||||
|
expect(galleria.exists()).toBe(true)
|
||||||
|
expect(galleria.props('value')).toEqual(mockGalleryItems)
|
||||||
|
expect(galleria.props('showIndicators')).toBe(false)
|
||||||
|
expect(galleria.props('showItemNavigators')).toBe(true)
|
||||||
|
expect(galleria.props('fullScreen')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows gallery when activeIndex changes from -1', async () => {
|
||||||
|
const wrapper = mountGallery({ activeIndex: -1 })
|
||||||
|
|
||||||
|
// Initially galleryVisible should be false
|
||||||
|
const vm: any = wrapper.vm
|
||||||
|
expect(vm.galleryVisible).toBe(false)
|
||||||
|
|
||||||
|
// Change activeIndex
|
||||||
|
await wrapper.setProps({ activeIndex: 0 })
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// galleryVisible should become true
|
||||||
|
expect(vm.galleryVisible).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should render the component properly', () => {
|
||||||
|
// This is a meta-test to confirm the component mounts properly
|
||||||
|
const wrapper = mountGallery()
|
||||||
|
|
||||||
|
// We can't directly test the compiled CSS, but we can verify the component renders
|
||||||
|
expect(wrapper.exists()).toBe(true)
|
||||||
|
|
||||||
|
// Verify that the Galleria component exists and is properly mounted
|
||||||
|
const galleria = wrapper.findComponent(Galleria)
|
||||||
|
expect(galleria.exists()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ensures correct configuration for mobile viewport', async () => {
|
||||||
|
// Mock window.matchMedia to simulate mobile viewport
|
||||||
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
|
writable: true,
|
||||||
|
value: vi.fn().mockImplementation((query) => ({
|
||||||
|
matches: query.includes('max-width: 768px'),
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: vi.fn(),
|
||||||
|
removeListener: vi.fn(),
|
||||||
|
addEventListener: vi.fn(),
|
||||||
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn()
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mountGallery()
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
// Verify mobile media query is working
|
||||||
|
expect(window.matchMedia('(max-width: 768px)').matches).toBe(true)
|
||||||
|
|
||||||
|
// Check if the component renders with Galleria
|
||||||
|
const galleria = wrapper.findComponent(Galleria)
|
||||||
|
expect(galleria.exists()).toBe(true)
|
||||||
|
|
||||||
|
// Check that our PT props for positioning work correctly
|
||||||
|
const pt = galleria.props('pt') as any
|
||||||
|
expect(pt?.prevButton?.style).toContain('position: fixed')
|
||||||
|
expect(pt?.nextButton?.style).toContain('position: fixed')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Additional tests for interaction could be added once we can reliably
|
||||||
|
// test Galleria component in fullscreen mode
|
||||||
|
})
|
||||||
@@ -144,4 +144,12 @@ img.galleria-image {
|
|||||||
/* Set z-index so the close button doesn't get hidden behind the image when image is large */
|
/* Set z-index so the close button doesn't get hidden behind the image when image is large */
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile/tablet specific fixes */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.p-galleria-prev-button,
|
||||||
|
.p-galleria-next-button {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user