tests/system/correctness.test.js
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
- import { chromium } from "playwright";
- import { unlinkSync } from "fs";
- import { tmpdir } from "os";
- import { join } from "path";
- import { findChrome } from "../../config/find-chrome.js";
- describe("system: pipeline workflow with default parameters", () => {
- let browser, page;
- beforeAll(async () => {
- const url = "http://localhost:8080";
- const resp = await fetch(url).catch(() => null);
- if (!resp?.ok) {
- throw new Error(
- `App not reachable at ${url}. Start it first: npm run app`,
- );
- }
- browser = await chromium.launch({
- executablePath: findChrome(),
- headless: false,
- args: [
- "--no-sandbox",
- "--disable-setuid-sandbox",
- "--disable-dev-shm-usage",
- ],
- });
- page = await browser.newPage();
- await page.goto(url);
- }, 30000);
- afterAll(async () => {
- await browser?.close();
- });
- it("app initializes and reaches ready state", async () => {
- const status = page.locator("#output-status");
- await status.waitFor({ state: "visible", timeout: 20000 });
- const text = await status.textContent();
- expect(text).toMatch(/Ready/);
- }, 30000);
- it("parameters round-trip through export and re-import", async () => {
-
- const [download] = await Promise.all([
- page.waitForEvent("download"),
- page.click("button:has-text('Export')"),
- ]);
- const exportPath = join(tmpdir(), "params-export.json");
- await download.saveAs(exportPath);
-
- const fileInput = page.locator("#import-params");
- await fileInput.setInputFiles(exportPath);
-
- const nameField = page.locator("#import-params-name");
- await nameField.waitFor({ state: "visible", timeout: 5000 });
- const val = await nameField.inputValue();
- expect(val).toMatch(/\.json$/);
- unlinkSync(exportPath);
- }, 30000);
- it("Run button produces MIDI output", async () => {
- await page.click("#run-optimization-button");
-
- await page.waitForFunction(
- () => {
- const el = document.getElementById("midi-player");
- return el?.getAttribute("src")?.startsWith("data:audio/midi;base64,");
- },
- { timeout: 60000 },
- );
- const src = await page.locator("#midi-player").getAttribute("src");
- expect(src).toMatch(/^data:audio\/midi;base64,/);
- }, 90000);
- it("MIDI player plays back from start to stop event", async () => {
-
- await page.waitForFunction(
- () => document.getElementById("midi-player")?.duration > 0,
- { timeout: 10000 },
- );
-
- await page.evaluate(async () => {
- const player = document.getElementById("midi-player");
- const started = new Promise((resolve) => {
- player.addEventListener("start", () => resolve(), { once: true });
- });
- const stopped = new Promise((resolve) => {
- player.addEventListener("stop", () => resolve(), { once: true });
- });
- const btn = player.shadowRoot?.querySelector("button[title='play']");
- if (btn) {
- btn.click();
- } else {
- player.start?.();
- }
- await started;
- await stopped;
- });
- }, 60000);
- it("MIDI download button triggers a file download", async () => {
- const [download] = await Promise.all([
- page.waitForEvent("download"),
- page.click("button:has-text('Download')"),
- ]);
- const filename = download.suggestedFilename();
- expect(filename).toMatch(/\.mid$/);
- }, 30000);
- });