import { mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import { computed, defineComponent, h, ref, nextTick } from 'vue'
import { describe, expect, it, vi } from 'vitest'
import AppLayout from '../../components/AppLayout.vue'
import AppSidebar from '../../components/AppSidebar.vue'
import DoseDesignWorkspaceView from '../../components/DoseDesignWorkspaceView.vue'
vi.mock('../../composables/usePlatformContext', () => ({
usePlatformContext: vi.fn(() => ({
isIntegrated: computed(() => false),
context: ref({ isIntegrated: false, theme: 'system' }),
plugin: computed(() => undefined),
user: computed(() => undefined),
theme: computed(() => 'system' as const),
features: computed(() => undefined),
navigate: vi.fn(),
notify: vi.fn(),
sendToPlatform: vi.fn(),
})),
}))
vi.mock('../../composables/useTheme', () => ({
useTheme: vi.fn(() => ({
isDark: ref(false),
theme: ref('light'),
toggleTheme: vi.fn(),
})),
}))
const WellPlateStub = defineComponent({
name: 'WellPlate',
props: {
modelValue: { type: Array, default: () => [] },
format: { type: Number, default: 96 },
wells: { type: Object, default: undefined },
disabled: { type: Boolean, default: false },
size: { type: String, default: undefined },
selectionMode: { type: String, default: undefined },
heatmap: { type: Object, default: undefined },
},
emits: ['update:modelValue'],
template: '',
})
const DoseCalculatorStub = defineComponent({
name: 'DoseCalculator',
props: {
mode: { type: String, default: 'auto' },
targetWells: { type: Array, default: () => [] },
disabled: { type: Boolean, default: false },
molecularWeight: { type: Number, default: undefined },
},
template: '
',
})
function mountWorkspace(
props: Record = {},
slots: Record = {},
) {
return mount(DoseDesignWorkspaceView, {
props,
slots: slots as never,
global: {
plugins: [createPinia()],
stubs: {
WellPlate: WellPlateStub,
DoseCalculator: DoseCalculatorStub,
'router-link': {
template: '',
},
BaseModal: {
template: '
',
},
},
},
})
}
describe('DoseDesignWorkspaceView', () => {
it('renders WellPlate and DoseCalculator from one dose-design model', async () => {
const wrapper = mountWorkspace({
modelValue: {
selectedWells: ['A1'],
plateFormat: 384,
doseMode: 'serial',
disabled: false,
},
doseDesignOptions: {
includeMolecularWeight: true,
},
wellPlateProps: {
size: 'lg',
selectionMode: 'single',
heatmap: { enabled: true },
},
doseCalculatorProps: {
disabled: true,
},
})
const wellPlate = wrapper.findComponent(WellPlateStub)
const doseCalculator = wrapper.findComponent(DoseCalculatorStub)
expect(wellPlate.props()).toMatchObject({
modelValue: ['A1'],
format: 384,
size: 'lg',
selectionMode: 'single',
heatmap: { enabled: true },
})
expect(doseCalculator.props()).toMatchObject({
mode: 'serial',
targetWells: ['A1'],
disabled: true,
molecularWeight: 300,
})
await wellPlate.trigger('click')
await nextTick()
expect(wrapper.emitted('update:modelValue')?.at(-1)?.[0]).toMatchObject({
selectedWells: ['B1', 'B2'],
})
})
it('uses custom generated component prop ids from doseDesignOptions', () => {
const wrapper = mountWorkspace({
doseDesignOptions: {
selectedWells: ['C1'],
componentProps: {
plateId: 'plateView',
doseId: 'doseTool',
},
},
})
expect(wrapper.findComponent(WellPlateStub).props('modelValue')).toEqual(['C1'])
expect(wrapper.findComponent(DoseCalculatorStub).props('targetWells')).toEqual(['C1'])
})
it('passes through sidebar chrome overrides', () => {
const wrapper = mountWorkspace({
sidebarVariant: 'default',
responsiveSidebar: false,
sidebarTitle: 'Dose Controls',
sidebarSubtitle: 'Plate setup',
sidebarBadge: 'ready',
})
expect(wrapper.findComponent(AppLayout).props('responsiveSidebar')).toBe(false)
expect(wrapper.findComponent(AppSidebar).props('title')).toBe('Dose Controls')
expect(wrapper.findComponent(AppSidebar).props('subtitle')).toBe('Plate setup')
expect(wrapper.findComponent(AppSidebar).props('badge')).toBe('ready')
})
it('exposes merged component props to the default slot', () => {
const wrapper = mountWorkspace(
{
doseDesignOptions: {
selectedWells: ['D1'],
},
},
{
default: (rawProps: unknown) => {
const props = rawProps as {
wellPlateProps: Record
doseCalculatorProps: Record
}
return h('pre', { class: 'slot-props' }, JSON.stringify({
plate: props.wellPlateProps.modelValue,
dose: props.doseCalculatorProps.targetWells,
}))
},
},
)
expect(JSON.parse(wrapper.find('.slot-props').text())).toEqual({
plate: ['D1'],
dose: ['D1'],
})
})
})