diff --git a/test/business-adapter.test.mjs b/test/business-adapter.test.mjs index 5eb8210..83da9f7 100644 --- a/test/business-adapter.test.mjs +++ b/test/business-adapter.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import { execFile } from 'node:child_process'; -import { mkdtemp, readFile, readdir, rm, stat } from 'node:fs/promises'; +import { mkdir, mkdtemp, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises'; import http from 'node:http'; import os from 'node:os'; import path from 'node:path'; @@ -130,3 +130,104 @@ test('bundled Business adapter atomically replaces a shared session under concur assert.equal((await stat(sessionFile)).mode & 0o777, 0o600); assert.deepEqual((await readdir(stateDir)).filter((entry) => entry.endsWith('.tmp')), []); }); + +test('bundled Business adapter sends repeated local attachments through the workspace operation', async (t) => { + const stateHome = await mkdtemp(path.join(os.tmpdir(), 'mere-business-bundled-attachments-')); + t.after(() => rm(stateHome, { recursive: true, force: true })); + + const markdownPath = path.join(stateHome, 'approval-packet.md'); + const jsonPath = path.join(stateHome, 'receipt.json'); + await writeFile(markdownPath, '# Approval packet\n', 'utf8'); + await writeFile(jsonPath, '{"ok":true}\n', 'utf8'); + + let received; + const server = http.createServer(async (request, response) => { + if (request.method !== 'POST' || request.url !== '/api/cli/v2') { + response.writeHead(404).end(); + return; + } + received = { + authorization: request.headers.authorization, + body: JSON.parse(await readBody(request)), + }; + response.writeHead(200, { 'content-type': 'application/json' }); + response.end(JSON.stringify({ ok: true, data: { threadId: 'thread_1', messageId: 'message_1' } })); + }); + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + t.after(() => new Promise((resolve) => server.close(resolve))); + + const address = server.address(); + assert.ok(address && typeof address === 'object'); + const workspaceUrl = `http://127.0.0.1:${address.port}`; + const session = sessionPayload('attachments'); + session.workspace.host = workspaceUrl; + session.workspaces[0].host = workspaceUrl; + const stateDir = path.join(stateHome, 'mere-business'); + await mkdir(stateDir, { recursive: true }); + await writeFile( + path.join(stateDir, 'session.json'), + `${JSON.stringify({ ...session, version: 1, baseUrl: workspaceUrl })}\n`, + 'utf8', + ); + + const env = { + ...process.env, + HOME: stateHome, + XDG_STATE_HOME: stateHome, + MERE_ROOT: path.join(stateHome, 'missing-mere-root'), + MERE_CLI_SOURCE: 'bundled', + }; + const result = await execFileAsync( + process.execPath, + [ + rootCli, + 'business', + 'mail', + 'send', + '--mailbox-id', + 'mb_1', + '--to', + 'director@example.com', + '--subject', + 'Approval packet', + '--body', + 'Attached.', + '--attach', + markdownPath, + '--attach', + jsonPath, + '--yes', + '--json', + ], + { cwd: repoRoot, env }, + ); + + assert.equal(result.stderr, ''); + assert.deepEqual(JSON.parse(result.stdout), { messageId: 'message_1', threadId: 'thread_1' }); + assert.deepEqual(received, { + authorization: 'Bearer fake-access-attachments', + body: { + op: 'mail.send', + input: { + mailboxId: 'mb_1', + to: ['director@example.com'], + cc: [], + bcc: [], + attachments: [ + { + filename: 'approval-packet.md', + mimeType: 'text/markdown; charset=utf-8', + contentBase64: Buffer.from('# Approval packet\n').toString('base64'), + }, + { + filename: 'receipt.json', + mimeType: 'application/json; charset=utf-8', + contentBase64: Buffer.from('{"ok":true}\n').toString('base64'), + }, + ], + subject: 'Approval packet', + bodyText: 'Attached.', + }, + }, + }); +});