import { mount } from '@vue/test-utils' import { afterEach, describe, expect, it } from 'vitest' import ExperimentPopover from '../../components/ExperimentPopover.vue' function mountPopover(props = {}) { return mount(ExperimentPopover, { props, attachTo: document.body, global: { stubs: { ConfirmDialog: { template: '
', }, }, }, }) } describe('ExperimentPopover', () => { afterEach(() => { document.body.innerHTML = '' }) it('requests experiment selection on the first click when no experiment is selected', async () => { const wrapper = mountPopover() await wrapper.find('.mint-experiment-popover__trigger').trigger('click') expect(wrapper.emitted('select')).toHaveLength(1) expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(false) wrapper.unmount() }) it.each([ { experimentName: 'Dose response run' }, { experimentCode: 'EXP-001' }, { isResolving: true }, { error: 'Experiment not found' }, ])('keeps the popover interaction for bound experiment state %o', async (props) => { const wrapper = mountPopover(props) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') expect(wrapper.emitted('select')).toBeUndefined() expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(true) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(false) wrapper.unmount() }) it('prefers the experiment name in the trigger when both name and code are available', () => { const wrapper = mountPopover({ experimentName: 'Dose response run', experimentCode: 'EXP-001', }) const trigger = wrapper.find('.mint-experiment-popover__trigger') expect(trigger.text()).toContain('Dose response run') expect(trigger.text()).not.toContain('EXP-001') wrapper.unmount() }) it('falls back to the experiment code in the trigger when the name is unavailable', () => { const wrapper = mountPopover({ experimentCode: 'EXP-001', }) expect(wrapper.find('.mint-experiment-popover__trigger').text()).toContain('EXP-001') wrapper.unmount() }) it('opens and closes the popover on trigger and outside click', async () => { const wrapper = mountPopover({ experimentName: 'Dose response run', experimentCode: 'EXP-001', }) expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(false) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(true) document.body.click() await wrapper.vm.$nextTick() expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(false) wrapper.unmount() }) it('shows a placeholder instead of "No experiment" while the record resolves', () => { const wrapper = mountPopover({ isResolving: true, showDetach: true }) const trigger = wrapper.find('.mint-experiment-popover__trigger') expect(trigger.find('.mint-experiment-popover__trigger-skeleton').exists()).toBe(true) expect(trigger.text()).not.toContain('No experiment') expect(trigger.attributes('aria-busy')).toBe('true') wrapper.unmount() }) it('never renders the bound id as a stand-in name while resolving', () => { const wrapper = mountPopover({ isResolving: true, showDetach: true }) expect(wrapper.text()).not.toMatch(/\d/) wrapper.unmount() }) it('shows the resolution failure instead of "No experiment"', () => { const wrapper = mountPopover({ error: 'Experiment not found', showDetach: true }) const trigger = wrapper.find('.mint-experiment-popover__trigger') expect(trigger.text()).toContain('Experiment unavailable') expect(trigger.text()).not.toContain('No experiment') expect(trigger.classes()).toContain('mint-experiment-popover__trigger--error') wrapper.unmount() }) it('surfaces the platform error message and keeps detach reachable on failure', async () => { const wrapper = mountPopover({ error: 'Experiment not found', showDetach: true }) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') const panel = wrapper.find('.mint-experiment-popover__panel') expect(panel.text()).toContain('Experiment not found') await wrapper.find('.mint-experiment-popover__detach-btn').trigger('click') expect(wrapper.emitted('detach')).toHaveLength(1) wrapper.unmount() }) it('shows skeleton placeholders in the panel while the record resolves', async () => { const wrapper = mountPopover({ isResolving: true, showDetach: true }) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') const panel = wrapper.find('.mint-experiment-popover__panel') expect(panel.findAll('.mint-experiment-popover__skeleton-line').length).toBeGreaterThan(0) expect(panel.find('.mint-experiment-popover__select-btn').exists()).toBe(false) wrapper.unmount() }) it('hides the inline save action while no resolved experiment exists', () => { const wrapper = mountPopover({ isResolving: true, showSave: true }) expect(wrapper.find('.mint-experiment-popover__save-trigger').exists()).toBe(false) wrapper.unmount() }) it('emits select and closes when changing experiment context', async () => { const wrapper = mountPopover({ experimentName: 'Dose response run', experimentCode: 'EXP-001', }) await wrapper.find('.mint-experiment-popover__trigger').trigger('click') await wrapper.find('.mint-experiment-popover__change-btn').trigger('click') expect(wrapper.emitted('select')).toHaveLength(1) expect(wrapper.find('.mint-experiment-popover__panel').exists()).toBe(false) wrapper.unmount() }) })