Files
pokemon-inventory/apps/worker/tests/image-derivative-worker.test.js
2026-09-08 22:06:28 -04:00

98 lines
3.4 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
createInMemoryImageDerivativeQueue,
processNextImageDerivativeJob,
processNextPersistentImageDerivativeJob,
runImageDerivativeJob,
} from '../src/image-derivative-worker.js';
test('completes an image derivative job after loading and processing the source', async () => {
const calls = [];
const result = await runImageDerivativeJob({
job: { id: 'job-1', type: 'IMAGE_DERIVATIVES', sourceKey: 'source.jpg', status: 'PENDING' },
async loadSource(sourceKey) {
calls.push(`load:${sourceKey}`);
return { sourceKey, data: Buffer.from('image') };
},
processor: {
async process(source) {
calls.push(`process:${source.sourceKey}`);
return [{ name: 'thumbnail', key: 'source-thumbnail.webp' }];
},
},
});
assert.equal(result.status, 'COMPLETED');
assert.deepEqual(result.derivatives, [{ name: 'thumbnail', key: 'source-thumbnail.webp' }]);
assert.deepEqual(calls, ['load:source.jpg', 'process:source.jpg']);
assert.ok(result.completedAt instanceof Date);
});
test('records a failed image derivative job without throwing worker errors', async () => {
const result = await runImageDerivativeJob({
job: { id: 'job-2', type: 'IMAGE_DERIVATIVES', sourceKey: 'missing.jpg', status: 'PENDING' },
async loadSource() {
throw new Error('source unavailable');
},
processor: { async process() { return []; } },
});
assert.equal(result.status, 'FAILED');
assert.equal(result.error, 'source unavailable');
assert.ok(result.failedAt instanceof Date);
});
test('claims queued jobs and persists their processing lifecycle', async () => {
const queue = createInMemoryImageDerivativeQueue();
await queue.enqueue({ id: 'job-3', type: 'IMAGE_DERIVATIVES', sourceKey: 'queued.jpg', status: 'PENDING' });
const claimed = await queue.claimNext();
assert.equal(claimed.status, 'PROCESSING');
assert.equal(queue.getJob('job-3').status, 'PROCESSING');
const result = await processNextImageDerivativeJob({
queue,
async loadSource(sourceKey) {
return { sourceKey, data: Buffer.from('queued-image') };
},
processor: {
async process(source) {
return [{ name: 'thumbnail', key: `${source.sourceKey}-thumbnail.webp` }];
},
},
});
assert.equal(result.status, 'COMPLETED');
assert.equal(queue.getJob('job-3').status, 'COMPLETED');
assert.equal(queue.getJob('job-3').derivatives[0].key, 'queued.jpg-thumbnail.webp');
});
test('claims and persists a durable image derivative job lifecycle', async () => {
const calls = [];
const jobRepository = {
async claimNext() {
return { id: 'job-4', sourceKey: 'durable.jpg', status: 'PROCESSING' };
},
async complete(id, derivatives) {
calls.push({ action: 'complete', id, derivatives });
},
async fail() {
throw new Error('A successful durable job must not fail.');
},
};
const result = await processNextPersistentImageDerivativeJob({
jobRepository,
async loadSource(sourceKey) { return { sourceKey, data: Buffer.from('image') }; },
processor: { async process() { return [{ name: 'thumbnail', key: 'durable-thumbnail.webp' }]; } },
});
assert.equal(result.status, 'COMPLETED');
assert.deepEqual(calls, [{
action: 'complete',
id: 'job-4',
derivatives: [{ name: 'thumbnail', key: 'durable-thumbnail.webp' }],
}]);
});