Quality / test (push) Canceled after 0s
Commit the working vertical slices for inventory image processing and the Sale workflow, including Sale history, audited voiding, multi-item persistence, admin UI, migrations, documentation, and tests.
59 lines
2.6 KiB
JavaScript
59 lines
2.6 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { mkdtemp, rm } from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import test from 'node:test';
|
|
|
|
import { createImageStorageContract } from '../../src/infrastructure/images/image-storage.js';
|
|
import { createLocalImageStorage, resolveProjectImageStorageRoot } from '../../src/infrastructure/images/local-image-storage.js';
|
|
|
|
test('local image storage round-trips and deletes binary data', async () => {
|
|
const root = await mkdtemp(path.join(os.tmpdir(), 'pokemon-images-'));
|
|
const storage = createLocalImageStorage(root);
|
|
|
|
try {
|
|
await storage.put({ key: 'inventory/item-1/front.jpg', data: Buffer.from('image-bytes') });
|
|
assert.deepEqual(await storage.get('inventory/item-1/front.jpg'), Buffer.from('image-bytes'));
|
|
await storage.delete('inventory/item-1/front.jpg');
|
|
await assert.rejects(() => storage.get('inventory/item-1/front.jpg'), { code: 'ENOENT' });
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('local image storage rejects traversal and duplicate writes', async () => {
|
|
const root = await mkdtemp(path.join(os.tmpdir(), 'pokemon-images-'));
|
|
const storage = createLocalImageStorage(root);
|
|
|
|
try {
|
|
await assert.rejects(
|
|
() => storage.put({ key: '../outside.jpg', data: Buffer.from('image-bytes') }),
|
|
/escapes the storage root/,
|
|
);
|
|
await storage.put({ key: 'same.jpg', data: Buffer.from('first') });
|
|
await assert.rejects(
|
|
() => storage.put({ key: 'same.jpg', data: Buffer.from('second') }),
|
|
{ code: 'EEXIST' },
|
|
);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('relative storage roots resolve from the project root regardless of the process cwd', () => {
|
|
const apiSource = new URL('../../src/app/server.js', import.meta.url);
|
|
const workerSource = new URL('../../../worker/src/worker-runtime.js', import.meta.url);
|
|
const expectedRoot = fileURLToPath(new URL('../../../../', import.meta.url));
|
|
|
|
assert.equal(resolveProjectImageStorageRoot('.local/image-storage', apiSource), path.join(expectedRoot, '.local/image-storage'));
|
|
assert.equal(resolveProjectImageStorageRoot('.local/image-storage', workerSource), path.join(expectedRoot, '.local/image-storage'));
|
|
assert.equal(resolveProjectImageStorageRoot('/tmp/custom-image-storage', apiSource), '/tmp/custom-image-storage');
|
|
});
|
|
|
|
test('image storage contracts reject incomplete adapters', () => {
|
|
assert.throws(
|
|
() => createImageStorageContract({ put() {} }),
|
|
/must implement get\(\)/,
|
|
);
|
|
}); |