From f697c569223f1848d91cf4b951f1b1685de8a0c3 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 10 Mar 2026 08:47:06 -0300 Subject: [PATCH] fix(ci): repair unit, e2e and i18n failures - tests/unit/combo-circuit-breaker: use full model path keys (combo:groq/llama-3.3-70b) matching combo.ts implementation - tests/e2e/protocol-visibility: click Protocols tab before asserting MCP/A2A links (they moved into tab panel, not header nav) - src/i18n/messages/en.json: add missing header.mcp / header.a2a keys that caused MISSING_MESSAGE runtime errors during E2E boot --- src/i18n/messages/en.json | 4 ++++ tests/e2e/protocol-visibility.spec.ts | 14 ++++++++------ tests/unit/combo-circuit-breaker.test.mjs | 22 ++++++++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index d98f24defd..92e004ae11 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -131,6 +131,10 @@ "homeDescription": "Welcome to OmniRoute", "endpoint": "Endpoints", "endpointDescription": "Manage proxy endpoints, MCP, A2A, and API endpoints", + "mcp": "MCP", + "mcpDescription": "Model Context Protocol server management and tools", + "a2a": "A2A", + "a2aDescription": "Agent-to-Agent protocol tasks and observability", "settings": "Settings", "settingsDescription": "Manage your preferences", "openaiCompatible": "OpenAI Compatible", diff --git a/tests/e2e/protocol-visibility.spec.ts b/tests/e2e/protocol-visibility.spec.ts index b27b2901d5..ca1e3cd21a 100644 --- a/tests/e2e/protocol-visibility.spec.ts +++ b/tests/e2e/protocol-visibility.spec.ts @@ -1,24 +1,26 @@ import { test, expect } from "@playwright/test"; test.describe("Protocol visibility", () => { - test("shows MCP/A2A navigation and protocols tab in endpoint page", async ({ page }) => { + test("shows MCP/A2A links inside protocols tab in endpoint page", async ({ page }) => { await page.goto("/dashboard/endpoint"); await page.waitForLoadState("networkidle"); const redirectedToLogin = page.url().includes("/login"); test.skip(redirectedToLogin, "Authentication enabled without a login fixture."); - await expect(page.locator('a[href="/dashboard/mcp"]').first()).toBeVisible(); - await expect(page.locator('a[href="/dashboard/a2a"]').first()).toBeVisible(); - + // 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(); + // 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(); + const mcpLinks = await page.locator('a[href="/dashboard/mcp"]').count(); const a2aLinks = await page.locator('a[href="/dashboard/a2a"]').count(); - expect(mcpLinks).toBeGreaterThanOrEqual(2); - expect(a2aLinks).toBeGreaterThanOrEqual(2); + expect(mcpLinks).toBeGreaterThanOrEqual(1); + expect(a2aLinks).toBeGreaterThanOrEqual(1); }); test("loads MCP and A2A dashboards without runtime error page", async ({ page }) => { diff --git a/tests/unit/combo-circuit-breaker.test.mjs b/tests/unit/combo-circuit-breaker.test.mjs index 617ed590b0..90d6d9e3de 100644 --- a/tests/unit/combo-circuit-breaker.test.mjs +++ b/tests/unit/combo-circuit-breaker.test.mjs @@ -39,10 +39,13 @@ function mockHandler(statusSequence) { } // ─── Circuit Breaker Integration Tests ────────────────────────────────────── +// NOTE: combo.ts uses the full model string (e.g. "combo:groq/llama-3.3-70b") +// as the circuit breaker key, not just the provider prefix. test("handleComboChat: circuit breaker opens after repeated 502 errors", async () => { - // Reset breaker for this test's provider - const breaker = getCircuitBreaker("combo:groq", { + // breaker key mirrors what combo.ts uses: "combo:" + const breakerKey = "combo:groq/llama-3.3-70b"; + const breaker = getCircuitBreaker(breakerKey, { failureThreshold: 3, resetTimeout: 60000, }); @@ -77,7 +80,8 @@ test("handleComboChat: circuit breaker opens after repeated 502 errors", async ( test("handleComboChat: skips models with open circuit breaker", async () => { // Set up: groq breaker is OPEN, fireworks breaker is CLOSED - const groqBreaker = getCircuitBreaker("combo:groq", { + const groqBreakerKey = "combo:groq/llama-3.3-70b"; + const groqBreaker = getCircuitBreaker(groqBreakerKey, { failureThreshold: 3, resetTimeout: 60000, }); @@ -88,7 +92,8 @@ test("handleComboChat: skips models with open circuit breaker", async () => { groqBreaker._onFailure(); assert.equal(groqBreaker.getStatus().state, STATE.OPEN); - const fireworksBreaker = getCircuitBreaker("combo:fireworks", { + const fireworksBreakerKey = "combo:fireworks/deepseek-v3p1"; + const fireworksBreaker = getCircuitBreaker(fireworksBreakerKey, { failureThreshold: 5, resetTimeout: 30000, }); @@ -125,14 +130,14 @@ test("handleComboChat: skips models with open circuit breaker", async () => { }); test("handleComboChat: returns 503 when all breakers are open", async () => { - // Open both breakers - const groqBreaker = getCircuitBreaker("combo:groq"); + // Open both breakers using the full model string keys + const groqBreaker = getCircuitBreaker("combo:groq/llama-3.3-70b"); groqBreaker.reset(); groqBreaker._onFailure(); groqBreaker._onFailure(); groqBreaker._onFailure(); - const fireworksBreaker = getCircuitBreaker("combo:fireworks"); + const fireworksBreaker = getCircuitBreaker("combo:fireworks/deepseek-v3p1"); fireworksBreaker.reset(); for (let i = 0; i < 5; i++) fireworksBreaker._onFailure(); @@ -163,7 +168,8 @@ test("handleComboChat: returns 503 when all breakers are open", async () => { }); test("handleComboChat: 429 errors also trigger circuit breaker", async () => { - const breaker = getCircuitBreaker("combo:cerebras", { + const breakerKey = "combo:cerebras/llama-3.3-70b"; + const breaker = getCircuitBreaker(breakerKey, { failureThreshold: 5, resetTimeout: 30000, });