Skip to content

Commit 9f15f76

Browse files
committed
tests(dojo): break out langgraph platform tests into typescript and python
Signed-off-by: Tyler Slaton <[email protected]>
1 parent 9a49a4e commit 9f15f76

15 files changed

+615
-4
lines changed

.github/workflows/dojo-e2e.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ jobs:
2626
test_path: tests/crewAITests
2727
services: ["dojo","crew-ai"]
2828
wait_on: http://localhost:9999,tcp:localhost:8003
29-
- suite: langgraph
30-
test_path: tests/langgraphTests
31-
services: ["dojo","langgraph-platform-python","langgraph-platform-typescript"]
32-
wait_on: http://localhost:9999,tcp:localhost:8005,tcp:localhost:8006
29+
- suite: langgraph-python
30+
test_path: tests/langgraphPythonTests
31+
services: ["dojo","langgraph-platform-python"]
32+
wait_on: http://localhost:9999,tcp:localhost:8005
33+
- suite: langgraph-typescript
34+
test_path: tests/langgraphTypescriptTests
35+
services: ["dojo","langgraph-platform-typescript"]
36+
wait_on: http://localhost:9999,tcp:localhost:8006
3337
- suite: langgraph-fastapi
3438
test_path: tests/langgraphFastAPITests
3539
services: ["dojo","langgraph-fastapi"]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import {
2+
test,
3+
expect,
4+
waitForAIResponse,
5+
retryOnAIFailure,
6+
} from "../../test-isolation-helper";
7+
import { AgenticChatPage } from "../../featurePages/AgenticChatPage";
8+
9+
test("[LangGraph] Agentic Chat sends and receives a message", async ({
10+
page,
11+
}) => {
12+
await retryOnAIFailure(async () => {
13+
await page.goto(
14+
"/langgraph-typescript/feature/agentic_chat"
15+
);
16+
17+
const chat = new AgenticChatPage(page);
18+
19+
await chat.openChat();
20+
await chat.agentGreeting.isVisible;
21+
await chat.sendMessage("Hi, I am duaa");
22+
23+
await waitForAIResponse(page);
24+
await chat.assertUserMessageVisible("Hi, I am duaa");
25+
await chat.assertAgentReplyVisible(/Hello/i);
26+
});
27+
});
28+
29+
test("[LangGraph] Agentic Chat changes background on message and reset", async ({
30+
page,
31+
}) => {
32+
await retryOnAIFailure(async () => {
33+
await page.goto(
34+
"/langgraph-typescript/feature/agentic_chat"
35+
);
36+
37+
const chat = new AgenticChatPage(page);
38+
39+
await chat.openChat();
40+
await chat.agentGreeting.waitFor({ state: "visible" });
41+
42+
// Store initial background color
43+
const initialBackground = await chat.getBackground();
44+
console.log("Initial background color:", initialBackground);
45+
46+
// 1. Send message to change background to blue
47+
await chat.sendMessage("Hi change the background color to blue");
48+
await chat.assertUserMessageVisible(
49+
"Hi change the background color to blue"
50+
);
51+
await waitForAIResponse(page);
52+
53+
const backgroundBlue = await chat.getBackground();
54+
expect(backgroundBlue).not.toBe(initialBackground);
55+
// Check if background is blue (string color name or contains blue)
56+
expect(backgroundBlue.toLowerCase()).toMatch(/blue|rgb\(.*,.*,.*\)|#[0-9a-f]{6}/);
57+
58+
// 2. Change to pink
59+
await chat.sendMessage("Hi change the background color to pink");
60+
await chat.assertUserMessageVisible(
61+
"Hi change the background color to pink"
62+
);
63+
await waitForAIResponse(page);
64+
65+
const backgroundPink = await chat.getBackground();
66+
expect(backgroundPink).not.toBe(backgroundBlue);
67+
// Check if background is pink (string color name or contains pink)
68+
expect(backgroundPink.toLowerCase()).toMatch(/pink|rgb\(.*,.*,.*\)|#[0-9a-f]{6}/);
69+
});
70+
});
71+
72+
test("[LangGraph] Agentic Chat retains memory of user messages during a conversation", async ({
73+
page,
74+
}) => {
75+
await retryOnAIFailure(async () => {
76+
await page.goto(
77+
"/langgraph-typescript/feature/agentic_chat"
78+
);
79+
80+
const chat = new AgenticChatPage(page);
81+
await chat.openChat();
82+
await chat.agentGreeting.click();
83+
84+
await chat.sendMessage("Hey there");
85+
await chat.assertUserMessageVisible("Hey there");
86+
await waitForAIResponse(page);
87+
await chat.assertAgentReplyVisible(/how can I assist you/i);
88+
89+
const favFruit = "Mango";
90+
await chat.sendMessage(`My favorite fruit is ${favFruit}`);
91+
await chat.assertUserMessageVisible(`My favorite fruit is ${favFruit}`);
92+
await waitForAIResponse(page);
93+
await chat.assertAgentReplyVisible(new RegExp(favFruit, "i"));
94+
95+
await chat.sendMessage("and I love listening to Kaavish");
96+
await chat.assertUserMessageVisible("and I love listening to Kaavish");
97+
await waitForAIResponse(page);
98+
await chat.assertAgentReplyVisible(/Kaavish/i);
99+
100+
await chat.sendMessage("tell me an interesting fact about Moon");
101+
await chat.assertUserMessageVisible(
102+
"tell me an interesting fact about Moon"
103+
);
104+
await waitForAIResponse(page);
105+
await chat.assertAgentReplyVisible(/Moon/i);
106+
107+
await chat.sendMessage("Can you remind me what my favorite fruit is?");
108+
await chat.assertUserMessageVisible(
109+
"Can you remind me what my favorite fruit is?"
110+
);
111+
await waitForAIResponse(page);
112+
await chat.assertAgentReplyVisible(new RegExp(favFruit, "i"));
113+
});
114+
});
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { test, expect } from "@playwright/test";
2+
import { AgenticGenUIPage } from "../../pages/langGraphPages/AgenticUIGenPage";
3+
4+
test.describe("Agent Generative UI Feature", () => {
5+
test("[LangGraph] should interact with the chat to get a planner on prompt", async ({
6+
page,
7+
}) => {
8+
const genUIAgent = new AgenticGenUIPage(page);
9+
10+
await page.goto(
11+
"/langgraph-typescript/feature/agentic_generative_ui"
12+
);
13+
14+
await genUIAgent.openChat();
15+
await genUIAgent.sendMessage("Hi");
16+
await genUIAgent.sendButton.click();
17+
await genUIAgent.assertAgentReplyVisible(/Hello/);
18+
19+
await genUIAgent.sendMessage("Give me a plan to make brownies");
20+
await genUIAgent.sendButton.click();
21+
22+
await expect(genUIAgent.agentPlannerContainer).toBeVisible({ timeout: 15000 });
23+
24+
await genUIAgent.plan();
25+
26+
await page.waitForFunction(
27+
() => {
28+
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
29+
const lastMessage = messages[messages.length - 1];
30+
const content = lastMessage?.textContent?.trim() || '';
31+
32+
return messages.length >= 3 && content.length > 0;
33+
},
34+
{ timeout: 30000 }
35+
);
36+
});
37+
38+
test("[LangGraph] should interact with the chat using predefined prompts and perform steps", async ({
39+
page,
40+
}) => {
41+
const genUIAgent = new AgenticGenUIPage(page);
42+
43+
await page.goto(
44+
"/langgraph-typescript/feature/agentic_generative_ui"
45+
);
46+
47+
await genUIAgent.openChat();
48+
await genUIAgent.sendMessage("Hi");
49+
await genUIAgent.sendButton.click();
50+
await genUIAgent.assertAgentReplyVisible(/Hello/);
51+
52+
await genUIAgent.sendMessage("Go to Mars");
53+
await genUIAgent.sendButton.click();
54+
55+
await expect(genUIAgent.agentPlannerContainer).toBeVisible({ timeout: 15000 });
56+
await genUIAgent.plan();
57+
58+
await page.waitForFunction(
59+
() => {
60+
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
61+
const lastMessage = messages[messages.length - 1];
62+
const content = lastMessage?.textContent?.trim() || '';
63+
64+
return messages.length >= 3 && content.length > 0;
65+
},
66+
{ timeout: 30000 }
67+
);
68+
});
69+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { test, expect, waitForAIResponse, retryOnAIFailure } from "../../test-isolation-helper";
2+
import { HumanInLoopPage } from "../../pages/langGraphPages/HumanInLoopPage";
3+
4+
test.describe("Human in the Loop Feature", () => {
5+
test("[LangGraph] should interact with the chat and perform steps", async ({
6+
page,
7+
}) => {
8+
await retryOnAIFailure(async () => {
9+
const humanInLoop = new HumanInLoopPage(page);
10+
11+
await page.goto(
12+
"/langgraph-typescript/feature/human_in_the_loop"
13+
);
14+
15+
await humanInLoop.openChat();
16+
17+
await humanInLoop.sendMessage("Hi");
18+
await humanInLoop.agentGreeting.isVisible();
19+
20+
await humanInLoop.sendMessage(
21+
"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"
22+
);
23+
await waitForAIResponse(page);
24+
await expect(humanInLoop.plan).toBeVisible({ timeout: 10000 });
25+
26+
const itemText = "eggs";
27+
await page.waitForTimeout(5000);
28+
await humanInLoop.uncheckItem(itemText);
29+
await humanInLoop.performSteps();
30+
await page.waitForFunction(
31+
() => {
32+
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
33+
const lastMessage = messages[messages.length - 1];
34+
const content = lastMessage?.textContent?.trim() || '';
35+
36+
return messages.length >= 3 && content.length > 0;
37+
},
38+
{ timeout: 30000 }
39+
);
40+
41+
await humanInLoop.sendMessage(
42+
`Does the planner include ${itemText}? ⚠️ Reply with only words 'Yes' or 'No' (no explanation, no punctuation).`
43+
);
44+
await waitForAIResponse(page);
45+
});
46+
});
47+
48+
test("should interact with the chat using predefined prompts and perform steps", async ({
49+
page,
50+
}) => {
51+
await retryOnAIFailure(async () => {
52+
const humanInLoop = new HumanInLoopPage(page);
53+
await page.goto(
54+
"/langgraph-typescript/feature/human_in_the_loop"
55+
);
56+
57+
await humanInLoop.openChat();
58+
59+
await humanInLoop.sendMessage("Hi");
60+
await humanInLoop.agentGreeting.isVisible();
61+
62+
await humanInLoop.sendMessage(
63+
"Plan a mission to Mars with the first step being Start The Planning"
64+
);
65+
await waitForAIResponse(page);
66+
await expect(humanInLoop.plan).toBeVisible({ timeout: 10000 });
67+
68+
const uncheckedItem = "Start The Planning";
69+
70+
await page.waitForTimeout(5000);
71+
await humanInLoop.uncheckItem(uncheckedItem);
72+
await humanInLoop.performSteps();
73+
74+
await page.waitForFunction(
75+
() => {
76+
const messages = Array.from(document.querySelectorAll('.copilotKitAssistantMessage'));
77+
const lastMessage = messages[messages.length - 1];
78+
const content = lastMessage?.textContent?.trim() || '';
79+
80+
return messages.length >= 3 && content.length > 0;
81+
},
82+
{ timeout: 30000 }
83+
);
84+
85+
await humanInLoop.sendMessage(
86+
`Does the planner include ${uncheckedItem}? ⚠️ Reply with only words 'Yes' or 'No' (no explanation, no punctuation).`
87+
);
88+
await waitForAIResponse(page);
89+
});
90+
});
91+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import {
2+
test,
3+
expect,
4+
retryOnAIFailure,
5+
} from "../../test-isolation-helper";
6+
import { PredictiveStateUpdatesPage } from "../../pages/langGraphPages/PredictiveStateUpdatesPage";
7+
8+
test.describe("Predictive Status Updates Feature", () => {
9+
test("[LangGraph] should interact with agent and approve asked changes", async ({
10+
page,
11+
}) => {
12+
await retryOnAIFailure(async () => {
13+
const predictiveStateUpdates = new PredictiveStateUpdatesPage(page);
14+
15+
await page.goto(
16+
"/langgraph-typescript/feature/predictive_state_updates"
17+
);
18+
19+
await predictiveStateUpdates.openChat();
20+
await page.waitForTimeout(2000);
21+
22+
await predictiveStateUpdates.sendMessage(
23+
"Give me a story for a dragon called Atlantis in document"
24+
);
25+
await page.waitForTimeout(2000);
26+
27+
await predictiveStateUpdates.getPredictiveResponse();
28+
await predictiveStateUpdates.getUserApproval();
29+
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
30+
const dragonName = await predictiveStateUpdates.verifyAgentResponse(
31+
"Atlantis"
32+
);
33+
expect(dragonName).not.toBeNull();
34+
35+
await page.waitForTimeout(3000);
36+
37+
await predictiveStateUpdates.sendMessage("Change dragon name to Lola");
38+
await page.waitForTimeout(2000);
39+
40+
await predictiveStateUpdates.verifyHighlightedText();
41+
await predictiveStateUpdates.getUserApproval();
42+
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
43+
const dragonNameNew = await predictiveStateUpdates.verifyAgentResponse(
44+
"Lola"
45+
);
46+
expect(dragonNameNew).not.toBe(dragonName);
47+
});
48+
});
49+
50+
test("[LangGraph] should interact with agent and reject asked changes", async ({
51+
page,
52+
}) => {
53+
await retryOnAIFailure(async () => {
54+
const predictiveStateUpdates = new PredictiveStateUpdatesPage(page);
55+
56+
await page.goto(
57+
"/langgraph-typescript/feature/predictive_state_updates"
58+
);
59+
60+
await predictiveStateUpdates.openChat();
61+
await page.waitForTimeout(2000);
62+
63+
await predictiveStateUpdates.sendMessage(
64+
"Give me a story for a dragon called Atlantis in document"
65+
);
66+
await page.waitForTimeout(2000);
67+
68+
await predictiveStateUpdates.getPredictiveResponse();
69+
await predictiveStateUpdates.getUserApproval();
70+
await predictiveStateUpdates.confirmedChangesResponse.isVisible();
71+
const dragonName = await predictiveStateUpdates.verifyAgentResponse(
72+
"Atlantis"
73+
);
74+
expect(dragonName).not.toBeNull();
75+
76+
await page.waitForTimeout(3000);
77+
78+
await predictiveStateUpdates.sendMessage("Change dragon name to Lola");
79+
await page.waitForTimeout(2000);
80+
81+
await predictiveStateUpdates.verifyHighlightedText();
82+
await predictiveStateUpdates.getUserRejection();
83+
await predictiveStateUpdates.rejectedChangesResponse.isVisible();
84+
const dragonNameAfterRejection = await predictiveStateUpdates.verifyAgentResponse(
85+
"Atlantis"
86+
);
87+
expect(dragonNameAfterRejection).toBe(dragonName);
88+
expect(dragonNameAfterRejection).not.toBe("Lola");
89+
});
90+
});
91+
});

0 commit comments

Comments
 (0)