feat(backend): persist per-experiment plot_config via PUT /:id/plot-config

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Experiments DB Dev
2026-06-01 10:12:23 -04:00
parent 2dd4a329ee
commit e9511bdac3
4 changed files with 90 additions and 0 deletions
+46
View File
@@ -136,3 +136,49 @@ describe('GET /health', () => {
expect(res.body.status).toBe('ok');
});
});
describe('PUT /api/experiments/:id/plot-config', () => {
const CONFIG = { xField: '__days__', tickStep: 2, hiddenSubjects: ['a1', 'a2'], sidebarOpen: true };
it('saves a valid config and returns it without writing an audit log', async () => {
prisma.experiment.findUnique.mockResolvedValue(EXPERIMENT);
prisma.experiment.update.mockResolvedValue({ ...EXPERIMENT, plot_config: CONFIG });
const res = await request(app).put(`/api/experiments/${EXPERIMENT.id}/plot-config`).send(CONFIG);
expect(res.status).toBe(200);
expect(res.body).toEqual(CONFIG);
expect(prisma.experiment.update).toHaveBeenCalledWith({
where: { id: EXPERIMENT.id },
data: { plot_config: CONFIG },
});
expect(prisma.auditLog.create).not.toHaveBeenCalled();
});
it('returns 404 when the experiment does not exist', async () => {
prisma.experiment.findUnique.mockResolvedValue(null);
const res = await request(app).put(`/api/experiments/${EXPERIMENT.id}/plot-config`).send(CONFIG);
expect(res.status).toBe(404);
expect(prisma.experiment.update).not.toHaveBeenCalled();
});
it('rejects a non-object body with 422', async () => {
prisma.experiment.findUnique.mockResolvedValue(EXPERIMENT);
const res = await request(app).put(`/api/experiments/${EXPERIMENT.id}/plot-config`).send([1, 2, 3]);
expect(res.status).toBe(422);
expect(prisma.experiment.update).not.toHaveBeenCalled();
});
it('rejects an invalid hiddenSubjects with 422', async () => {
prisma.experiment.findUnique.mockResolvedValue(EXPERIMENT);
const res = await request(app).put(`/api/experiments/${EXPERIMENT.id}/plot-config`).send({ hiddenSubjects: [1, 2] });
expect(res.status).toBe(422);
expect(prisma.experiment.update).not.toHaveBeenCalled();
});
it('rejects an oversized config with 422', async () => {
prisma.experiment.findUnique.mockResolvedValue(EXPERIMENT);
const big = { blob: 'x'.repeat(20000) };
const res = await request(app).put(`/api/experiments/${EXPERIMENT.id}/plot-config`).send(big);
expect(res.status).toBe(422);
expect(prisma.experiment.update).not.toHaveBeenCalled();
});
});