possibly fix tests

This commit is contained in:
Swifty
2025-10-31 13:26:08 +01:00
parent 2535046ce6
commit 348991464a
4 changed files with 323 additions and 239 deletions

View File

@@ -7,7 +7,6 @@ import { ChatLoadingState } from "./components/ChatLoadingState/ChatLoadingState
function ChatPage() {
const {
session,
messages,
isLoading,
isCreating,
@@ -55,7 +54,7 @@ function ChatPage() {
)}
{/* Session Content */}
{session && !isLoading && !error && (
{sessionId && !isLoading && !error && (
<ChatContainer
sessionId={sessionId}
initialMessages={messages}

View File

@@ -16,7 +16,9 @@ export const ADMIN_PAGES = ["/admin"] as const;
export function getCookieSettings(): Partial<CookieOptions> {
return {
secure: process.env.NODE_ENV === "production",
// Use secure cookies only when behaving as CLOUD (served over HTTPS)
// Local/dev and Playwright runs use http://localhost, so cookies must be non-secure
secure: environment.isCloud(),
sameSite: "lax",
httpOnly: true,
} as const;

View File

@@ -12,49 +12,48 @@ test.describe("Chat Messages - Tool Call Message", () => {
test("displays tool call message with spinning animation", async ({
page,
}) => {
// Mock the session API to return a session with a tool call message
await page.route("**/api/v1/chat/sessions/*", async (route) => {
// Mock session GET using URL param session=test-session
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
// Navigate to chat and inject messages via page.evaluate
// Mock SSE stream to emit a tool_call event
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const sse = [
`data: ${JSON.stringify({
type: "tool_call",
tool_id: "tool-123",
tool_name: "find_agent",
arguments: { query: "data analysis" },
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
const chatPage = new ChatPage(page);
await chatPage.goto();
await chatPage.goto("test-session");
// Inject messages directly into the component state for testing
await page.evaluate(() => {
const mockMessages = [
{
type: "message",
role: "user",
content: "Find data analysis agents",
timestamp: new Date(),
},
{
type: "tool_call",
toolId: "tool-123",
toolName: "find_agent",
arguments: { query: "data analysis" },
timestamp: new Date(),
},
];
// Trigger streaming
await chatPage.sendMessage("Find data analysis agents");
// Dispatch a custom event or use React DevTools to inject state
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
// Verify tool call message is visible
const toolCallText = page.getByText("find_agent");
await expect(toolCallText).toBeVisible({ timeout: 5000 });
});
@@ -62,76 +61,88 @@ test.describe("Chat Messages - Tool Call Message", () => {
test.describe("Chat Messages - Tool Response Message", () => {
test("displays successful tool response in green", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-456",
tool_name: "get_agent_details",
result: { name: "Test Agent", version: 1 },
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
type: "tool_response",
toolId: "tool-456",
toolName: "get_agent_details",
result: { name: "Test Agent", version: 1 },
success: true,
timestamp: new Date(),
},
];
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
await chatPage.goto("test-session");
await chatPage.sendMessage("details");
const completedText = page.getByText(/Completed.*get_agent_details/);
await expect(completedText).toBeVisible({ timeout: 5000 });
});
test("displays failed tool response in red", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-789",
tool_name: "run_agent",
result: "Error: Agent not found",
success: false,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
type: "tool_response",
toolId: "tool-789",
toolName: "run_agent",
result: "Error: Agent not found",
success: false,
timestamp: new Date(),
},
];
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
await chatPage.goto("test-session");
await chatPage.sendMessage("run");
const failedText = page.getByText(/Failed.*run_agent/);
await expect(failedText).toBeVisible({ timeout: 5000 });
@@ -140,39 +151,44 @@ test.describe("Chat Messages - Tool Response Message", () => {
test.describe("Chat Messages - Login Prompt", () => {
test("displays login prompt with action buttons", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const sse = [
`data: ${JSON.stringify({
type: "login_needed",
message:
"To run agents and save your chat history, please log in to your account.",
session_id: "test-session",
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
const chatPage = new ChatPage(page);
await chatPage.goto();
await chatPage.goto("test-session");
await chatPage.sendMessage("login");
await page.evaluate(() => {
const mockMessages = [
{
type: "login_needed",
message:
"To run agents and save your chat history, please log in to your account.",
sessionId: "test-session",
timestamp: new Date(),
},
];
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
// Check for login prompt elements
const loginHeader = page.getByText("Login Required");
await expect(loginHeader).toBeVisible({ timeout: 5000 });
@@ -188,42 +204,60 @@ test.describe("Chat Messages - Login Prompt", () => {
test.describe("Chat Messages - Credentials Prompt", () => {
test("displays credentials prompt for OAuth", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const setupInfo = {
setup_info: {
agent_name: "GitHub Integration",
user_readiness: {
missing_credentials: {
github: {
provider: "github",
provider_name: "GitHub",
type: "oauth2",
scopes: [],
},
},
},
},
};
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-setup",
tool_name: "get_required_setup_info",
result: setupInfo,
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
const chatPage = new ChatPage(page);
await chatPage.goto();
await chatPage.goto("test-session");
await chatPage.sendMessage("run github agent");
await page.evaluate(() => {
const mockMessages = [
{
type: "credentials_needed",
provider: "github",
providerName: "GitHub",
credentialType: "oauth2",
title: "GitHub Integration",
message:
"To run the GitHub Integration agent, you need to add GitHub credentials.",
timestamp: new Date(),
},
];
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
// Check for credentials prompt elements
const credentialsHeader = page.getByText("Credentials Required");
await expect(credentialsHeader).toBeVisible({ timeout: 5000 });
@@ -239,23 +273,24 @@ test.describe("Chat Messages - Credentials Prompt", () => {
test.describe("Chat Messages - No Results Message", () => {
test("displays no results message with suggestions", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const result = {
type: "no_results",
message:
"No agents found matching 'crypto mining'. Try different keywords or browse the marketplace.",
@@ -264,18 +299,29 @@ test.describe("Chat Messages - No Results Message", () => {
"Browse categories in the marketplace",
"Check spelling",
],
timestamp: new Date(),
},
];
};
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-find",
tool_name: "find_agent",
result,
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
const chatPage = new ChatPage(page);
await chatPage.goto("test-session");
await chatPage.sendMessage("crypto mining");
// Check for no results elements
const noResultsHeader = page.getByText("No Results Found");
await expect(noResultsHeader).toBeVisible({ timeout: 5000 });
@@ -286,23 +332,24 @@ test.describe("Chat Messages - No Results Message", () => {
test.describe("Chat Messages - Agent Carousel Message", () => {
test("displays agent carousel with multiple agents", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const result = {
type: "agent_carousel",
agents: [
{
@@ -318,19 +365,30 @@ test.describe("Chat Messages - Agent Carousel Message", () => {
version: 2,
},
],
totalCount: 8,
timestamp: new Date(),
},
];
total_count: 8,
};
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-find",
tool_name: "find_agent",
result,
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
const chatPage = new ChatPage(page);
await chatPage.goto("test-session");
await chatPage.sendMessage("find agents");
// Check for agent carousel elements
const carouselHeader = page.getByText(/Found \d+ Agents/);
await expect(carouselHeader).toBeVisible({ timeout: 5000 });
@@ -344,39 +402,51 @@ test.describe("Chat Messages - Agent Carousel Message", () => {
test.describe("Chat Messages - Execution Started Message", () => {
test("displays execution started confirmation", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const result = {
type: "execution_started",
executionId: "exec-123e4567-e89b-12d3-a456-426614174000",
agentName: "Data Analysis Agent",
execution_id: "exec-123e4567-e89b-12d3-a456-426614174000",
agent_name: "Data Analysis Agent",
message: "Your agent execution has started successfully",
timestamp: new Date(),
},
];
};
const sse = [
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-run",
tool_name: "run_agent",
result,
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
const chatPage = new ChatPage(page);
await chatPage.goto("test-session");
await chatPage.sendMessage("run agent");
// Check for execution started elements
const executionHeader = page.getByText("Execution Started");
await expect(executionHeader).toBeVisible({ timeout: 5000 });
@@ -390,73 +460,86 @@ test.describe("Chat Messages - Execution Started Message", () => {
test.describe("Chat Messages - Mixed Conversation", () => {
test("displays multiple message types in sequence", async ({ page }) => {
await page.route("**/api/v1/chat/sessions/*", async (route) => {
await page.route("**/api/chat/sessions/test-session", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
session_id: "test-session",
id: "test-session",
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
user_id: null,
messages: [],
}),
});
});
const chatPage = new ChatPage(page);
await chatPage.goto();
await page.evaluate(() => {
const mockMessages = [
{
type: "message",
role: "user",
content: "Find automation agents",
timestamp: new Date(Date.now() - 5 * 60 * 1000),
},
{
type: "tool_call",
toolId: "tool-111",
toolName: "find_agent",
arguments: { query: "automation" },
timestamp: new Date(Date.now() - 4 * 60 * 1000),
},
{
type: "agent_carousel",
agents: [
{
id: "agent-1",
name: "Email Automation",
description: "Automates emails",
version: 1,
await page.route(
"**/api/chat/sessions/test-session/stream?**",
async (route) => {
const sse = [
// tool call
`data: ${JSON.stringify({
type: "tool_call",
tool_id: "tool-111",
tool_name: "find_agent",
arguments: { query: "automation" },
})}\n\n`,
// agent carousel
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-111",
tool_name: "find_agent",
result: {
type: "agent_carousel",
agents: [
{
id: "agent-1",
name: "Email Automation",
description: "Automates emails",
version: 1,
},
],
total_count: 5,
},
],
totalCount: 5,
timestamp: new Date(Date.now() - 3 * 60 * 1000),
},
{
type: "message",
role: "user",
content: "Run the first one",
timestamp: new Date(Date.now() - 2 * 60 * 1000),
},
{
type: "credentials_needed",
provider: "gmail",
providerName: "Gmail",
credentialType: "oauth2",
title: "Email Automation",
message: "You need Gmail credentials",
timestamp: new Date(Date.now() - 1 * 60 * 1000),
},
];
success: true,
})}\n\n`,
// credentials needed via setup info
`data: ${JSON.stringify({
type: "tool_response",
tool_id: "tool-setup",
tool_name: "get_required_setup_info",
result: {
setup_info: {
agent_name: "Email Automation",
user_readiness: {
missing_credentials: {
gmail: {
provider: "gmail",
provider_name: "Gmail",
type: "oauth2",
scopes: [],
},
},
},
},
},
success: true,
})}\n\n`,
`data: ${JSON.stringify({ type: "stream_end" })}\n\n`,
].join("");
await route.fulfill({
status: 200,
contentType: "text/event-stream",
body: sse,
});
},
);
window.dispatchEvent(
new CustomEvent("test:inject-messages", {
detail: { messages: mockMessages },
}),
);
});
const chatPage = new ChatPage(page);
await chatPage.goto("test-session");
await chatPage.sendMessage("Find automation agents");
// Verify multiple message types are present
const userMessage = page.getByText("Find automation agents");
await expect(userMessage).toBeVisible({ timeout: 5000 });

View File

@@ -3,8 +3,8 @@ import { Page, Locator } from "@playwright/test";
export class ChatPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto("/chat");
async goto(sessionId?: string) {
await this.page.goto(sessionId ? `/chat?session=${sessionId}` : "/chat");
}
// Selectors