memlnaut-nisps/manifold/tests/e2e/output-display-count.spec.ts

91 lines
4.3 KiB
TypeScript
Raw Normal View History

import { expect, test } from '@playwright/test';
import { loadProbe } from './helpers';
import type { MfDebugHook } from '../../src/console/ConsoleApp';
declare global {
interface Window {
__mf?: MfDebugHook;
}
}
test('output cards add/delete in both drawer depths and capacity mode avoids reconstruction', async ({ page }) => {
await loadProbe(page);
// Drive the real UI path: output target → Outputs drawer → expanded MIDI
// config. This deliberately does not use the debug setters; the regression
// covers the same interaction an operator performs.
await page.getByTitle(/^Mode:/).click();
await page.getByRole('button', { name: 'MIDI', exact: true }).click();
await page.getByTitle('Outputs').click();
await page.getByTitle('Expand').click();
// MIDI starts with eight output cards. Delete six real cards instead of
// editing a detached numeric count.
await expect(page.getByText('8 outputs', { exact: true })).toBeVisible();
for (let i = 0; i < 6; ++i) {
await page.getByRole('button', { name: /^Delete .* output$/ }).last().click();
}
await expect(page.getByText('2 outputs', { exact: true })).toBeVisible();
// Default "Keep capacity" policy edits semantic mappings in place.
expect(await page.evaluate(() => window.__nisps!.getOutputs().length)).toBe(33);
// The count remains visible in condensed chrome after leaving the advanced
// config. Adding in condensed depth updates that same card set.
await page.getByTitle('Condense').click();
await expect(page.getByText('2 outputs', { exact: true })).toBeVisible();
await page.getByRole('button', { name: '+ output', exact: true }).click();
await expect(page.getByText('3 outputs', { exact: true })).toBeVisible();
await page.getByTitle('Close').click();
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', '3');
// Backends without a configured count present the full mode output set.
const fullCount = await page.evaluate(() => window.__mf!.paramCount());
await page.getByTitle(/^Mode:/).click();
await page.getByRole('button', { name: 'OSC', exact: true }).click();
await expect(page.getByTestId('output-stage')).toHaveAttribute('data-output-count', String(fullCount));
});
test('deleting a named particle card removes that identity instead of shifting its name', async ({ page }) => {
await loadProbe(page);
await page.getByTitle('Outputs').click();
await expect(page.getByRole('button', { name: 'Delete Scale output' })).toBeVisible();
await page.getByRole('button', { name: 'Delete Scale output' }).click();
await expect(page.getByText('32 outputs', { exact: true })).toBeVisible();
await expect(page.getByRole('button', { name: 'Delete Scale output' })).toHaveCount(0);
await expect(page.getByRole('button', { name: 'Delete Speed output' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Delete Hue output' })).toBeVisible();
});
test('exact I/O persists and adapts examples across a deleted output identity', async ({ page }) => {
await loadProbe(page);
await page.getByTitle('Settings').click();
await page.getByRole('radio', { name: 'Exact I/O' }).click();
await page.getByTitle('Close').click();
await page.getByTitle(/^Mode:/).click();
await page.getByRole('button', { name: 'MIDI', exact: true }).click();
await expect.poll(() => page.evaluate(() => window.__nisps!.getOutputs().length)).toBe(8);
const added = await page.evaluate(() => {
const probe = window.__nisps!;
probe.setFeedbackMode('explore_and_place');
return probe.addExample([0.1, 0.2, 0.3, 0.4], Array.from(probe.getOutputs()));
});
expect(added).toBe(true);
expect(await page.evaluate(() => window.__nisps!.getExampleCount())).toBe(1);
await page.getByTitle('Outputs').click();
await page.getByRole('button', { name: /^Delete .* output$/ }).first().click();
await expect.poll(() => page.evaluate(() => window.__nisps!.getOutputs().length)).toBe(7);
expect(await page.evaluate(() => window.__nisps!.getExampleCount())).toBe(1);
expect(await page.evaluate(() => window.__nisps!.getFeedbackMode())).toBe('explore_and_place');
const persisted = await page.evaluate(() => JSON.parse(localStorage.getItem('mf-settings') ?? '{}'));
expect(persisted.networkResizePolicy).toBe('exact');
expect(persisted.exampleResizePolicy).toBe('adapt');
expect(persisted.addedOutputExampleValue).toBe(0.5);
});