I1: move cog registration + tree.sync into ChorusBot.setup_hook (called once before gateway connect) instead of on_ready (fires on every reconnect), preventing duplicate cogs/listeners/poll loops after a gateway RESUME. I2 (email_ingest.py, addressed alongside I1 for IMAP stability): none here, handled separately. I3/I4: TriageList.vue now renders a follow_up_date column so it actually surfaces back to Donna. App.vue adds a "Show completed" checkbox bound to includeDone, matching what docs/smoke-test.md step 7 already describes. I5: add frontend/tests/ItemModal.spec.js covering stagesForType() options for donation/other/unset types and the type-change stage reset regression. I6: App.vue wraps loadItems/openItem in try/catch with a calm (no-panic) error message, and shows calm empty-state copy when there are zero items. Also fixes thread_ingest.py: standalone threads not started from a message raise discord.NotFound on fetch_message; now caught and returns early.
56 lines
2 KiB
JavaScript
56 lines
2 KiB
JavaScript
import { describe, it, expect, vi } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import ItemModal from '../src/components/ItemModal.vue'
|
|
|
|
vi.mock('../src/api.js', () => ({
|
|
updateItem: vi.fn(async (id, fields) => ({ id, ...fields })),
|
|
}))
|
|
|
|
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',
|
|
notes: '',
|
|
follow_up_date: '',
|
|
...overrides,
|
|
}
|
|
}
|
|
|
|
describe('ItemModal', () => {
|
|
it('offers the donation stages when item.type is donation', () => {
|
|
const wrapper = mount(ItemModal, { props: { item: makeItem({ type: 'donation', stage: 'new' }) } })
|
|
const options = wrapper.findAll('select')[1].findAll('option').map((o) => o.element.value)
|
|
expect(options).toEqual([
|
|
'new', 'replied', 'pickup_scheduled', 'picked_up', 'logged_in_bookmark',
|
|
])
|
|
})
|
|
|
|
it('offers only new/done stages when item.type is other', () => {
|
|
const wrapper = mount(ItemModal, { props: { item: makeItem({ type: 'other', stage: 'new' }) } })
|
|
const options = wrapper.findAll('select')[1].findAll('option').map((o) => o.element.value)
|
|
expect(options).toEqual(['new', 'done'])
|
|
})
|
|
|
|
it('offers only the new stage when item.type is unset/null', () => {
|
|
const wrapper = mount(ItemModal, { props: { item: makeItem({ type: null, stage: 'new' }) } })
|
|
const options = wrapper.findAll('select')[1].findAll('option').map((o) => o.element.value)
|
|
expect(options).toEqual(['new'])
|
|
})
|
|
|
|
it('resets stage to new when type changes away from donation while stage is pickup_scheduled', async () => {
|
|
const wrapper = mount(ItemModal, {
|
|
props: { item: makeItem({ type: 'donation', stage: 'pickup_scheduled' }) },
|
|
})
|
|
const stageSelect = wrapper.findAll('select')[1]
|
|
expect(stageSelect.element.value).toBe('pickup_scheduled')
|
|
|
|
const typeSelect = wrapper.findAll('select')[0]
|
|
await typeSelect.setValue('other')
|
|
|
|
expect(wrapper.findAll('select')[1].element.value).toBe('new')
|
|
})
|
|
})
|