87 lines
3.6 KiB
JavaScript
87 lines
3.6 KiB
JavaScript
import { describe, it, expect } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import KanbanBoard from '../src/components/KanbanBoard.vue'
|
|
|
|
function makeItem(overrides = {}) {
|
|
return {
|
|
id: 1,
|
|
modality: 'bh_email',
|
|
sender_id: 'jane@example.com',
|
|
raw_content: 'I have some books to donate.',
|
|
type: null,
|
|
stage: 'new',
|
|
direction: 'inbound',
|
|
follow_up_date: '',
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
describe('KanbanBoard', () => {
|
|
it('buckets items into the correct board and shows counts on tabs', () => {
|
|
const items = [
|
|
makeItem({ id: 1, type: 'donation', direction: 'inbound', stage: 'new' }),
|
|
makeItem({ id: 2, type: 'other', direction: 'inbound', stage: 'new' }),
|
|
makeItem({ id: 3, type: null, direction: 'outbound', stage: 'new' }),
|
|
makeItem({ id: 4, type: null, direction: 'inbound', stage: 'new' }),
|
|
]
|
|
const wrapper = mount(KanbanBoard, { props: { items } })
|
|
const tabs = wrapper.findAll('[role="tab"]').map((t) => t.text())
|
|
expect(tabs).toEqual([
|
|
'Donations (1)', 'Other (1)', 'Outbound Leads (1)', 'Unsorted (1)',
|
|
])
|
|
})
|
|
|
|
it('defaults to the Donations board and its first stage', () => {
|
|
const wrapper = mount(KanbanBoard, { props: { items: [] } })
|
|
const activeTab = wrapper.find('[role="tab"][aria-selected="true"]')
|
|
expect(activeTab.text()).toContain('Donations')
|
|
})
|
|
|
|
it('shows humanized stage labels, not raw stage strings, on column headers', () => {
|
|
const items = [makeItem({ id: 1, type: 'donation', stage: 'pickup_scheduled' })]
|
|
const wrapper = mount(KanbanBoard, { props: { items } })
|
|
expect(wrapper.text()).toContain('Pickup Scheduled')
|
|
expect(wrapper.text()).not.toContain('pickup_scheduled')
|
|
})
|
|
|
|
it('switching board tabs resets the active stage to that board\'s first stage', async () => {
|
|
const wrapper = mount(KanbanBoard, { props: { items: [] } })
|
|
const outboundTab = wrapper.findAll('[role="tab"]').find((t) => t.text().includes('Outbound Leads'))
|
|
await outboundTab.trigger('click')
|
|
const breadcrumb = wrapper.find('.mobile-breadcrumb')
|
|
expect(breadcrumb.text()).toContain('New')
|
|
expect(breadcrumb.text()).toContain('Outbound Leads')
|
|
})
|
|
|
|
it('clicking a stage-strip button switches the active stage', async () => {
|
|
const items = [makeItem({ id: 1, type: 'donation', stage: 'replied' })]
|
|
const wrapper = mount(KanbanBoard, { props: { items } })
|
|
const repliedButton = wrapper.findAll('.stage-strip-button').find((b) => b.text().includes('Replied'))
|
|
await repliedButton.trigger('click')
|
|
expect(wrapper.find('.mobile-breadcrumb').text()).toContain('Replied')
|
|
})
|
|
|
|
it('clicking a card emits select-item with the item id', async () => {
|
|
const items = [makeItem({ id: 42, type: 'donation', stage: 'new' })]
|
|
const wrapper = mount(KanbanBoard, { props: { items } })
|
|
await wrapper.find('.card').trigger('click')
|
|
expect(wrapper.emitted('select-item')).toEqual([[42]])
|
|
})
|
|
|
|
it('renders an empty-state message for a column with no items', () => {
|
|
const wrapper = mount(KanbanBoard, { props: { items: [] } })
|
|
expect(wrapper.text()).toContain('Nothing here')
|
|
})
|
|
|
|
it('applies the is-active-mobile class only to the currently active stage column', () => {
|
|
const items = [
|
|
makeItem({ id: 1, type: 'donation', stage: 'new' }),
|
|
makeItem({ id: 2, type: 'donation', stage: 'replied' }),
|
|
]
|
|
const wrapper = mount(KanbanBoard, { props: { items } })
|
|
const columns = wrapper.findAll('.column')
|
|
const activeColumns = columns.filter((c) => c.classes().includes('is-active-mobile'))
|
|
expect(activeColumns).toHaveLength(1)
|
|
expect(activeColumns[0].text()).toContain('New')
|
|
})
|
|
})
|