108 lines
2.7 KiB
JavaScript
108 lines
2.7 KiB
JavaScript
import { describe, expect, it, vi } from 'vitest';
|
|||
|
|
import crypto from 'crypto';
|
||
|
|
import path from 'path';
|
||
|
|
|
||
|
|
import { registerProjectIconRoutes } from './project-icon-routes.js';
|
||
|
|
|
||
|
|
const createRouteRegistry = () => {
|
||
|
|
const routes = new Map();
|
||
|
|
|
||
|
|
return {
|
||
|
|
app: {
|
||
|
|
get(routePath, handler) {
|
||
|
|
routes.set(`GET ${routePath}`, handler);
|
||
|
|
},
|
||
|
|
post(routePath, handler) {
|
||
|
|
routes.set(`POST ${routePath}`, handler);
|
||
|
|
},
|
||
|
|
put(routePath, handler) {
|
||
|
|
routes.set(`PUT ${routePath}`, handler);
|
||
|
|
},
|
||
|
|
delete(routePath, handler) {
|
||
|
|
routes.set(`DELETE ${routePath}`, handler);
|
||
|
|
},
|
||
|
|
},
|
||
|
|
getRoute(method, routePath) {
|
||
|
|
return routes.get(`${method} ${routePath}`);
|
||
|
|
},
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
const createMockResponse = () => {
|
||
|
|
const headers = new Map();
|
||
|
|
let statusCode = 200;
|
||
|
|
let body = null;
|
||
|
|
|
||
|
|
return {
|
||
|
|
setHeader(name, value) {
|
||
|
|
headers.set(name.toLowerCase(), value);
|
||
|
|
},
|
||
|
|
getHeader(name) {
|
||
|
|
return headers.get(name.toLowerCase());
|
||
|
|
},
|
||
|
|
status(code) {
|
||
|
|
statusCode = code;
|
||
|
|
return this;
|
||
|
|
},
|
||
|
|
json(payload) {
|
||
|
|
body = payload;
|
||
|
|
return this;
|
||
|
|
},
|
||
|
|
send(payload) {
|
||
|
|
body = payload;
|
||
|
|
return this;
|
||
|
|
},
|
||
|
|
get statusCode() {
|
||
|
|
return statusCode;
|
||
|
|
},
|
||
|
|
get body() {
|
||
|
|
return body;
|
||
|
|
},
|
||
|
|
};
|
||
|
|
};
|
||
|
|
|
||
|
|
describe('project icon routes', () => {
|
||
|
|
it('uses fallback file extension MIME when metadata points to a missing icon', async () => {
|
||
|
|
const { app, getRoute } = createRouteRegistry();
|
||
|
|
const jpgBytes = Buffer.from('jpg-bytes');
|
||
|
|
const enoent = Object.assign(new Error('missing'), { code: 'ENOENT' });
|
||
|
|
const fsPromises = {
|
||
|
|
readFile: vi.fn(async (iconPath) => {
|
||
|
|
if (iconPath.endsWith('.jpg')) {
|
||
|
|
return jpgBytes;
|
||
|
|
}
|
||
|
|
throw enoent;
|
||
|
|
}),
|
||
|
|
};
|
||
|
|
|
||
|
|
registerProjectIconRoutes(app, {
|
||
|
|
fsPromises,
|
||
|
|
path,
|
||
|
|
crypto,
|
||
|
|
openchamberDataDir: '/tmp/openchamber-test',
|
||
|
|
sanitizeProjects: (projects) => projects,
|
||
|
|
readSettingsFromDiskMigrated: async () => ({
|
||
|
|
projects: [{
|
||
|
|
id: 'proj-1',
|
||
|
|
path: '/repo',
|
||
|
|
iconImage: { mime: 'image/png', updatedAt: 1, source: 'custom' },
|
||
|
|
}],
|
||
|
|
}),
|
||
|
|
persistSettings: async () => ({}),
|
||
|
|
createFsSearchRuntime: () => ({ searchFilesystemFiles: async () => [] }),
|
||
|
|
spawn: vi.fn(),
|
||
|
|
resolveGitBinaryForSpawn: vi.fn(),
|
||
|
|
});
|
||
|
|
|
||
|
|
const res = createMockResponse();
|
||
|
|
await getRoute('GET', '/api/projects/:projectId/icon')({
|
||
|
|
params: { projectId: 'proj-1' },
|
||
|
|
query: {},
|
||
|
|
}, res);
|
||
|
|
|
||
|
|
expect(res.statusCode).toBe(200);
|
||
|
|
expect(res.getHeader('Content-Type')).toBe('image/jpeg');
|
||
|
|
expect(res.body).toBe(jpgBytes);
|
||
|
|
});
|
||
|
|
});
|