memlnaut-nisps/manifold/tests/e2e/smoke.spec.ts
monkey-w1n5t0n 19b7f7eee8 feat(manifold): add convertible React front-end + simplify console chrome
Adds the Manifold app (manifold/) — the convertible-mode React front-end on
the real NISPS ML+audio engine, served live at meml.lnfinitemonkeys.org/next/.

Console chrome trimmed per UI pass:
- drop mode label + subtitle from the top-left overlay (keep MEMLNaut wordmark)
- remove the composite split preset/ratio readout (top-centre)
- remove the OUTPUT corner tag above the bars
- remove the A/B compare toggle from the verdict cluster
- remove the follow button + input/noise readout (bottom-left)
- remove AltitudeNav focus switcher (bottom-right)
2026-06-28 03:28:45 +02:00

59 lines
1.9 KiB
TypeScript

import { test, expect } from '@playwright/test';
/**
* Manifold smoke test — proves the app is REAL (not a mockup): the WASM engine
* loads, the reactive spine propagates (input change → output change in one
* tick), the verdict feedback runs, and the convertible Console renders with no
* "C15" string in the UI.
*/
declare global {
interface Window {
__nisps?: {
getOutputs(): Float32Array;
setInputs(x: number, y: number): void;
thumbsDown(): number;
getExampleCount(): number;
};
}
}
test('engine loads, spine propagates, console renders', async ({ page }) => {
const errors: string[] = [];
page.on('console', (m) => { if (m.type() === 'error') errors.push(m.text()); });
page.on('pageerror', (e) => errors.push(String(e)));
await page.goto('/?debug=1');
// 1. The probe + engine become ready (WASM compiled + instance created).
await page.waitForFunction(() => {
const n = window.__nisps;
return !!n && n.getOutputs().length > 0;
}, { timeout: 20_000 });
// 2. Spine invariant: changing the input changes the output vector.
const changed = await page.evaluate(() => {
const n = window.__nisps!;
n.setInputs(0.15, 0.15);
const a = Array.from(n.getOutputs());
n.setInputs(0.85, 0.85);
const b = Array.from(n.getOutputs());
const delta = a.reduce((s, v, i) => s + Math.abs(v - (b[i] ?? 0)), 0);
return { len: a.length, delta };
});
expect(changed.len).toBeGreaterThan(0);
expect(changed.delta).toBeGreaterThan(1e-4);
// 3. Feedback runs without throwing.
await page.evaluate(() => window.__nisps!.thumbsDown());
// 4. The convertible Console rendered.
await expect(page.getByText('MEMLNaut')).toBeVisible();
// 5. No "C15" anywhere in the rendered UI.
const body = await page.evaluate(() => document.body.innerText);
expect(body).not.toContain('C15');
// 6. No console/page errors.
expect(errors, errors.join('\n')).toEqual([]);
});