diff --git a/src/components/templates/TemplateWorkflowView.spec.ts b/src/components/templates/TemplateWorkflowView.spec.ts
index a70e828a5..6860797c6 100644
--- a/src/components/templates/TemplateWorkflowView.spec.ts
+++ b/src/components/templates/TemplateWorkflowView.spec.ts
@@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
+import { createI18n } from 'vue-i18n'
import TemplateWorkflowView from '@/components/templates/TemplateWorkflowView.vue'
import { TemplateInfo } from '@/types/workflowTemplateTypes'
@@ -53,10 +54,46 @@ vi.mock('@/components/templates/TemplateWorkflowList.vue', () => ({
}
}))
+vi.mock('@/components/templates/TemplateSearchBar.vue', () => ({
+ default: {
+ template: '
',
+ props: ['searchQuery', 'filteredCount'],
+ emits: ['update:searchQuery', 'clearFilters']
+ }
+}))
+
+vi.mock('@/components/templates/TemplateWorkflowCardSkeleton.vue', () => ({
+ default: {
+ template: ''
+ }
+}))
+
vi.mock('@vueuse/core', () => ({
useLocalStorage: () => 'grid'
}))
+vi.mock('@/composables/useIntersectionObserver', () => ({
+ useIntersectionObserver: vi.fn()
+}))
+
+vi.mock('@/composables/useLazyPagination', () => ({
+ useLazyPagination: (items: any) => ({
+ paginatedItems: items,
+ isLoading: { value: false },
+ hasMoreItems: { value: false },
+ loadNextPage: vi.fn(),
+ reset: vi.fn()
+ })
+}))
+
+vi.mock('@/composables/useTemplateFiltering', () => ({
+ useTemplateFiltering: (templates: any) => ({
+ searchQuery: { value: '' },
+ filteredTemplates: templates,
+ filteredCount: { value: templates.value?.length || 0 }
+ })
+}))
+
describe('TemplateWorkflowView', () => {
const createTemplate = (name: string): TemplateInfo => ({
name,
@@ -67,6 +104,18 @@ describe('TemplateWorkflowView', () => {
})
const mountView = (props = {}) => {
+ const i18n = createI18n({
+ legacy: false,
+ locale: 'en',
+ messages: {
+ en: {
+ templateWorkflows: {
+ loadingMore: 'Loading more...'
+ }
+ }
+ }
+ })
+
return mount(TemplateWorkflowView, {
props: {
title: 'Test Templates',
@@ -79,6 +128,9 @@ describe('TemplateWorkflowView', () => {
],
loading: null,
...props
+ },
+ global: {
+ plugins: [i18n]
}
})
}
diff --git a/src/components/templates/thumbnails/CompareSliderThumbnail.spec.ts b/src/components/templates/thumbnails/CompareSliderThumbnail.spec.ts
index 7d0fcc9c9..681d81238 100644
--- a/src/components/templates/thumbnails/CompareSliderThumbnail.spec.ts
+++ b/src/components/templates/thumbnails/CompareSliderThumbnail.spec.ts
@@ -12,6 +12,15 @@ vi.mock('@/components/templates/thumbnails/BaseThumbnail.vue', () => ({
}
}))
+vi.mock('@/components/common/LazyImage.vue', () => ({
+ default: {
+ name: 'LazyImage',
+ template:
+ '
',
+ props: ['src', 'alt', 'imageClass', 'imageStyle']
+ }
+}))
+
vi.mock('@vueuse/core', () => ({
useMouseInElement: () => ({
elementX: ref(50),
@@ -35,23 +44,24 @@ describe('CompareSliderThumbnail', () => {
it('renders both base and overlay images', () => {
const wrapper = mountThumbnail()
- const images = wrapper.findAll('img')
- expect(images.length).toBe(2)
- expect(images[0].attributes('src')).toBe('/base-image.jpg')
- expect(images[1].attributes('src')).toBe('/overlay-image.jpg')
+ const lazyImages = wrapper.findAllComponents({ name: 'LazyImage' })
+ expect(lazyImages.length).toBe(2)
+ expect(lazyImages[0].props('src')).toBe('/base-image.jpg')
+ expect(lazyImages[1].props('src')).toBe('/overlay-image.jpg')
})
it('applies correct alt text to both images', () => {
const wrapper = mountThumbnail({ alt: 'Custom Alt Text' })
- const images = wrapper.findAll('img')
- expect(images[0].attributes('alt')).toBe('Custom Alt Text')
- expect(images[1].attributes('alt')).toBe('Custom Alt Text')
+ const lazyImages = wrapper.findAllComponents({ name: 'LazyImage' })
+ expect(lazyImages[0].props('alt')).toBe('Custom Alt Text')
+ expect(lazyImages[1].props('alt')).toBe('Custom Alt Text')
})
it('applies clip-path style to overlay image', () => {
const wrapper = mountThumbnail()
- const overlay = wrapper.findAll('img')[1]
- expect(overlay.attributes('style')).toContain('clip-path')
+ const overlayLazyImage = wrapper.findAllComponents({ name: 'LazyImage' })[1]
+ const imageStyle = overlayLazyImage.props('imageStyle')
+ expect(imageStyle.clipPath).toContain('inset')
})
it('renders slider divider', () => {
diff --git a/src/components/templates/thumbnails/DefaultThumbnail.spec.ts b/src/components/templates/thumbnails/DefaultThumbnail.spec.ts
index bb754c0dd..ebe138a9e 100644
--- a/src/components/templates/thumbnails/DefaultThumbnail.spec.ts
+++ b/src/components/templates/thumbnails/DefaultThumbnail.spec.ts
@@ -11,6 +11,15 @@ vi.mock('@/components/templates/thumbnails/BaseThumbnail.vue', () => ({
}
}))
+vi.mock('@/components/common/LazyImage.vue', () => ({
+ default: {
+ name: 'LazyImage',
+ template:
+ '
',
+ props: ['src', 'alt', 'imageClass', 'imageStyle']
+ }
+}))
+
describe('DefaultThumbnail', () => {
const mountThumbnail = (props = {}) => {
return mount(DefaultThumbnail, {
@@ -25,9 +34,9 @@ describe('DefaultThumbnail', () => {
it('renders image with correct src and alt', () => {
const wrapper = mountThumbnail()
- const img = wrapper.find('img')
- expect(img.attributes('src')).toBe('/test-image.jpg')
- expect(img.attributes('alt')).toBe('Test Image')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ expect(lazyImage.props('src')).toBe('/test-image.jpg')
+ expect(lazyImage.props('alt')).toBe('Test Image')
})
it('applies scale transform when hovered', () => {
@@ -35,35 +44,43 @@ describe('DefaultThumbnail', () => {
isHovered: true,
hoverZoom: 10
})
- const img = wrapper.find('img')
- expect(img.attributes('style')).toContain('scale(1.1)')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ expect(lazyImage.props('imageStyle')).toEqual({ transform: 'scale(1.1)' })
})
it('does not apply scale transform when not hovered', () => {
const wrapper = mountThumbnail({
isHovered: false
})
- const img = wrapper.find('img')
- expect(img.attributes('style')).toBeUndefined()
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ expect(lazyImage.props('imageStyle')).toBeUndefined()
})
it('applies video styling for video type', () => {
const wrapper = mountThumbnail({
isVideo: true
})
- const img = wrapper.find('img')
- expect(img.classes()).toContain('w-full')
- expect(img.classes()).toContain('h-full')
- expect(img.classes()).toContain('object-cover')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ const imageClass = lazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('w-full')
+ expect(classString).toContain('h-full')
+ expect(classString).toContain('object-cover')
})
it('applies image styling for non-video type', () => {
const wrapper = mountThumbnail({
isVideo: false
})
- const img = wrapper.find('img')
- expect(img.classes()).toContain('max-w-full')
- expect(img.classes()).toContain('object-contain')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ const imageClass = lazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('max-w-full')
+ expect(classString).toContain('object-contain')
})
it('applies correct styling for webp images', () => {
@@ -71,8 +88,12 @@ describe('DefaultThumbnail', () => {
src: '/test-video.webp',
isVideo: true
})
- const img = wrapper.find('img')
- expect(img.classes()).toContain('object-cover')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ const imageClass = lazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('object-cover')
})
it('image is not draggable', () => {
@@ -83,11 +104,15 @@ describe('DefaultThumbnail', () => {
it('applies transition classes', () => {
const wrapper = mountThumbnail()
- const img = wrapper.find('img')
- expect(img.classes()).toContain('transform-gpu')
- expect(img.classes()).toContain('transition-transform')
- expect(img.classes()).toContain('duration-300')
- expect(img.classes()).toContain('ease-out')
+ const lazyImage = wrapper.findComponent({ name: 'LazyImage' })
+ const imageClass = lazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('transform-gpu')
+ expect(classString).toContain('transition-transform')
+ expect(classString).toContain('duration-300')
+ expect(classString).toContain('ease-out')
})
it('passes correct props to BaseThumbnail', () => {
diff --git a/src/components/templates/thumbnails/HoverDissolveThumbnail.spec.ts b/src/components/templates/thumbnails/HoverDissolveThumbnail.spec.ts
index b8b8b77d7..4ca00c668 100644
--- a/src/components/templates/thumbnails/HoverDissolveThumbnail.spec.ts
+++ b/src/components/templates/thumbnails/HoverDissolveThumbnail.spec.ts
@@ -11,6 +11,15 @@ vi.mock('@/components/templates/thumbnails/BaseThumbnail.vue', () => ({
}
}))
+vi.mock('@/components/common/LazyImage.vue', () => ({
+ default: {
+ name: 'LazyImage',
+ template:
+ '
',
+ props: ['src', 'alt', 'imageClass', 'imageStyle']
+ }
+}))
+
describe('HoverDissolveThumbnail', () => {
const mountThumbnail = (props = {}) => {
return mount(HoverDissolveThumbnail, {
@@ -27,31 +36,39 @@ describe('HoverDissolveThumbnail', () => {
it('renders both base and overlay images', () => {
const wrapper = mountThumbnail()
- const images = wrapper.findAll('img')
- expect(images.length).toBe(2)
- expect(images[0].attributes('src')).toBe('/base-image.jpg')
- expect(images[1].attributes('src')).toBe('/overlay-image.jpg')
+ const lazyImages = wrapper.findAllComponents({ name: 'LazyImage' })
+ expect(lazyImages.length).toBe(2)
+ expect(lazyImages[0].props('src')).toBe('/base-image.jpg')
+ expect(lazyImages[1].props('src')).toBe('/overlay-image.jpg')
})
it('applies correct alt text to both images', () => {
const wrapper = mountThumbnail({ alt: 'Custom Alt Text' })
- const images = wrapper.findAll('img')
- expect(images[0].attributes('alt')).toBe('Custom Alt Text')
- expect(images[1].attributes('alt')).toBe('Custom Alt Text')
+ const lazyImages = wrapper.findAllComponents({ name: 'LazyImage' })
+ expect(lazyImages[0].props('alt')).toBe('Custom Alt Text')
+ expect(lazyImages[1].props('alt')).toBe('Custom Alt Text')
})
it('makes overlay image visible when hovered', () => {
const wrapper = mountThumbnail({ isHovered: true })
- const overlayImage = wrapper.findAll('img')[1]
- expect(overlayImage.classes()).toContain('opacity-100')
- expect(overlayImage.classes()).not.toContain('opacity-0')
+ const overlayLazyImage = wrapper.findAllComponents({ name: 'LazyImage' })[1]
+ const imageClass = overlayLazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('opacity-100')
+ expect(classString).not.toContain('opacity-0')
})
it('makes overlay image hidden when not hovered', () => {
const wrapper = mountThumbnail({ isHovered: false })
- const overlayImage = wrapper.findAll('img')[1]
- expect(overlayImage.classes()).toContain('opacity-0')
- expect(overlayImage.classes()).not.toContain('opacity-100')
+ const overlayLazyImage = wrapper.findAllComponents({ name: 'LazyImage' })[1]
+ const imageClass = overlayLazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('opacity-0')
+ expect(classString).not.toContain('opacity-100')
})
it('passes isHovered prop to BaseThumbnail', () => {
@@ -62,21 +79,33 @@ describe('HoverDissolveThumbnail', () => {
it('applies transition classes to overlay image', () => {
const wrapper = mountThumbnail()
- const overlayImage = wrapper.findAll('img')[1]
- expect(overlayImage.classes()).toContain('transition-opacity')
- expect(overlayImage.classes()).toContain('duration-300')
+ const overlayLazyImage = wrapper.findAllComponents({ name: 'LazyImage' })[1]
+ const imageClass = overlayLazyImage.props('imageClass')
+ const classString = Array.isArray(imageClass)
+ ? imageClass.join(' ')
+ : imageClass
+ expect(classString).toContain('transition-opacity')
+ expect(classString).toContain('duration-300')
})
it('applies correct positioning to both images', () => {
const wrapper = mountThumbnail()
- const images = wrapper.findAll('img')
+ const lazyImages = wrapper.findAllComponents({ name: 'LazyImage' })
// Check base image
- expect(images[0].classes()).toContain('absolute')
- expect(images[0].classes()).toContain('inset-0')
+ const baseImageClass = lazyImages[0].props('imageClass')
+ const baseClassString = Array.isArray(baseImageClass)
+ ? baseImageClass.join(' ')
+ : baseImageClass
+ expect(baseClassString).toContain('absolute')
+ expect(baseClassString).toContain('inset-0')
// Check overlay image
- expect(images[1].classes()).toContain('absolute')
- expect(images[1].classes()).toContain('inset-0')
+ const overlayImageClass = lazyImages[1].props('imageClass')
+ const overlayClassString = Array.isArray(overlayImageClass)
+ ? overlayImageClass.join(' ')
+ : overlayImageClass
+ expect(overlayClassString).toContain('absolute')
+ expect(overlayClassString).toContain('inset-0')
})
})