Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .github/workflows/dojo-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ jobs:
test_path: tests/crewAITests
services: ["dojo","crew-ai"]
wait_on: http://localhost:9999,tcp:localhost:8003
- suite: langgraph
test_path: tests/langgraphTests
services: ["dojo","langgraph-platform-python","langgraph-platform-typescript"]
wait_on: http://localhost:9999,tcp:localhost:8005,tcp:localhost:8006
- suite: langgraph-python
test_path: tests/langgraphPythonTests
services: ["dojo","langgraph-platform-python"]
wait_on: http://localhost:9999,tcp:localhost:8005
- suite: langgraph-typescript
test_path: tests/langgraphTypescriptTests
services: ["dojo","langgraph-platform-typescript"]
wait_on: http://localhost:9999,tcp:localhost:8006
- suite: langgraph-fastapi
test_path: tests/langgraphFastAPITests
services: ["dojo","langgraph-fastapi"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {
test,
expect,
waitForAIResponse,
retryOnAIFailure,
} from "../../test-isolation-helper";
import { AgenticChatPage } from "../../featurePages/AgenticChatPage";

test("[LangGraph] Agentic Chat sends and receives a message", async ({
page,
}) => {
await retryOnAIFailure(async () => {
await page.goto(
"/langgraph-typescript/feature/agentic_chat"
);

const chat = new AgenticChatPage(page);

await chat.openChat();
await chat.agentGreeting.isVisible;
await chat.sendMessage("Hi, I am duaa");

await waitForAIResponse(page);
await chat.assertUserMessageVisible("Hi, I am duaa");
await chat.assertAgentReplyVisible(/Hello/i);
});
});

test("[LangGraph] Agentic Chat changes background on message and reset", async ({
page,
}) => {
await retryOnAIFailure(async () => {
await page.goto(
"/langgraph-typescript/feature/agentic_chat"
);

const chat = new AgenticChatPage(page);

await chat.openChat();
await chat.agentGreeting.waitFor({ state: "visible" });

// Store initial background color
const initialBackground = await chat.getBackground();
console.log("Initial background color:", initialBackground);

// 1. Send message to change background to blue
await chat.sendMessage("Hi change the background color to blue");
await chat.assertUserMessageVisible(
"Hi change the background color to blue"
);
await waitForAIResponse(page);

const backgroundBlue = await chat.getBackground();
expect(backgroundBlue).not.toBe(initialBackground);
// Check if background is blue (string color name or contains blue)
expect(backgroundBlue.toLowerCase()).toMatch(/blue|rgb\(.*,.*,.*\)|#[0-9a-f]{6}/);

// 2. Change to pink
await chat.sendMessage("Hi change the background color to pink");
await chat.assertUserMessageVisible(
"Hi change the background color to pink"
);
await waitForAIResponse(page);

const backgroundPink = await chat.getBackground();
expect(backgroundPink).not.toBe(backgroundBlue);
// Check if background is pink (string color name or contains pink)
expect(backgroundPink.toLowerCase()).toMatch(/pink|rgb\(.*,.*,.*\)|#[0-9a-f]{6}/);
});
});

test("[LangGraph] Agentic Chat retains memory of user messages during a conversation", async ({
page,
}) => {
await retryOnAIFailure(async () => {
await page.goto(
"/langgraph-typescript/feature/agentic_chat"
);

const chat = new AgenticChatPage(page);
await chat.openChat();
await chat.agentGreeting.click();

await chat.sendMessage("Hey there");
await chat.assertUserMessageVisible("Hey there");
await waitForAIResponse(page);
await chat.assertAgentReplyVisible(/how can I assist you/i);

const favFruit = "Mango";
await chat.sendMessage(`My favorite fruit is ${favFruit}`);
await chat.assertUserMessageVisible(`My favorite fruit is ${favFruit}`);
await waitForAIResponse(page);
await chat.assertAgentReplyVisible(new RegExp(favFruit, "i"));

await chat.sendMessage("and I love listening to Kaavish");
await chat.assertUserMessageVisible("and I love listening to Kaavish");
await waitForAIResponse(page);
await chat.assertAgentReplyVisible(/Kaavish/i);

await chat.sendMessage("tell me an interesting fact about Moon");
await chat.assertUserMessageVisible(
"tell me an interesting fact about Moon"
);
await waitForAIResponse(page);
await chat.assertAgentReplyVisible(/Moon/i);

await chat.sendMessage("Can you remind me what my favorite fruit is?");
await chat.assertUserMessageVisible(
"Can you remind me what my favorite fruit is?"
);
await waitForAIResponse(page);
await chat.assertAgentReplyVisible(new RegExp(favFruit, "i"));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { test, expect } from "@playwright/test";
import { AgenticGenUIPage } from "../../pages/langGraphPages/AgenticUIGenPage";

test.describe("Agent Generative UI Feature", () => {
test("[LangGraph] should interact with the chat to get a planner on prompt", async ({
page,
}) => {
const genUIAgent = new AgenticGenUIPage(page);

await page.goto(
"/langgraph-typescript/feature/agentic_generative_ui"
);

await genUIAgent.openChat();
await genUIAgent.sendMessage("Hi");
await genUIAgent.sendButton.click();
await genUIAgent.assertAgentReplyVisible(/Hello/);

await genUIAgent.sendMessage("Give me a plan to make brownies");
await genUIAgent.sendButton.click();

await expect(genUIAgent.agentPlannerContainer).toBeVisible({ timeout: 15000 });

await genUIAgent.plan();

await page.waitForFunction(
() => {
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
const lastMessage = messages[messages.length - 1];
const content = lastMessage?.textContent?.trim() || '';

return messages.length >= 3 && content.length > 0;
},
{ timeout: 30000 }
);
});

test("[LangGraph] should interact with the chat using predefined prompts and perform steps", async ({
page,
}) => {
const genUIAgent = new AgenticGenUIPage(page);

await page.goto(
"/langgraph-typescript/feature/agentic_generative_ui"
);

await genUIAgent.openChat();
await genUIAgent.sendMessage("Hi");
await genUIAgent.sendButton.click();
await genUIAgent.assertAgentReplyVisible(/Hello/);

await genUIAgent.sendMessage("Go to Mars");
await genUIAgent.sendButton.click();

await expect(genUIAgent.agentPlannerContainer).toBeVisible({ timeout: 15000 });
await genUIAgent.plan();

await page.waitForFunction(
() => {
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
const lastMessage = messages[messages.length - 1];
const content = lastMessage?.textContent?.trim() || '';

return messages.length >= 3 && content.length > 0;
},
{ timeout: 30000 }
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { test, expect, waitForAIResponse, retryOnAIFailure } from "../../test-isolation-helper";
import { HumanInLoopPage } from "../../pages/langGraphPages/HumanInLoopPage";

test.describe("Human in the Loop Feature", () => {
test("[LangGraph] should interact with the chat and perform steps", async ({
page,
}) => {
await retryOnAIFailure(async () => {
const humanInLoop = new HumanInLoopPage(page);

await page.goto(
"/langgraph-typescript/feature/human_in_the_loop"
);

await humanInLoop.openChat();

await humanInLoop.sendMessage("Hi");
await humanInLoop.agentGreeting.isVisible();

await humanInLoop.sendMessage(
"Give me a plan to make brownies, there should be only one step with eggs and one step with oven, this is a strict requirement so adhere"
);
await waitForAIResponse(page);
await expect(humanInLoop.plan).toBeVisible({ timeout: 10000 });

const itemText = "eggs";
await page.waitForTimeout(5000);
await humanInLoop.uncheckItem(itemText);
await humanInLoop.performSteps();
await page.waitForFunction(
() => {
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
const lastMessage = messages[messages.length - 1];
const content = lastMessage?.textContent?.trim() || '';

return messages.length >= 3 && content.length > 0;
},
{ timeout: 30000 }
);

await humanInLoop.sendMessage(
`Does the planner include ${itemText}? ⚠️ Reply with only words 'Yes' or 'No' (no explanation, no punctuation).`
);
await waitForAIResponse(page);
});
});

test("should interact with the chat using predefined prompts and perform steps", async ({
page,
}) => {
await retryOnAIFailure(async () => {
const humanInLoop = new HumanInLoopPage(page);
await page.goto(
"/langgraph-typescript/feature/human_in_the_loop"
);

await humanInLoop.openChat();

await humanInLoop.sendMessage("Hi");
await humanInLoop.agentGreeting.isVisible();

await humanInLoop.sendMessage(
"Plan a mission to Mars with the first step being Start The Planning"
);
await waitForAIResponse(page);
await expect(humanInLoop.plan).toBeVisible({ timeout: 10000 });

const uncheckedItem = "Start The Planning";

await page.waitForTimeout(5000);
await humanInLoop.uncheckItem(uncheckedItem);
await humanInLoop.performSteps();

await page.waitForFunction(
() => {
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
const lastMessage = messages[messages.length - 1];
const content = lastMessage?.textContent?.trim() || '';

return messages.length >= 3 && content.length > 0;
},
{ timeout: 30000 }
);

await humanInLoop.sendMessage(
`Does the planner include ${uncheckedItem}? ⚠️ Reply with only words 'Yes' or 'No' (no explanation, no punctuation).`
);
await waitForAIResponse(page);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
test,
expect,
retryOnAIFailure,
} from "../../test-isolation-helper";
import { PredictiveStateUpdatesPage } from "../../pages/langGraphPages/PredictiveStateUpdatesPage";

test.fixme("Predictive Status Updates Feature", () => {
test("[LangGraph] should interact with agent and approve asked changes", async ({
page,
}) => {
await retryOnAIFailure(async () => {
const predictiveStateUpdates = new PredictiveStateUpdatesPage(page);

await page.goto(
"/langgraph-typescript/feature/predictive_state_updates"
);

await predictiveStateUpdates.openChat();
await page.waitForTimeout(2000);

await predictiveStateUpdates.sendMessage(
"Give me a story for a dragon called Atlantis in document"
);
await page.waitForTimeout(2000);

await predictiveStateUpdates.getPredictiveResponse();
await predictiveStateUpdates.getUserApproval();
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
const dragonName = await predictiveStateUpdates.verifyAgentResponse(
"Atlantis"
);
expect(dragonName).not.toBeNull();

await page.waitForTimeout(3000);

await predictiveStateUpdates.sendMessage("Change dragon name to Lola");
await page.waitForTimeout(2000);

await predictiveStateUpdates.verifyHighlightedText();
await predictiveStateUpdates.getUserApproval();
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
const dragonNameNew = await predictiveStateUpdates.verifyAgentResponse(
"Lola"
);
expect(dragonNameNew).not.toBe(dragonName);
});
});

test.fixme("[LangGraph] should interact with agent and reject asked changes", async ({
page,
}) => {
await retryOnAIFailure(async () => {
const predictiveStateUpdates = new PredictiveStateUpdatesPage(page);

await page.goto(
"/langgraph-typescript/feature/predictive_state_updates"
);

await predictiveStateUpdates.openChat();
await page.waitForTimeout(2000);

await predictiveStateUpdates.sendMessage(
"Give me a story for a dragon called Atlantis in document"
);
await page.waitForTimeout(2000);

await predictiveStateUpdates.getPredictiveResponse();
await predictiveStateUpdates.getUserApproval();
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
const dragonName = await predictiveStateUpdates.verifyAgentResponse(
"Atlantis"
);
expect(dragonName).not.toBeNull();

await page.waitForTimeout(3000);

await predictiveStateUpdates.sendMessage("Change dragon name to Lola");
await page.waitForTimeout(2000);

await predictiveStateUpdates.verifyHighlightedText();
await predictiveStateUpdates.getUserRejection();
await predictiveStateUpdates.rejectedChangesResponse.isVisible();
const dragonNameAfterRejection = await predictiveStateUpdates.verifyAgentResponse(
"Atlantis"
);
expect(dragonNameAfterRejection).toBe(dragonName);
expect(dragonNameAfterRejection).not.toBe("Lola");
});
});
});
Loading
Loading