Skip to content

Commit 91092fb

Browse files
committed
test(plugin-email): assert the over-limit attachment by identity, not deep equality
The over-limit test's stated subject is the comment above it -- "delivered inline and delivered WHOLE". Deep equality is the WEAKER reading of that: it passes for a copy too, so it cannot tell an untouched buffer from one the service re-encoded and rebuilt to the same bytes. `toBe` on the captured call argument proves the exact instance the caller allocated travelled through the over-limit path untouched, which is what "whole" means. Removing the O(n) walk over the 256 KiB + 1 fixture is a consequence of that, not the reason for it. Measured in this container, under the shared verify lock, `--reporter=verbose`: target test 674 ms -> 1 ms its file, tests total 800 ms -> 125 ms (21 siblings total 126 ms) whole package 2287 ms -> 1537 ms across the same 468 tests The fixture size is unchanged (the over-limit boundary IS the subject), no timeout was raised, and nothing was skipped. The transport fake in this one test now declares its parameter so the captured call is typed rather than cast -- `vi.fn(async () => ...)` has an empty parameter tuple, which makes `mock.calls[0][0]` a type error under the package's test-layer typecheck. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
1 parent c383352 commit 91092fb

1 file changed

Lines changed: 21 additions & 5 deletions

File tree

packages/plugins/plugin-email/src/email-service.queue-delivery.test.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import { describe, it, expect, vi } from 'vitest';
1818
import { createHash } from 'node:crypto';
19-
import type { IQueueService } from '@objectstack/spec/contracts';
19+
import type { IQueueService, NormalizedEmailMessage } from '@objectstack/spec/contracts';
2020
import {
2121
EmailService,
2222
EMAIL_SEND_QUEUE,
@@ -277,7 +277,10 @@ describe('EmailService — queue delivery on', () => {
277277
});
278278

279279
it('still refuses the queue for attachments OVER the limit, and stores nothing (#5177)', async () => {
280-
const transport = { send: vi.fn(async () => ({ messageId: '<big@x>' })) };
280+
// The parameter is DECLARED (unlike this file's other transport fakes) so
281+
// the captured call below is typed rather than cast — see the identity
282+
// assertion and its note further down.
283+
const transport = { send: vi.fn(async (_message: NormalizedEmailMessage) => ({ messageId: '<big@x>' })) };
281284
const queue = makeQueue();
282285
const { p, rows } = makePersistence();
283286
const logger = makeLogger();
@@ -289,11 +292,24 @@ describe('EmailService — queue delivery on', () => {
289292
const res = await svc.send({ ...MSG, attachments: [{ filename: 'big.bin', content: huge }] });
290293

291294
// Pre-#5177 behaviour, unchanged: delivered inline and delivered WHOLE.
295+
//
296+
// "WHOLE" is asserted by IDENTITY, not by deep equality (#16506). Deep
297+
// equality is the weaker claim: it passes for a *copy* too, so it cannot
298+
// tell an untouched buffer from one the service re-encoded, sliced and
299+
// rebuilt to the same bytes. `toBe` proves the exact instance the caller
300+
// allocated travelled through the over-limit path untouched — which is
301+
// what "whole" means here, and it is what the inline path promises when
302+
// it declines the queue. Do NOT "simplify" this back to
303+
// `toHaveBeenCalledWith(objectContaining({ attachments: [...] }))`: that
304+
// asserts less AND deep-compares a 256 KiB + 1 buffer, which cost 674 ms
305+
// of this file's 800 ms — its 21 siblings total 126 ms between them — and
306+
// ejected two PRs from the merge queue on vitest's 5000 ms default.
292307
expect(res.status).toBe('sent');
293308
expect(queue.published).toHaveLength(0);
294-
expect(transport.send).toHaveBeenCalledWith(expect.objectContaining({
295-
attachments: [{ filename: 'big.bin', content: huge }],
296-
}));
309+
const [delivered] = transport.send.mock.calls[0]!;
310+
expect(delivered.attachments).toHaveLength(1);
311+
expect(delivered.attachments![0]!.filename).toBe('big.bin');
312+
expect(delivered.attachments![0]!.content).toBe(huge);
297313
// The row must stay bounded: over-limit content never lands in the column.
298314
expect(rows.get(res.id)!.attachments_json).toBeUndefined();
299315
const info = logger.info.mock.calls.map((c) => String(c[0])).join('\n');

0 commit comments

Comments
 (0)