import { mount } from '@vue/test-utils' import { describe, expect, it } from 'vitest' import AppointmentCalendarPanel from './AppointmentCalendarPanel.vue' describe('appointment calendar interactions', () => { it('keeps creation beside the title and record actions beside data notices', () => { const wrapper = mount(AppointmentCalendarPanel, { props: { canCreate: true, events: [], notices: ['数据范围不完整'] }, slots: { 'toolbar-actions': '' }, global: { stubs: { ElButton: { template: '' } }, directives: { loading: {} } }, }) expect(wrapper.get('.calendar-label').text()).toContain('新增预约') const actions = wrapper.get('[aria-label="预约记录与数据提示"]') expect(actions.text()).toContain('未定时安排') expect(actions.text()).toContain('取消记录') expect(actions.get('summary').text()).toContain('数据提示') wrapper.unmount() }) const render = () => mount(AppointmentCalendarPanel, { props: { initialDate: '2026-09-24', canCreate: true, events: [ { key: 'a', type: 'delivery', date: '2026-09-24', time: '09:00-11:00', title: 'ONT8 预约送货', fields: [], canEdit: true, canDelete: true }, ] }, global: { stubs: { ElButton: { template: '' } }, directives: { loading: {} } }, }) it('opens a readable appointment without exposing write actions', async () => { const wrapper = render() const event = {key:'a',type:'delivery' as const,date:'2026-09-24',time:'09:00',title:'预约',fields:[],canView:true,canEdit:false,canDelete:false} await wrapper.setProps({events:[event]}) const actions=wrapper.get('.detail-event footer') expect(actions.text()).toBe('查看预约') await actions.get('button').trigger('click') expect(wrapper.emitted('view')?.[0]).toEqual([event]) expect(wrapper.emitted('edit')).toBeUndefined() wrapper.unmount() }) it('hides optional references by default and counts only appointments after enabling them', async () => { const wrapper = render() await wrapper.setProps({ events: [ { key: 'a', type: 'delivery', date: '2026-09-24', time: '09:00', title: '收货预约', fields: [] }, { key: 'b', type: 'arrival', date: '2026-09-24', time: '08:00', title: '到港参考', fields: [] }, { key: 'c', type: 'trip', date: '2026-09-24', time: '07:00', title: '运输计划', fields: [] }, ] }) expect(wrapper.findAll('.detail-event')).toHaveLength(1) const switches = wrapper.get('[aria-label="参考图层"]').findAll('input') await switches[0]!.setValue(true); await switches[1]!.setValue(true) expect(wrapper.findAll('.detail-event')).toHaveLength(3) expect(wrapper.get('[aria-label="当天安排"] header').text()).toContain('1 项预约') expect(wrapper.get('[aria-label="当天安排"] header').text()).toContain('2 条参考计划') expect(wrapper.emitted('range')).toBeUndefined() }) it('selects an already loaded date without requesting data again', async () => { const wrapper = render() await wrapper.get('[aria-label="2026-09-25,0 项安排"]').trigger('click') expect(wrapper.emitted('range')).toBeUndefined() expect(wrapper.get('[aria-label="当天安排"]').text()).toContain('当天暂无预约') }) it('shows an overnight slot on both days without fetching again and excludes midnight ends', async () => { const wrapper = render() await wrapper.setProps({ events: [ { key: 'overnight', type: 'delivery', date: '2026-09-23', endAt: '2026-09-24T01:00:00', time: '23:00–01:00', title: '跨日送仓', fields: [] }, { key: 'midnight', type: 'delivery', date: '2026-09-23', endAt: '2026-09-24T00:00:00', time: '23:00–00:00', title: '午夜结束', fields: [] }, ] }) expect(wrapper.find('[aria-label="2026-09-23,2 项安排"]').exists()).toBe(true) expect(wrapper.find('[aria-label="2026-09-24,1 项安排"]').exists()).toBe(true) expect(wrapper.get('[aria-label="当天安排"]').text()).toContain('跨日送仓') expect(wrapper.get('[aria-label="当天安排"]').text()).not.toContain('午夜结束') expect(wrapper.emitted('range')).toBeUndefined() }) it('requests exactly one range for a view switch and navigates seven days', async () => { const wrapper = render() await wrapper.get('[aria-label="预约视图"]').findAll('button')[1]!.trigger('click') expect(wrapper.emitted('range')).toEqual([[{ from: '2026-09-21', to: '2026-09-28' }]]) await wrapper.get('[aria-label="下一周"]').trigger('click') expect(wrapper.emitted('range')?.at(-1)).toEqual([{ from: '2026-09-28', to: '2026-10-05' }]) }) it('keeps busy days to three previews in both views and exposes the full count', async () => { const wrapper = render() await wrapper.setProps({ events: Array.from({ length: 233 }, (_, index) => ({ key: `arrival-${index}`, type: 'arrival' as const, date: '2026-09-24', time: '09:00', title: `船舶 ${index}`, fields: [], })) }) await wrapper.get('[aria-label="参考图层"] input').setValue(true) for (const view of ['month', 'week']) { if (view === 'week') await wrapper.get('[aria-label="预约视图"]').findAll('button')[1]!.trigger('click') const day = wrapper.get('[aria-label="2026-09-24,233 项安排"]') expect(day.findAll('.event-chip')).toHaveLength(3) expect(day.attributes('title')).toContain('共 233 条安排') expect(day.get('.event-more').text()).toBe('还有 230 条') expect(wrapper.findAll('.detail-event')).toHaveLength(233) } }) it('uses the selected day for creation and emits edit/delete only from detail actions', async () => { const wrapper = render() await wrapper.findAll('button').find(button => button.text() === '+ 新增预约')!.trigger('click') expect(wrapper.emitted('create')).toEqual([['2026-09-24']]) await wrapper.findAll('button').find(button => button.text() === '编辑')!.trigger('click') await wrapper.findAll('button').find(button => button.text() === '取消预约')!.trigger('click') expect(wrapper.emitted('edit')?.[0]?.[0]).toMatchObject({ key: 'a' }) expect(wrapper.emitted('delete')?.[0]?.[0]).toMatchObject({ key: 'a' }) }) it('renders many inbound codes outside the two-column fields with only three previews', async () => { const wrapper = render() await wrapper.setProps({ events: [{ key: 'many', type: 'delivery', date: '2026-09-24', time: '09:00', title: 'ONT8 预约送仓', fields: [{ label: '货物信息', value: '20 票 / 12 个客户' }], inboundCodes: Array.from({ length: 20 }, (_, index) => `WT-INBOUND-${index}`), canEdit: true, }] }) const card = wrapper.get('.detail-event') expect(card.get('dl').text()).not.toContain('WT-INBOUND') expect(card.findAll('.inbound-codes li')).toHaveLength(3) expect(card.get('.inbound-codes').text()).toContain('20 个') expect(card.get('footer').text()).toContain('编辑') }) })