Files
ComfyUI_frontend/src/components/load3d/controls/viewer/ViewerExportControls.test.ts
Terry Jia cd2f4677c2 FE-719 feat(load3d): add FBX export support (#12323)
## Summary
implement fbx export, using our own lib fbx-exporter-three

## Screenshots (if applicable)


https://github.com/user-attachments/assets/80012338-d065-4a00-a9a0-0a2e73d67db4

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12323-FE-719-feat-load3d-add-FBX-export-support-3656d73d365081ef901ffe880ae9568a)
by [Unito](https://www.unito.io)
2026-05-20 06:52:56 -04:00

118 lines
3.5 KiB
TypeScript

import { render, screen } from '@testing-library/vue'
import userEvent from '@testing-library/user-event'
import { describe, expect, it, vi } from 'vitest'
import { createI18n } from 'vue-i18n'
import ViewerExportControls from '@/components/load3d/controls/viewer/ViewerExportControls.vue'
vi.mock('@/components/ui/select/Select.vue', async () => {
const { provide } = await import('vue')
return {
default: {
name: 'Select',
props: ['modelValue'],
emits: ['update:modelValue'],
setup(
props: { modelValue: string },
{ emit }: { emit: (event: string, value: string) => void }
) {
provide('selectModelValue', (): string => props.modelValue)
provide('selectUpdate', (v: string): void =>
emit('update:modelValue', v)
)
},
template: '<div><slot /></div>'
}
}
})
vi.mock('@/components/ui/select/SelectContent.vue', async () => {
const { inject, ref, onMounted } = await import('vue')
return {
default: {
name: 'SelectContent',
setup() {
const selectModelValue = inject<() => string>('selectModelValue')
const selectUpdate = inject<(v: string) => void>('selectUpdate')
const el = ref<HTMLSelectElement | null>(null)
onMounted(() => {
if (el.value) el.value.value = selectModelValue?.() ?? ''
})
return {
el,
onChange: (e: Event) => {
selectUpdate?.((e.target as HTMLSelectElement).value)
}
}
},
template: '<select ref="el" @change="onChange"><slot /></select>'
}
}
})
vi.mock('@/components/ui/select/SelectItem.vue', () => ({
default: {
name: 'SelectItem',
props: ['value'],
template: '<option :value="value"><slot /></option>'
}
}))
vi.mock('@/components/ui/select/SelectTrigger.vue', () => ({
default: { name: 'SelectTrigger', template: '<span />' }
}))
vi.mock('@/components/ui/select/SelectValue.vue', () => ({
default: { name: 'SelectValue', template: '<span />' }
}))
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: { en: { load3d: { export: 'Export' } } }
})
function renderComponent(onExportModel?: (format: string) => void) {
const utils = render(ViewerExportControls, {
props: { onExportModel },
global: { plugins: [i18n] }
})
return { ...utils, user: userEvent.setup() }
}
describe('ViewerExportControls', () => {
it('renders all four export format options', () => {
renderComponent()
const select = screen.getByRole('combobox') as HTMLSelectElement
const optionValues = Array.from(select.options).map((o) => o.value)
expect(optionValues).toEqual(['glb', 'obj', 'stl', 'fbx'])
})
it('defaults the export format to obj', () => {
renderComponent()
expect((screen.getByRole('combobox') as HTMLSelectElement).value).toBe(
'obj'
)
})
it('emits exportModel with the currently selected format when the button is clicked', async () => {
const onExportModel = vi.fn()
const { user } = renderComponent(onExportModel)
await user.click(screen.getByRole('button', { name: 'Export' }))
expect(onExportModel).toHaveBeenCalledWith('obj')
})
it('emits the newly chosen format after the user changes the dropdown', async () => {
const onExportModel = vi.fn()
const { user } = renderComponent(onExportModel)
await user.selectOptions(screen.getByRole('combobox'), 'glb')
await user.click(screen.getByRole('button', { name: 'Export' }))
expect(onExportModel).toHaveBeenCalledWith('glb')
})
})