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)
59 lines
1.9 KiB
TypeScript
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([]);
|
|
});
|