/** * SETTINGS-SEMANTIC QA sweep: verify every tool setting actually changes the * output in the expected way, not just "no crash". * * For each tool, we vary one setting at a time from a sane default, process, * download, and assert the output changed as expected via decode oracles * (imageInfo, imageLuma, imageSaturation, probeMedia, mediaDuration, magicMatches). * * Run: * pnpm playwright test --config tests/qa/playwright.qa.config.ts tests/qa/settings.qa.spec.ts --workers=1 */ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { expect, type Page, test } from "@playwright/test"; import { downloadResult, fixture, gotoTool, imageInfo, imageLuma, imageSaturation, instrument, isClean, issuesSummary, magicMatches, mediaDuration, type PageIssues, probeMedia, processTool, signalStats, uploadFiles, } from "./qa-helpers"; // ── Findings accumulator ───────────────────────────────────────────── interface Finding { tool: string; setting: string; value: string; expected: string; actual: string; severity: "bug" | "warn"; } const findings: Finding[] = []; const coverage: Record = {}; function bug(f: Omit) { findings.push({ ...f, severity: "bug" }); } function warn(f: Omit) { findings.push({ ...f, severity: "warn" }); } // ── Fixtures ───────────────────────────────────────────────────────── const IMG_200x150 = fixture("image", "valid", "test-200x150.png"); // 200x150 PNG const IMG_JPG = fixture("image", "valid", "sample-photo.jpg"); const VID_MP4 = fixture("video", "formats", "tiny.mp4"); // 64x64, 1s, 8fps const AUD_MP3 = fixture("audio", "formats", "tiny.mp3"); // mono, ~1s const AUD_STEREO = fixture("audio", "formats", "tone-stereo.wav"); // stereo, 1s const PDF_3PAGE = fixture("document", "valid", "test-3page.pdf"); // 3 pages // ── Helpers ────────────────────────────────────────────────────────── const TOOL_TIMEOUT = 120_000; /** Fill a numeric input by id, clearing first. */ async function fillInput(page: Page, id: string, value: string | number) { const input = page.locator(`#${id}`); await input.waitFor({ state: "visible", timeout: 10_000 }); await input.fill(String(value)); } /** Set a slider by id to a specific value. */ async function setSlider(page: Page, id: string, value: number) { const slider = page.locator(`#${id}`); await slider.waitFor({ state: "visible", timeout: 10_000 }); await slider.fill(String(value)); } /** Select a value in a