import { test, testSkipIfWindows, Timeout } from "./helpers/test_helper";
import { expect } from "@playwright/test";
import fs from "fs";
import path from "path";
const MINIMAL_APP = "minimal-with-ai-rules";
test("problems auto-fix - enabled", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.importApp(MINIMAL_APP);
await po.expectPreviewIframeIsVisible();
await po.sendPrompt("tc=create-ts-errors");
await po.snapshotServerDump("all-messages", { dumpIndex: -2 });
await po.snapshotServerDump("all-messages", { dumpIndex: -1 });
await po.snapshotMessages({ replaceDumpPath: true });
});
test("problems auto-fix - gives up after 2 attempts", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.importApp(MINIMAL_APP);
await po.expectPreviewIframeIsVisible();
await po.sendPrompt("tc=create-unfixable-ts-errors");
await po.snapshotServerDump("all-messages", { dumpIndex: -2 });
await po.snapshotServerDump("all-messages", { dumpIndex: -1 });
await po.page.getByTestId("problem-summary").last().click();
await expect(
po.page.getByTestId("problem-summary").last(),
).toMatchAriaSnapshot();
await po.snapshotMessages({ replaceDumpPath: true });
});
test("problems auto-fix - complex delete-rename-write", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.importApp(MINIMAL_APP);
await po.expectPreviewIframeIsVisible();
await po.sendPrompt("tc=create-ts-errors-complex");
await po.snapshotServerDump("all-messages", { dumpIndex: -2 });
await po.snapshotServerDump("all-messages", { dumpIndex: -1 });
await po.snapshotMessages({ replaceDumpPath: true });
});
test("problems auto-fix - disabled", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: false });
await po.importApp(MINIMAL_APP);
await po.expectPreviewIframeIsVisible();
await po.sendPrompt("tc=create-ts-errors");
await po.snapshotMessages();
});
testSkipIfWindows("problems - fix all", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.importApp(MINIMAL_APP);
const appPath = await po.getCurrentAppPath();
const badFilePath = path.join(appPath, "src", "bad-file.tsx");
fs.writeFileSync(
badFilePath,
`const App = () =>
Minimal imported app
;
nonExistentFunction1();
nonExistentFunction2();
nonExistentFunction3();
export default App;
`,
);
await po.ensurePnpmInstall();
await po.sendPrompt("tc=create-ts-errors");
await po.selectPreviewMode("problems");
await po.clickFixAllProblems();
await po.snapshotServerDump("last-message");
await po.snapshotMessages({ replaceDumpPath: true });
});
testSkipIfWindows(
"problems - select specific problems and fix",
async ({ po }) => {
await po.setUp();
await po.importApp(MINIMAL_APP);
// Create multiple TS errors in one file
const appPath = await po.getCurrentAppPath();
const badFilePath = path.join(appPath, "src", "bad-file.tsx");
fs.writeFileSync(
badFilePath,
`const App = () => Minimal imported app
;
nonExistentFunction1();
nonExistentFunction2();
nonExistentFunction3();
export default App;
`,
);
await po.ensurePnpmInstall();
// Trigger creation of problems and open problems panel
// await po.sendPrompt("tc=create-ts-errors");
await po.selectPreviewMode("problems");
await po.clickRecheckProblems();
// Initially, all selected: button shows Fix X problems and Clear all is visible
const fixButton = po.page.getByTestId("fix-all-button");
await expect(fixButton).toBeVisible();
await expect(fixButton).toContainText(/Fix \d+ problems/);
// Click first two rows to toggle off (deselect)
const rows = po.page.getByTestId("problem-row");
const rowCount = await rows.count();
expect(rowCount).toBeGreaterThan(2);
await rows.nth(0).click();
await rows.nth(1).click();
// Button should update to reflect remaining selected
await expect(fixButton).toContainText(/Fix 1 problem/);
// Clear all should switch to Select all when none selected
// Deselect remaining rows
for (let i = 2; i < rowCount; i++) {
await rows.nth(i).click();
}
const selectButton = po.page.getByRole("button", {
name: /Select all/,
});
await expect(selectButton).toHaveText("Select all");
// Select all, then fix selected
await selectButton.click();
// Unselect the second row
await rows.nth(1).click();
await expect(fixButton).toContainText(/Fix 2 problems/);
await fixButton.click();
await po.waitForChatCompletion();
await po.snapshotServerDump("last-message");
await po.snapshotMessages({ replaceDumpPath: true });
},
);
testSkipIfWindows("problems - manual edit (react/vite)", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.sendPrompt("tc=1");
const appPath = await po.getCurrentAppPath();
const badFilePath = path.join(appPath, "src", "bad-file.tsx");
fs.writeFileSync(
badFilePath,
`const App = () => Minimal imported app
;
nonExistentFunction();
export default App;
`,
);
await po.ensurePnpmInstall();
await po.clickTogglePreviewPanel();
await po.selectPreviewMode("problems");
const fixButton = po.page.getByTestId("fix-all-button");
await expect(fixButton).toBeEnabled({ timeout: Timeout.LONG });
await expect(fixButton).toContainText(/Fix 1 problem/);
fs.unlinkSync(badFilePath);
await po.clickRecheckProblems();
await expect(fixButton).toBeDisabled({ timeout: Timeout.LONG });
await expect(fixButton).toContainText(/Fix 0 problems/);
});
testSkipIfWindows("problems - manual edit (next.js)", async ({ po }) => {
await po.setUp({ enableAutoFixProblems: true });
await po.goToHubAndSelectTemplate("Next.js Template");
await po.sendPrompt("tc=1");
const appPath = await po.getCurrentAppPath();
const badFilePath = path.join(appPath, "src", "bad-file.tsx");
fs.writeFileSync(
badFilePath,
`const App = () => Minimal imported app
;
nonExistentFunction();
export default App;
`,
);
await po.ensurePnpmInstall();
await po.clickTogglePreviewPanel();
await po.selectPreviewMode("problems");
const fixButton = po.page.getByTestId("fix-all-button");
await expect(fixButton).toBeEnabled({ timeout: Timeout.LONG });
await expect(fixButton).toContainText(/Fix 1 problem/);
fs.unlinkSync(badFilePath);
await po.clickRecheckProblems();
await expect(fixButton).toBeDisabled({ timeout: Timeout.LONG });
await expect(fixButton).toContainText(/Fix 0 problems/);
});