diff --git a/docs/testing/vitest-patterns.md b/docs/testing/vitest-patterns.md index 2eb7c8e09..9c7fef7c2 100644 --- a/docs/testing/vitest-patterns.md +++ b/docs/testing/vitest-patterns.md @@ -30,6 +30,10 @@ describe('MyStore', () => { **Why `stubActions: false`?** By default, testing pinia stubs all actions. Set to `false` when testing actual store behavior. +## i18n in Component Tests + +Use real `createI18n` with empty messages instead of mocking `vue-i18n`. See `SearchBox.test.ts` for example. + ## Mock Patterns ### Reset all mocks at once diff --git a/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts b/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts index 1863b90b7..ae5cd988b 100644 --- a/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts +++ b/src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts @@ -1,44 +1,19 @@ import { mount } from '@vue/test-utils' -import { describe, expect, it, vi } from 'vitest' +import { createTestingPinia } from '@pinia/testing' +import { describe, expect, it } from 'vitest' +import { createI18n } from 'vue-i18n' import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBrowser' import ModelInfoPanel from './ModelInfoPanel.vue' -vi.mock('vue-i18n', () => ({ - useI18n: () => ({ - t: (key: string, params?: Record) => - params ? `${key}:${JSON.stringify(params)}` : key - }) -})) - -vi.mock( - '@/components/rightSidePanel/layout/PropertiesAccordionItem.vue', - () => ({ - default: { - name: 'PropertiesAccordionItem', - template: ` -
-
-
-
- ` - } - }) -) - -vi.mock('./ModelInfoField.vue', () => ({ - default: { - name: 'ModelInfoField', - props: ['label'], - template: ` -
- {{ label }} - -
- ` - } -})) +const i18n = createI18n({ + legacy: false, + locale: 'en', + messages: { en: {} }, + missingWarn: false, + fallbackWarn: false +}) describe('ModelInfoPanel', () => { const createMockAsset = ( @@ -63,6 +38,7 @@ describe('ModelInfoPanel', () => { return mount(ModelInfoPanel, { props: { asset }, global: { + plugins: [createTestingPinia({ stubActions: false }), i18n], mocks: { $t: (key: string, params?: Record) => params ? `${key}:${JSON.stringify(params)}` : key @@ -72,9 +48,9 @@ describe('ModelInfoPanel', () => { } describe('Basic Info Section', () => { - it('renders panel title', () => { + it('renders basic info section', () => { const wrapper = mountPanel(createMockAsset()) - expect(wrapper.text()).toContain('assetBrowser.modelInfo.title') + expect(wrapper.text()).toContain('assetBrowser.modelInfo.basicInfo') }) it('displays asset filename', () => { @@ -83,47 +59,41 @@ describe('ModelInfoPanel', () => { expect(wrapper.text()).toContain('my-model.safetensors') }) - it('displays display_name from user_metadata when present', () => { + it('displays name from user_metadata when present', () => { const asset = createMockAsset({ - user_metadata: { display_name: 'My Custom Model' } + user_metadata: { name: 'My Custom Model' } }) const wrapper = mountPanel(asset) expect(wrapper.text()).toContain('My Custom Model') }) - it('falls back to asset name when display_name not present', () => { + it('falls back to asset name when user_metadata.name not present', () => { const asset = createMockAsset({ name: 'fallback-model.safetensors' }) const wrapper = mountPanel(asset) expect(wrapper.text()).toContain('fallback-model.safetensors') }) - it('renders source link when source_url is present', () => { + it('renders source link when source_arn is present', () => { const asset = createMockAsset({ - user_metadata: { source_url: 'https://civitai.com/models/123' } + user_metadata: { source_arn: 'civitai:model:123:version:456' } }) const wrapper = mountPanel(asset) - const link = wrapper.find('a[href="https://civitai.com/models/123"]') + const link = wrapper.find( + 'a[href="https://civitai.com/models/123?modelVersionId=456"]' + ) expect(link.exists()).toBe(true) expect(link.attributes('target')).toBe('_blank') }) it('displays correct source name for Civitai', () => { const asset = createMockAsset({ - user_metadata: { source_url: 'https://civitai.com/models/123' } + user_metadata: { source_arn: 'civitai:model:123:version:456' } }) const wrapper = mountPanel(asset) expect(wrapper.text()).toContain('Civitai') }) - it('displays correct source name for Hugging Face', () => { - const asset = createMockAsset({ - user_metadata: { source_url: 'https://huggingface.co/org/model' } - }) - const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('Hugging Face') - }) - - it('does not render source field when source_url is absent', () => { + it('does not render source field when source_arn is absent', () => { const asset = createMockAsset() const wrapper = mountPanel(asset) const links = wrapper.findAll('a') @@ -132,55 +102,47 @@ describe('ModelInfoPanel', () => { }) describe('Model Tagging Section', () => { - it('displays model type from tags', () => { - const asset = createMockAsset({ tags: ['models', 'loras'] }) - const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('loras') + it('renders model tagging section', () => { + const wrapper = mountPanel(createMockAsset()) + expect(wrapper.text()).toContain('assetBrowser.modelInfo.modelTagging') }) - it('extracts last segment from nested tag path', () => { - const asset = createMockAsset({ - tags: ['models', 'checkpoints/sd15'] - }) - const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('sd15') + it('renders model type field', () => { + const wrapper = mountPanel(createMockAsset()) + expect(wrapper.text()).toContain('assetBrowser.modelInfo.modelType') }) - it('displays base_model when present', () => { + it('renders base models field', () => { const asset = createMockAsset({ - user_metadata: { base_model: 'SDXL' } + user_metadata: { base_models: ['SDXL'] } }) const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('SDXL') + expect(wrapper.text()).toContain( + 'assetBrowser.modelInfo.compatibleBaseModels' + ) }) - it('renders additional tags as badges', () => { - const asset = createMockAsset({ - user_metadata: { tags: ['anime', 'portrait', 'detailed'] } - }) - const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('anime') - expect(wrapper.text()).toContain('portrait') - expect(wrapper.text()).toContain('detailed') + it('renders additional tags field', () => { + const wrapper = mountPanel(createMockAsset()) + expect(wrapper.text()).toContain('assetBrowser.modelInfo.additionalTags') }) }) describe('Model Description Section', () => { it('renders trigger phrases when present', () => { const asset = createMockAsset({ - user_metadata: { trigger_phrases: ['trigger1', 'trigger2'] } + user_metadata: { trained_words: ['trigger1', 'trigger2'] } }) const wrapper = mountPanel(asset) expect(wrapper.text()).toContain('trigger1') expect(wrapper.text()).toContain('trigger2') }) - it('renders description when present', () => { - const asset = createMockAsset({ - user_metadata: { description: 'A detailed model description' } - }) - const wrapper = mountPanel(asset) - expect(wrapper.text()).toContain('A detailed model description') + it('renders description section', () => { + const wrapper = mountPanel(createMockAsset()) + expect(wrapper.text()).toContain( + 'assetBrowser.modelInfo.modelDescription' + ) }) it('does not render trigger phrases field when empty', () => { @@ -193,18 +155,11 @@ describe('ModelInfoPanel', () => { }) describe('Accordion Structure', () => { - it('renders three accordion sections', () => { + it('renders all three section labels', () => { const wrapper = mountPanel(createMockAsset()) - const accordions = wrapper.findAll('[data-testid="accordion-item"]') - expect(accordions).toHaveLength(3) - }) - - it('renders correct section labels', () => { - const wrapper = mountPanel(createMockAsset()) - const labels = wrapper.findAll('[data-testid="accordion-label"]') - expect(labels[0].text()).toContain('assetBrowser.modelInfo.basicInfo') - expect(labels[1].text()).toContain('assetBrowser.modelInfo.modelTagging') - expect(labels[2].text()).toContain( + expect(wrapper.text()).toContain('assetBrowser.modelInfo.basicInfo') + expect(wrapper.text()).toContain('assetBrowser.modelInfo.modelTagging') + expect(wrapper.text()).toContain( 'assetBrowser.modelInfo.modelDescription' ) })