import assert from 'node:assert/strict' import { afterEach, beforeEach, test } from 'node:test' import { SENDING as COMMITTED_SENDING } from '../src/config.js' import { HEY, installFetch, jsonResponse, redirectResponse, resetKodySecrets } from './helpers.mjs' import { ALLOWED_QUERY } from './hooks.mjs' const { SENDING } = await import(`../src/config.js${ALLOWED_QUERY}`) const { sendDraft, sendMessage, sendReply } = await import(`../src/send.js${ALLOWED_QUERY}`) const UNCONFIRMED = [{ confirm: 'true' }, { confirm: 1 }, { confirm: false }, {}] let fixture beforeEach(() => { resetKodySecrets() fixture = installFetch(async (url, init) => { const handler = fixture.routes.get(`${String(init.method || 'GET').toUpperCase()} ${url}`) if (handler) return handler(url, init) throw new Error(`unexpected ${init.method || 'GET'} ${url}`) }) fixture.routes = new Map() }) afterEach(() => { fixture?.restore() }) function on(method, url, handler) { fixture.routes.set(`${method} ${url}`, handler) } function writes() { return fixture.requests.filter((row) => row.method !== 'GET') } function routeDraft(contacts = [{ name: 'Ada', email_address: 'ada@example.com' }], extra = {}) { on('GET', `${HEY}/messages/9/edit.json`, () => jsonResponse(200, { id: 9, subject: 'Draft', content: '
Earlier', creator: { id: 7, name_tag: '
Dan
' }, addressed: { directly }, ...extra, }) ) } test('the allowed graph is separate from the committed barred config', () => { assert.equal(COMMITTED_SENDING, 'barred') assert.equal(SENDING, 'allowed') }) test('allowed sendMessage without boolean confirm is a dry run with no request', async () => { for (const confirm of UNCONFIRMED) { const result = await sendMessage({ to: 'ada@example.com', subject: 'Notes', text: 'Hi', ...confirm }) assert.deepEqual(result, { dryRun: true, wouldSend: true, to: ['ada@example.com'], subject: 'Notes', content: 'Rich
' }) assert.equal(result.content, 'Rich
') }) test('allowed sendMessage reports sent false when HEY does not say sent', async () => { routeIdentity() on('POST', `${HEY}/messages.json`, () => jsonResponse(202, { notice: null })) const result = await sendMessage({ to: 'ada@example.com', subject: 'Notes', text: 'Hi', confirm: true }) assert.equal(result.sent, false) }) test('allowed sendMessage with confirm true posts the nested body with no drafted status', async () => { routeIdentity() on('POST', `${HEY}/messages.json`, () => jsonResponse(200, { notice: 'sent' })) const result = await sendMessage({ to: 'ada@example.com', cc: 'bob@example.com', bcc: ['eve@example.com'], subject: 'Notes', text: 'Hi', confirm: true, }) assert.equal(result.sent, true) const [post] = writes() assert.equal(post.method, 'POST') assert.equal(post.url, `${HEY}/messages.json`) assert.equal(post.headers['content-type'], 'application/json') assert.deepEqual(JSON.parse(post.body), { acting_sender_id: 5, message: { subject: 'Notes', content: 'Dan
', }) } assert.deepEqual(writes(), []) }) test('allowed sendReply with no prefill recipients throws without a post', async () => { routeReplyPrefill([]) await assert.rejects(() => sendReply({ entryId: 42, text: 'Thanks', confirm: true }), /no recipients/) assert.deepEqual(writes(), []) }) test('allowed sendReply reports sent false when HEY does not say sent', async () => { routeIdentity() routeReplyPrefill() on('POST', `${HEY}/entries/42/replies.json`, () => jsonResponse(202, { notice: null })) const result = await sendReply({ entryId: 42, text: 'Thanks', confirm: true }) assert.equal(result.sent, false) }) test('allowed sendReply with confirm true posts the nested body to the prefill recipients', async () => { routeIdentity() routeReplyPrefill() on('POST', `${HEY}/entries/42/replies.json`, () => jsonResponse(200, { notice: 'sent' })) const result = await sendReply({ entryId: 42, text: 'Thanks', confirm: true }) assert.equal(result.sent, true) const [post] = writes() assert.equal(post.method, 'POST') assert.equal(post.url, `${HEY}/entries/42/replies.json`) assert.equal(post.headers['content-type'], 'application/json') assert.deepEqual(JSON.parse(post.body), { acting_sender_id: 5, message: { subject: 'Re: Notes', content: 'Dan
' }, entry: { addressed: { directly: ['ada@example.com'] } }, }) }) test('allowed sendReply acts as the prefill sender', async () => { routeReplyPrefill([{ email_address: 'ada@example.com' }], { sender: { id: 4242 } }) on('POST', `${HEY}/entries/42/replies.json`, () => jsonResponse(200, { notice: 'sent' })) await sendReply({ entryId: 42, text: 'Thanks', confirm: true }) assert.equal(JSON.parse(writes()[0].body).acting_sender_id, 4242) }) test('allowed sendDraft without boolean confirm reads the draft and does not put', async () => { routeDraft() for (const confirm of UNCONFIRMED) { const result = await sendDraft({ id: 9, ...confirm }) assert.equal(result.dryRun, true) assert.equal(result.wouldSend, true) assert.deepEqual(result.to, ['ada@example.com']) assert.equal(result.draft.subject, 'Draft') assert.equal(result.draft.content, '