Fix E2E flakiness and implicit any type errors

This commit is contained in:
diegosouzapw
2026-04-27 17:28:45 -03:00
parent cd67c18049
commit caeba1fd91
6 changed files with 38 additions and 50 deletions

View File

@@ -81,7 +81,7 @@ test.describe("Memory settings", () => {
deleteCalls: 0,
};
await page.route("**/api/settings", async (route) => {
await page.route(/\/api\/settings$/, async (route) => {
const method = route.request().method();
if (method === "GET") {
await fulfillJson(route, state.settings);
@@ -101,7 +101,7 @@ test.describe("Memory settings", () => {
await fulfillJson(route, { error: "Method not allowed in settings stub" }, 405);
});
await page.route("**/api/settings/memory", async (route) => {
await page.route(/\/api\/settings\/memory$/, async (route) => {
const method = route.request().method();
if (method === "GET") {
await fulfillJson(route, state.config);

View File

@@ -2,34 +2,24 @@ import { test, expect } from "@playwright/test";
import { gotoDashboardRoute } from "./helpers/dashboardAuth";
test.describe("Protocol visibility", () => {
test("shows MCP/A2A links inside protocols tab in endpoint page", async ({ page }) => {
test("shows MCP and A2A tabs inside the endpoint page", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/endpoint");
await page.waitForLoadState("networkidle");
// MCP and A2A are now shown inside the "Protocols" tab — click it first
const protocolTab = page.getByRole("tab", { name: /protocols|protocolos/i });
await expect(protocolTab).toBeVisible();
await protocolTab.click();
// MCP and A2A are now tabs directly in the SegmentedControl
const mcpTab = page.getByRole("tab", { name: "MCP" });
const a2aTab = page.getByRole("tab", { name: "A2A" });
// Links to MCP and A2A management pages appear after tab switch
await expect(page.locator('a[href="/dashboard/mcp"]').first()).toBeVisible();
await expect(page.locator('a[href="/dashboard/a2a"]').first()).toBeVisible();
await expect(mcpTab).toBeVisible();
await expect(a2aTab).toBeVisible();
const mcpLinks = await page.locator('a[href="/dashboard/mcp"]').count();
const a2aLinks = await page.locator('a[href="/dashboard/a2a"]').count();
expect(mcpLinks).toBeGreaterThanOrEqual(1);
expect(a2aLinks).toBeGreaterThanOrEqual(1);
});
test("loads MCP and A2A dashboards without runtime error page", async ({ page }) => {
await gotoDashboardRoute(page, "/dashboard/mcp");
await page.waitForLoadState("networkidle");
await expect(page.locator("body")).toBeVisible();
// Verify MCP dashboard mounts
await mcpTab.click();
// In dev/test it might just show "loading..." or the processStatus card
await expect(page.locator("body")).not.toContainText(/application error|500/i);
await gotoDashboardRoute(page, "/dashboard/a2a");
await page.waitForLoadState("networkidle");
await expect(page.locator("body")).toBeVisible();
// Verify A2A dashboard mounts
await a2aTab.click();
await expect(page.locator("body")).not.toContainText(/application error|500/i);
});
});

View File

@@ -69,18 +69,13 @@ test.describe("Bailian Coding Plan Provider", () => {
}
const addKeyButton = page.getByRole("button", {
name: /add.*api.*key|add.*key|add.*connection|connect/i,
name: /add.*api.*key|add.*key|add.*connection|connect|adicionar.*chave/i,
});
if (
await addKeyButton
.first()
.isVisible({ timeout: 15000 })
.catch(() => false)
) {
await expect(addKeyButton.first()).toBeEnabled({ timeout: 5000 });
await addKeyButton.first().click();
}
// Wait for the button to appear instead of immediately checking visibility
await addKeyButton.first().waitFor({ state: "visible", timeout: 15000 });
await expect(addKeyButton.first()).toBeEnabled({ timeout: 5000 });
await addKeyButton.first().click();
const dialog = page.getByRole("dialog").first();
await expect(dialog).toBeVisible({ timeout: 10000 });
@@ -185,18 +180,13 @@ test.describe("Bailian Coding Plan Provider", () => {
}
const addKeyButton = page.getByRole("button", {
name: /add.*api.*key|add.*key|add.*connection|connect/i,
name: /add.*api.*key|add.*key|add.*connection|connect|adicionar.*chave/i,
});
if (
await addKeyButton
.first()
.isVisible({ timeout: 15000 })
.catch(() => false)
) {
await expect(addKeyButton.first()).toBeEnabled({ timeout: 5000 });
await addKeyButton.first().click();
}
// Wait for the button to appear instead of immediately checking visibility
await addKeyButton.first().waitFor({ state: "visible", timeout: 15000 });
await expect(addKeyButton.first()).toBeEnabled({ timeout: 5000 });
await addKeyButton.first().click();
const dialog = page.getByRole("dialog").first();
await expect(dialog).toBeVisible({ timeout: 10000 });

View File

@@ -38,7 +38,10 @@ async function createManagementKey() {
return apiKeysDb.createApiKey("management", MACHINE_ID);
}
function makeRequest(url, { method = "GET", token, body } = {}) {
function makeRequest(
url: string | URL,
{ method = "GET", token, body }: { method?: string; token?: string; body?: unknown } = {}
) {
const headers = new Headers();
if (token) {
headers.set("authorization", `Bearer ${token}`);

View File

@@ -30,7 +30,7 @@ const { clearProviderFailure } = await import("../../open-sse/services/accountFa
const originalFetch = globalThis.fetch;
const originalRetryDelayMs = BaseExecutor.RETRY_CONFIG.delayMs;
function toPlainHeaders(headers) {
function toPlainHeaders(headers: Headers | Record<string, unknown> | undefined | null) {
if (!headers) return {};
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
return Object.fromEntries(
@@ -43,8 +43,13 @@ function buildRequest({
body,
authKey = null,
headers = {},
}: {
url?: string;
body?: unknown;
authKey?: string | null;
headers?: Record<string, string>;
} = {}) {
const requestHeaders = {
const requestHeaders: Record<string, string> = {
"Content-Type": "application/json",
...headers,
};

View File

@@ -14,19 +14,19 @@ import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, "..", "..");
function readProjectFile(relPath) {
function readProjectFile(relPath: string) {
const full = join(ROOT, relPath);
if (!existsSync(full)) return null;
return readFileSync(full, "utf8");
}
function assertFileExists(relPath) {
function assertFileExists(relPath: string) {
const full = join(ROOT, relPath);
assert.ok(existsSync(full), `${relPath} should exist`);
return full;
}
function assertRouteMethods(relPath, methods) {
function assertRouteMethods(relPath: string, methods: string[]) {
const src = readProjectFile(relPath);
assert.ok(src, `${relPath} should exist`);
for (const method of methods) {
@@ -34,7 +34,7 @@ function assertRouteMethods(relPath, methods) {
}
}
function listProjectFiles(relPath) {
function listProjectFiles(relPath: string): string[] {
const full = join(ROOT, relPath);
if (!existsSync(full)) return [];