fix(projects): use fallback icon MIME (#1197)
Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
This commit is contained in:
committed by
GitHub
co-authored by
Isaac Sanchez
parent
75d78b6113
commit
51356b4195
@@ -204,7 +204,9 @@ export const registerProjectIconRoutes = (app, dependencies) => {
|
|||||||
try {
|
try {
|
||||||
const data = await fsPromises.readFile(iconPath);
|
const data = await fsPromises.readFile(iconPath);
|
||||||
const ext = path.extname(iconPath).slice(1).toLowerCase();
|
const ext = path.extname(iconPath).slice(1).toLowerCase();
|
||||||
const resolvedMime = metadataMime || projectIconExtensionToMime[ext] || 'application/octet-stream';
|
const resolvedMime = iconPath === preferredPath && metadataMime
|
||||||
|
? metadataMime
|
||||||
|
: projectIconExtensionToMime[ext] || 'application/octet-stream';
|
||||||
const contentType = resolvedMime === 'image/svg+xml' ? 'image/svg+xml; charset=utf-8' : resolvedMime;
|
const contentType = resolvedMime === 'image/svg+xml' ? 'image/svg+xml; charset=utf-8' : resolvedMime;
|
||||||
|
|
||||||
if (resolvedMime === 'image/svg+xml' && requestedThemeVariant) {
|
if (resolvedMime === 'image/svg+xml' && requestedThemeVariant) {
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user