import { describe, it, expect, vi, beforeEach } from 'vitest' import { mount } from '@vue/test-utils' import { createPinia, setActivePinia } from 'pinia' import { computed, reactive, ref } from 'vue' import ExperimentSelectorModal from '../../components/ExperimentSelectorModal.vue' import { useExperimentSelector } from '../../composables/useExperimentSelector' import { useExperimentStore } from '../../stores/experiment' import type { ExperimentSummary } from '../../types' const fetchExperiments = vi.fn(async () => undefined) const fetchFilterOptions = vi.fn(async () => undefined) const experiments = ref([]) vi.mock('../../composables/useExperimentSelector', () => ({ useExperimentSelector: vi.fn(() => ({ experiments, filters: reactive({ search: undefined, status: undefined, project: undefined, experimentType: undefined, datePreset: undefined, }), isLoading: ref(false), error: ref(null), sortKey: ref('created_at:desc'), experimentTypes: ref([]), projects: ref([]), groupedByProject: computed(() => []), fetch: fetchExperiments, fetchFilterOptions, })), })) function experiment(overrides: Partial = {}): ExperimentSummary { return { id: 7, name: 'Hexokinase knockout run', experiment_code: 'EXP-007', status: 'ongoing', experiment_type: 'screen', created_at: '2026-07-01T08:00:00Z', updated_at: '2026-07-01T08:00:00Z', has_design_data: false, ...overrides, } } interface ModalProps { modelValue: boolean allowedExperimentTypes?: string[] | null currentExperimentId?: number | null } function mountModal(props: ModalProps) { return mount(ExperimentSelectorModal, { props, global: { stubs: { BaseModal: { props: ['modelValue', 'title', 'size'], template: '
', }, }, }, }) } describe('ExperimentSelectorModal', () => { beforeEach(() => { setActivePinia(createPinia()) experiments.value = [] fetchExperiments.mockClear() fetchFilterOptions.mockClear() vi.mocked(useExperimentSelector).mockClear() }) it('fetches experiments when mounted already open', () => { mountModal({ modelValue: true }) expect(fetchFilterOptions).toHaveBeenCalledTimes(1) expect(fetchExperiments).toHaveBeenCalledTimes(1) }) it('does not fetch while mounted closed', () => { mountModal({ modelValue: false }) expect(fetchFilterOptions).not.toHaveBeenCalled() expect(fetchExperiments).not.toHaveBeenCalled() }) it('passes allowed experiment types to the selector composable', () => { mountModal({ modelValue: false, allowedExperimentTypes: ['mass_spectrometry'] }) expect(useExperimentSelector).toHaveBeenCalledWith({ experimentType: undefined, allowedExperimentTypes: ['mass_spectrometry'], }) }) it('commits the clicked platform record to the shared store', async () => { const record = experiment() experiments.value = [record] const wrapper = mountModal({ modelValue: true }) await wrapper.find('.mint-resource-picker__row').trigger('click') const store = useExperimentStore() expect(store.current).toEqual(record) expect(store.currentId).toBe(7) }) it('does not emit a select event — the store is the single owner', async () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true }) await wrapper.find('.mint-resource-picker__row').trigger('click') expect(wrapper.emitted('select')).toBeUndefined() }) it('closes itself after committing a selection', async () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true }) await wrapper.find('.mint-resource-picker__row').trigger('click') expect(wrapper.emitted('update:modelValue')).toEqual([[false]]) }) it('should show the experiment code as a pill on the second line', () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true }) expect(wrapper.get('.mint-resource-picker__code').text()).toBe('EXP-007') }) it('should state the status as text in the right-hand column', () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true }) expect(wrapper.get('.mint-resource-picker__aside').text()).toContain('Ongoing') }) it('should tint the status with the experiment status variant', () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true }) expect(wrapper.get('.mint-resource-picker__status').classes()).toContain('mint-resource-picker__status--primary') }) it('should fill the current experiment row', () => { experiments.value = [experiment()] const wrapper = mountModal({ modelValue: true, currentExperimentId: 7 }) expect(wrapper.find('.mint-resource-picker__row--selected').exists()).toBe(true) }) it('clears the shared store from the clear-selection footer', async () => { const store = useExperimentStore() store.select(experiment()) const wrapper = mountModal({ modelValue: true, currentExperimentId: 7 }) await wrapper.find('.mint-experiment-selector__clear-btn').trigger('click') expect(store.current).toBeNull() expect(store.currentId).toBeNull() expect(wrapper.emitted('update:modelValue')).toEqual([[false]]) }) })