test(comment): покрыть fire-and-forget resolve-путь при отказе очереди (ревью #438)
resolve/unresolve enqueue — fire-and-forget (void ...catch(warn)): смысл #399 в том, что недоступность очереди НЕ должна ронять HTTP-запрос. Delete-путь уже покрыт (enqueue awaited перед hard-delete), а reject resolve-пути — нет. Тест: generalQueue.add реджектит -> resolveComment всё равно resolves (не throws) + warn залогирован (ошибка проглочена на микротаске после возврата, поэтому flushMicrotasks перед ассертом). Мутационно: сделать enqueue awaited без catch -> тест краснеет. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { CommentService } from './comment.service';
|
||||
import { QueueJob } from '../../integrations/queue/constants';
|
||||
|
||||
// Flush pending microtasks so a fire-and-forget `.catch(...)` runs before we assert.
|
||||
const flushMicrotasks = () => new Promise((r) => setImmediate(r));
|
||||
|
||||
/**
|
||||
* #399: the comment inline-mark update is moved OFF the HTTP critical path.
|
||||
* resolveComment / unresolve / the ephemeral-suggestion delete must NO LONGER
|
||||
@@ -150,4 +154,26 @@ describe('CommentService — async comment mark (#399)', () => {
|
||||
'delete-row',
|
||||
]);
|
||||
});
|
||||
|
||||
it('resolve is fire-and-forget: a queue-add rejection does NOT fail the HTTP call (best-effort warn)', async () => {
|
||||
const { service, generalQueue } = makeService();
|
||||
// The queue is unavailable — the whole point of #399 is that this must NOT
|
||||
// propagate out of resolveComment onto the HTTP request.
|
||||
const queueErr = new Error('queue is down');
|
||||
generalQueue.add.mockRejectedValue(queueErr);
|
||||
const warnSpy = jest
|
||||
.spyOn(Logger.prototype, 'warn')
|
||||
.mockImplementation(() => undefined);
|
||||
|
||||
// Must resolve, never throw, even though the enqueue rejects.
|
||||
await expect(service.resolveComment(comment(), true, user())).resolves.not.toThrow();
|
||||
|
||||
// The rejection is swallowed on a microtask AFTER the method returns; flush it.
|
||||
await flushMicrotasks();
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Failed to enqueue comment mark update for comment c-1'),
|
||||
queueErr,
|
||||
);
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user