fix(lint): resolve explicit any and empty catch in DM test scripts

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
emil
2026-05-15 18:10:36 +03:00
co-authored by Sisyphus
parent 8eafd504b2
commit 659b042de5
2 changed files with 60 additions and 51 deletions
+9 -6
View File
@@ -1,7 +1,7 @@
import { test, expect } from "@playwright/test"; import { test, expect, type Page } from "@playwright/test";
test.describe("Data Migration", () => { test.describe("Data Migration", () => {
async function seedStorage(page: any) { async function seedStorage(page: Page) {
await page.goto("/dm/"); await page.goto("/dm/");
await page.evaluate(() => { await page.evaluate(() => {
sessionStorage.setItem( sessionStorage.setItem(
@@ -37,9 +37,12 @@ test.describe("Data Migration", () => {
const migrated = await page.evaluate(() => { const migrated = await page.evaluate(() => {
const raw = sessionStorage.getItem("dm-dice-history"); const raw = sessionStorage.getItem("dm-dice-history");
if (!raw) return null; if (!raw) return null;
const parsed = JSON.parse(raw); const parsed = JSON.parse(raw) as Array<{
total?: unknown;
rolls?: unknown;
}>;
return parsed.every( return parsed.every(
(entry: any) => (entry) =>
entry.total !== undefined && entry.total !== undefined &&
Array.isArray(entry.rolls) Array.isArray(entry.rolls)
); );
@@ -73,8 +76,8 @@ test.describe("Data Migration", () => {
const migrated = await page.evaluate(() => { const migrated = await page.evaluate(() => {
const raw = sessionStorage.getItem("dm-initiative"); const raw = sessionStorage.getItem("dm-initiative");
if (!raw) return true; if (!raw) return true;
const parsed = JSON.parse(raw); const parsed = JSON.parse(raw) as Array<{ id?: unknown }>;
return parsed.length === 0 || parsed.every((c: any) => typeof c.id === "string"); return parsed.length === 0 || parsed.every((c) => typeof c.id === "string");
}); });
expect(migrated).toBe(true); expect(migrated).toBe(true);
}); });
+51 -45
View File
@@ -2,6 +2,10 @@ import { chromium, type Browser, type Page } from "playwright";
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
function errMsg(e: unknown): string {
return e instanceof Error ? e.message : String(e);
}
const BASE_URL = "http://localhost:4322"; const BASE_URL = "http://localhost:4322";
const EVIDENCE_DIR = ".sisyphus/evidence/final-qa"; const EVIDENCE_DIR = ".sisyphus/evidence/final-qa";
@@ -26,7 +30,9 @@ async function screenshot(name: string) {
const filePath = path.join(EVIDENCE_DIR, `${name}.png`); const filePath = path.join(EVIDENCE_DIR, `${name}.png`);
try { try {
await page.screenshot({ path: filePath, fullPage: true }); await page.screenshot({ path: filePath, fullPage: true });
} catch {} } catch {
// ignore screenshot errors (e.g., page not ready)
}
return filePath; return filePath;
} }
@@ -78,8 +84,8 @@ async function testTabs() {
const pass = hasHash && focusedAfterArrow === "initiative"; const pass = hasHash && focusedAfterArrow === "initiative";
log("T2: Tab switching and URL hash", pass ? "PASS" : "FAIL", `hash=${hasHash}, keyboardFocused=${focusedAfterArrow}`); log("T2: Tab switching and URL hash", pass ? "PASS" : "FAIL", `hash=${hasHash}, keyboardFocused=${focusedAfterArrow}`);
await screenshot("t2-tabs-navigation"); await screenshot("t2-tabs-navigation");
} catch (e: any) { } catch (e) {
log("T2: Tab switching and URL hash", "FAIL", e.message); log("T2: Tab switching and URL hash", "FAIL", errMsg(e));
} }
try { try {
@@ -101,8 +107,8 @@ async function testTabs() {
log("T2: Mobile scrollable tabs", allInRow && minHeightOk ? "PASS" : "FAIL", `allInRow=${allInRow}, minHeightOk=${minHeightOk}, tabCount=${tabs.length}`); log("T2: Mobile scrollable tabs", allInRow && minHeightOk ? "PASS" : "FAIL", `allInRow=${allInRow}, minHeightOk=${minHeightOk}, tabCount=${tabs.length}`);
await screenshot("t2-tabs-mobile"); await screenshot("t2-tabs-mobile");
} catch (e: any) { } catch (e) {
log("T2: Mobile scrollable tabs", "FAIL", e.message); log("T2: Mobile scrollable tabs", "FAIL", errMsg(e));
} }
try { try {
@@ -113,8 +119,8 @@ async function testTabs() {
const ariaSelected = await page.locator('[data-tab="initiative"]:visible').getAttribute("aria-selected"); const ariaSelected = await page.locator('[data-tab="initiative"]:visible').getAttribute("aria-selected");
log("T2: Initial tab state", ariaSelected === "true" ? "PASS" : "FAIL", `aria-selected=${ariaSelected}`); log("T2: Initial tab state", ariaSelected === "true" ? "PASS" : "FAIL", `aria-selected=${ariaSelected}`);
await screenshot("t2-tabs-initial"); await screenshot("t2-tabs-initial");
} catch (e: any) { } catch (e) {
log("T2: Initial tab state", "FAIL", e.message); log("T2: Initial tab state", "FAIL", errMsg(e));
} }
} }
@@ -153,8 +159,8 @@ async function testDice() {
const pass = resultValid && customValid && historyItems >= 2 && emptyVisible; const pass = resultValid && customValid && historyItems >= 2 && emptyVisible;
log("T9: Dice rolling and history", pass ? "PASS" : "FAIL", `d20=${resultNum}(valid=${resultValid}), 2d6+3=${customNum}(valid=${customValid}), history=${historyItems}, empty=${emptyVisible}`); log("T9: Dice rolling and history", pass ? "PASS" : "FAIL", `d20=${resultNum}(valid=${resultValid}), 2d6+3=${customNum}(valid=${customValid}), history=${historyItems}, empty=${emptyVisible}`);
await screenshot("t9-dice-roller"); await screenshot("t9-dice-roller");
} catch (e: any) { } catch (e) {
log("T9: Dice rolling and history", "FAIL", e.message); log("T9: Dice rolling and history", "FAIL", errMsg(e));
} }
try { try {
@@ -188,8 +194,8 @@ async function testDice() {
const pass = colorClassesFound; const pass = colorClassesFound;
log("T9: Critical hit/fail colors", pass ? "PASS" : "FAIL", `foundCrit=${foundCrit}, foundFail=${foundFail}, colorClasses=${colorClassesFound}`); log("T9: Critical hit/fail colors", pass ? "PASS" : "FAIL", `foundCrit=${foundCrit}, foundFail=${foundFail}, colorClasses=${colorClassesFound}`);
await screenshot("t9-dice-crit"); await screenshot("t9-dice-crit");
} catch (e: any) { } catch (e) {
log("T9: Critical hit/fail colors", "FAIL", e.message); log("T9: Critical hit/fail colors", "FAIL", errMsg(e));
} }
try { try {
@@ -204,8 +210,8 @@ async function testDice() {
const pass = hoverClassCheck && activeClassCheck; const pass = hoverClassCheck && activeClassCheck;
log("T9: Hover and active states", pass ? "PASS" : "FAIL", `hoverClass=${hoverClassCheck}, activeClass=${activeClassCheck}`); log("T9: Hover and active states", pass ? "PASS" : "FAIL", `hoverClass=${hoverClassCheck}, activeClass=${activeClassCheck}`);
await screenshot("t9-dice-states"); await screenshot("t9-dice-states");
} catch (e: any) { } catch (e) {
log("T9: Hover and active states", "FAIL", e.message); log("T9: Hover and active states", "FAIL", errMsg(e));
} }
} }
@@ -251,8 +257,8 @@ async function testInitiative() {
const pass = goblinVisible && goblinName?.includes("Гоблин") && sortedCorrectly && turnChanged && countAfterDelete === 1; const pass = goblinVisible && goblinName?.includes("Гоблин") && sortedCorrectly && turnChanged && countAfterDelete === 1;
log("T10: Initiative tracking flow", pass ? "PASS" : "FAIL", `goblin=${goblinVisible}, sorted=${sortedCorrectly}, turnChanged=${turnChanged}, afterDelete=${countAfterDelete}`); log("T10: Initiative tracking flow", pass ? "PASS" : "FAIL", `goblin=${goblinVisible}, sorted=${sortedCorrectly}, turnChanged=${turnChanged}, afterDelete=${countAfterDelete}`);
await screenshot("t10-initiative"); await screenshot("t10-initiative");
} catch (e: any) { } catch (e) {
log("T10: Initiative tracking flow", "FAIL", e.message); log("T10: Initiative tracking flow", "FAIL", errMsg(e));
} }
} }
@@ -292,8 +298,8 @@ async function testOpen5e() {
const pass = (resultsVisible || emptyVisible) && (searchResults > 0 || emptyVisible); const pass = (resultsVisible || emptyVisible) && (searchResults > 0 || emptyVisible);
log("T11: Open5e search and detail", pass ? "PASS" : "FAIL", `results=${resultsVisible}, empty=${emptyVisible}, searchResults=${searchResults}, modalOpened=${modalOpened}, modalClosed=${modalClosed}`); log("T11: Open5e search and detail", pass ? "PASS" : "FAIL", `results=${resultsVisible}, empty=${emptyVisible}, searchResults=${searchResults}, modalOpened=${modalOpened}, modalClosed=${modalClosed}`);
await screenshot("t11-open5e"); await screenshot("t11-open5e");
} catch (e: any) { } catch (e) {
log("T11: Open5e search and detail", "FAIL", e.message); log("T11: Open5e search and detail", "FAIL", errMsg(e));
} }
try { try {
@@ -309,8 +315,8 @@ async function testOpen5e() {
const noResults = await page.locator("[data-testid='ref-result-card']:visible").count() === 0; const noResults = await page.locator("[data-testid='ref-result-card']:visible").count() === 0;
log("T11: Empty search state", emptyVisible || noResults ? "PASS" : "FAIL", `emptyVisible=${emptyVisible}, noResults=${noResults}`); log("T11: Empty search state", emptyVisible || noResults ? "PASS" : "FAIL", `emptyVisible=${emptyVisible}, noResults=${noResults}`);
await screenshot("t11-open5e-empty"); await screenshot("t11-open5e-empty");
} catch (e: any) { } catch (e) {
log("T11: Empty search state", "FAIL", e.message); log("T11: Empty search state", "FAIL", errMsg(e));
} }
} }
@@ -351,8 +357,8 @@ async function testNotes() {
const pass = savedVisible && parseFloat(savedOpacity) > 0.1 && charCount === "16" && syncWorked && cleared; const pass = savedVisible && parseFloat(savedOpacity) > 0.1 && charCount === "16" && syncWorked && cleared;
log("T12: Notes auto-save and cross-tab sync", pass ? "PASS" : "FAIL", `savedVisible=${savedVisible}, savedOpacity=${savedOpacity}, chars=${charCount}, sync=${syncWorked}, cleared=${cleared}`); log("T12: Notes auto-save and cross-tab sync", pass ? "PASS" : "FAIL", `savedVisible=${savedVisible}, savedOpacity=${savedOpacity}, chars=${charCount}, sync=${syncWorked}, cleared=${cleared}`);
await screenshot("t12-notes-sync"); await screenshot("t12-notes-sync");
} catch (e: any) { } catch (e) {
log("T12: Notes auto-save and cross-tab sync", "FAIL", e.message); log("T12: Notes auto-save and cross-tab sync", "FAIL", errMsg(e));
} }
} }
@@ -378,8 +384,8 @@ async function testPage() {
log("T6: All sections accessible", allAccessible ? "PASS" : "FAIL", `allAccessible=${allAccessible}`); log("T6: All sections accessible", allAccessible ? "PASS" : "FAIL", `allAccessible=${allAccessible}`);
await screenshot("t6-sections"); await screenshot("t6-sections");
} catch (e: any) { } catch (e) {
log("T6: All sections accessible", "FAIL", e.message); log("T6: All sections accessible", "FAIL", errMsg(e));
} }
} }
@@ -400,8 +406,8 @@ async function testIntegration() {
if (!url.includes(`#${tabId}`)) pass = false; if (!url.includes(`#${tabId}`)) pass = false;
} }
log("INT-1: Switch between all tabs", pass ? "PASS" : "FAIL", `urlHashOk=${pass}`); log("INT-1: Switch between all tabs", pass ? "PASS" : "FAIL", `urlHashOk=${pass}`);
} catch (e: any) { } catch (e) {
log("INT-1: Switch between all tabs", "FAIL", e.message); log("INT-1: Switch between all tabs", "FAIL", errMsg(e));
} }
try { try {
@@ -424,8 +430,8 @@ async function testIntegration() {
const pass = historyCount >= 2 && emptyVisible; const pass = historyCount >= 2 && emptyVisible;
log("INT-2: Roll dice, check history, clear", pass ? "PASS" : "FAIL", `history=${historyCount}, empty=${emptyVisible}`); log("INT-2: Roll dice, check history, clear", pass ? "PASS" : "FAIL", `history=${historyCount}, empty=${emptyVisible}`);
} catch (e: any) { } catch (e) {
log("INT-2: Roll dice, check history, clear", "FAIL", e.message); log("INT-2: Roll dice, check history, clear", "FAIL", errMsg(e));
} }
try { try {
@@ -461,8 +467,8 @@ async function testIntegration() {
const pass = sorted && turnChanged && countAfterDelete === 1; const pass = sorted && turnChanged && countAfterDelete === 1;
log("INT-3: Initiative flow", pass ? "PASS" : "FAIL", `sorted=${sorted}, turnChanged=${turnChanged}, afterDelete=${countAfterDelete}`); log("INT-3: Initiative flow", pass ? "PASS" : "FAIL", `sorted=${sorted}, turnChanged=${turnChanged}, afterDelete=${countAfterDelete}`);
} catch (e: any) { } catch (e) {
log("INT-3: Initiative flow", "FAIL", e.message); log("INT-3: Initiative flow", "FAIL", errMsg(e));
} }
try { try {
@@ -494,8 +500,8 @@ async function testIntegration() {
const pass = cards > 0 && modalOpened && modalClosed; const pass = cards > 0 && modalOpened && modalClosed;
log("INT-4: Open5e search and modal", pass ? "PASS" : "FAIL", `cards=${cards}, modalOpened=${modalOpened}, modalClosed=${modalClosed}`); log("INT-4: Open5e search and modal", pass ? "PASS" : "FAIL", `cards=${cards}, modalOpened=${modalOpened}, modalClosed=${modalClosed}`);
} catch (e: any) { } catch (e) {
log("INT-4: Open5e search and modal", "FAIL", e.message); log("INT-4: Open5e search and modal", "FAIL", errMsg(e));
} }
try { try {
@@ -512,8 +518,8 @@ async function testIntegration() {
const value = await page.locator("[data-testid='notes-textarea']:visible").inputValue(); const value = await page.locator("[data-testid='notes-textarea']:visible").inputValue();
const pass = value === "Persistent note test"; const pass = value === "Persistent note test";
log("INT-5: Notes persistence", pass ? "PASS" : "FAIL", `value="${value}"`); log("INT-5: Notes persistence", pass ? "PASS" : "FAIL", `value="${value}"`);
} catch (e: any) { } catch (e) {
log("INT-5: Notes persistence", "FAIL", e.message); log("INT-5: Notes persistence", "FAIL", errMsg(e));
} }
try { try {
@@ -539,8 +545,8 @@ async function testIntegration() {
await page.setViewportSize({ width: 375, height: 812 }); await page.setViewportSize({ width: 375, height: 812 });
await page.waitForTimeout(300); await page.waitForTimeout(300);
await screenshot("int6-responsive-mobile"); await screenshot("int6-responsive-mobile");
} catch (e: any) { } catch (e) {
log("INT-6: Responsive layout", "FAIL", e.message); log("INT-6: Responsive layout", "FAIL", errMsg(e));
} }
} }
@@ -570,8 +576,8 @@ async function testEdgeCases() {
const pass = diceEmpty && initEmpty && notesEmpty; const pass = diceEmpty && initEmpty && notesEmpty;
log("EDGE-1: Empty states", pass ? "PASS" : "FAIL", `dice=${diceEmpty}, init=${initEmpty}, notes=${notesEmpty}`); log("EDGE-1: Empty states", pass ? "PASS" : "FAIL", `dice=${diceEmpty}, init=${initEmpty}, notes=${notesEmpty}`);
await screenshot("edge1-empty-states"); await screenshot("edge1-empty-states");
} catch (e: any) { } catch (e) {
log("EDGE-1: Empty states", "FAIL", e.message); log("EDGE-1: Empty states", "FAIL", errMsg(e));
} }
try { try {
@@ -589,8 +595,8 @@ async function testEdgeCases() {
const url = page.url(); const url = page.url();
const hasValidHash = tabs.some((t) => url.includes(`#${t}`)); const hasValidHash = tabs.some((t) => url.includes(`#${t}`));
log("EDGE-2: Rapid tab switching", hasValidHash ? "PASS" : "FAIL", `url=${url}`); log("EDGE-2: Rapid tab switching", hasValidHash ? "PASS" : "FAIL", `url=${url}`);
} catch (e: any) { } catch (e) {
log("EDGE-2: Rapid tab switching", "FAIL", e.message); log("EDGE-2: Rapid tab switching", "FAIL", errMsg(e));
} }
try { try {
@@ -606,8 +612,8 @@ async function testEdgeCases() {
const detailsText = await page.locator("#result-details").first().textContent(); const detailsText = await page.locator("#result-details").first().textContent();
const pass = resultText === "?" || detailsText?.includes("Invalid"); const pass = resultText === "?" || detailsText?.includes("Invalid");
log("EDGE-3: Invalid dice notation", pass ? "PASS" : "FAIL", `result="${resultText}", details="${detailsText}"`); log("EDGE-3: Invalid dice notation", pass ? "PASS" : "FAIL", `result="${resultText}", details="${detailsText}"`);
} catch (e: any) { } catch (e) {
log("EDGE-3: Invalid dice notation", "FAIL", e.message); log("EDGE-3: Invalid dice notation", "FAIL", errMsg(e));
} }
try { try {
@@ -625,8 +631,8 @@ async function testEdgeCases() {
const pass = (hasResults || hasEmptyState) && noError; const pass = (hasResults || hasEmptyState) && noError;
log("EDGE-4: Empty search in Open5e", pass ? "PASS" : "FAIL", `results=${hasResults}, empty=${hasEmptyState}, noError=${noError}`); log("EDGE-4: Empty search in Open5e", pass ? "PASS" : "FAIL", `results=${hasResults}, empty=${hasEmptyState}, noError=${noError}`);
} catch (e: any) { } catch (e) {
log("EDGE-4: Empty search in Open5e", "FAIL", e.message); log("EDGE-4: Empty search in Open5e", "FAIL", errMsg(e));
} }
try { try {
@@ -643,8 +649,8 @@ async function testEdgeCases() {
const charCount = await page.locator("[data-testid='notes-char-count']:visible").first().textContent(); const charCount = await page.locator("[data-testid='notes-char-count']:visible").first().textContent();
const pass = value === "" && charCount === "0"; const pass = value === "" && charCount === "0";
log("EDGE-5: Clear notes after typing", pass ? "PASS" : "FAIL", `value="${value}", chars=${charCount}`); log("EDGE-5: Clear notes after typing", pass ? "PASS" : "FAIL", `value="${value}", chars=${charCount}`);
} catch (e: any) { } catch (e) {
log("EDGE-5: Clear notes after typing", "FAIL", e.message); log("EDGE-5: Clear notes after typing", "FAIL", errMsg(e));
} }
} }