mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
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
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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:<full-model-string>"
|
||||
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,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user