Files
Void-Homelab/tests/api/improvements.test.js
root 3bd8ea399c feat: 2.14.0 — Eithan terminal toolbar, voice UX, Dross improvements framework
- Terminal renamed Eithan: mobile font A−/A+ (per-URL ttyd opts), same-origin
  xterm Copy/Paste buttons, scroll-to-live, touch-default 17px
- Dross voice: no keyboard pop after transcribe (fine-pointer only focus),
  autogrow textarea to ~5 lines, live amplitude meter on the mic while recording
- Dross improvements: propose_improvement tool (CSS layer, exfil-sanitized,
  owner-approved, per-improvement rollback/restore), public /improvements.css,
  Settings panel. External MCP registry unchanged (no tool leak).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 23:35:32 +10:00

60 lines
2.6 KiB
JavaScript

import { describe, it, expect, beforeAll } from 'vitest';
import request from 'supertest';
import { resetDb } from '../helpers/db.js';
import { migrateUp } from '../../lib/db/migrate.js';
import { createApp } from '../../server.js';
import { proposeImprovementTool } from '../../lib/ai/agent/tools/propose_improvement.js';
let app;
beforeAll(async () => {
await resetDb(); await migrateUp();
process.env.OWNER_TOKEN = 'test-token';
app = createApp();
});
const auth = (r) => r.set('Authorization', 'Bearer test-token');
const ctx = { agent: { slug: 'dross' } };
describe('dross improvements (2.14)', () => {
let id;
it('tool drafts a pending improvement, never applies', async () => {
const out = await proposeImprovementTool.handler(
{ summary: 'Soften card borders', css: '.card { border-radius: 10px; }' }, ctx);
expect(out.ok).toBe(true);
expect(out.note).toMatch(/NOT live/);
id = out.id;
const css = await request(app).get('/improvements.css');
expect(css.text).not.toContain('border-radius: 10px'); // pending ≠ live
});
it('tool rejects exfil css', async () => {
expect((await proposeImprovementTool.handler(
{ summary: 'evil', css: '.x { background: url(http://evil.tld/p.png); }' }, ctx)).error)
.toMatch(/url\(\)/);
expect((await proposeImprovementTool.handler(
{ summary: 'evil', css: '@import "http://evil.tld/x.css";' }, ctx)).error).toBeTruthy();
});
it('owner approves → live in the public stylesheet', async () => {
const res = await auth(request(app).post(`/api/improvements/${id}/approve`));
expect(res.status).toBe(200);
expect(res.body.status).toBe('active');
const css = await request(app).get('/improvements.css'); // unauthenticated by design
expect(css.headers['content-type']).toContain('text/css');
expect(css.text).toContain('border-radius: 10px');
expect(css.text).toContain('dross: Soften card borders');
});
it('rollback removes it instantly; restore brings it back', async () => {
await auth(request(app).post(`/api/improvements/${id}/rollback`));
expect((await request(app).get('/improvements.css')).text).not.toContain('border-radius');
await auth(request(app).post(`/api/improvements/${id}/restore`));
expect((await request(app).get('/improvements.css')).text).toContain('border-radius');
});
it('transitions are guarded (no approve on active, no anonymous verbs)', async () => {
expect((await auth(request(app).post(`/api/improvements/${id}/approve`))).status).toBe(409);
expect((await request(app).post(`/api/improvements/${id}/rollback`)).status).toBe(401);
});
});