Skip to content
Open
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
4 changes: 4 additions & 0 deletions .github/workflows/dojo-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ jobs:
test_path: tests/awsStrandsTests
services: ["dojo", "aws-strands"]
wait_on: http://localhost:9999,tcp:localhost:8017
- suite: aws-strands-typescript
test_path: tests/awsStrandsTypescriptTests
services: ["dojo", "aws-strands-typescript"]
wait_on: http://localhost:9999,tcp:localhost:8022
- suite: claude-agent-sdk-python
test_path: tests/claudeAgentSdkPythonTests
services: ["dojo", "claude-agent-sdk-python"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { test, expect } from "../../test-isolation-helper";
import * as path from "path";
import {
sendChatMessage,
awaitLLMResponseDone,
openChat,
} from "../../utils/copilot-actions";
import { CopilotSelectors } from "../../utils/copilot-selectors";

const TEST_IMAGE = path.join(
import.meta.dirname,
"../../fixtures/test-image.png",
);

test.describe("[Integration] AWS Strands (TS) - Agentic Chat Multimodal", () => {
test("should upload an image and receive a description", async ({ page }) => {
await page.goto("/aws-strands-typescript/feature/agentic_chat_multimodal");
await openChat(page);

const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles(TEST_IMAGE);

await sendChatMessage(page, "Tell me what do you see in this image");
await awaitLLMResponseDone(page);

const lastAssistant = CopilotSelectors.assistantMessages(page).last();
await expect(lastAssistant).toContainText(/image|visual|content/i, {
timeout: 10000,
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { test, expect } from "../../test-isolation-helper";
import { AgenticChatPage } from "../../featurePages/AgenticChatPage";

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

const chat = new AgenticChatPage(page);

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

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

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

const chat = new AgenticChatPage(page);

await chat.openChat();
await expect(chat.agentGreeting).toBeVisible();

const backgroundContainer = page.locator(
'[data-testid="background-container"]',
);
const getBackground = () =>
backgroundContainer.evaluate((el) => el.style.background);
const initialBackground = await getBackground();

await chat.sendMessage("Hi change the background color to blue");
await chat.assertUserMessageVisible("Hi change the background color to blue");

await expect.poll(getBackground).not.toBe(initialBackground);
const backgroundAfterBlue = await getBackground();

await chat.sendMessage("Hi change the background color to pink");
await chat.assertUserMessageVisible("Hi change the background color to pink");

await expect.poll(getBackground).not.toBe(backgroundAfterBlue);
});

test("[StrandsTS] Agentic Chat retains memory of user messages during a conversation", async ({
page,
}) => {
await page.goto("/aws-strands-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 chat.assertAgentReplyVisible(/Hello! How can I assist you today\?/);

const favFruit = "Mango";
await chat.sendMessage(`My favorite fruit is ${favFruit}`);
await chat.assertUserMessageVisible(`My favorite fruit is ${favFruit}`);
await chat.assertAgentReplyVisible(/Mango is a wonderful tropical fruit/);

await chat.sendMessage("and I love listening to Kaavish");
await chat.assertUserMessageVisible("and I love listening to Kaavish");
await chat.assertAgentReplyVisible(/Kaavish is a wonderful musical group/);

await chat.sendMessage("tell me an interesting fact about Moon");
await chat.assertUserMessageVisible("tell me an interesting fact about Moon");
await chat.assertAgentReplyVisible(
/The Moon is Earth's only natural satellite/,
);

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 chat.assertAgentReplyVisible(/Your favorite fruit is Mango!/);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { test, expect } from "../../test-isolation-helper";
import {
sendChatMessage,
awaitLLMResponseDone,
openChat,
} from "../../utils/copilot-actions";
import { CopilotSelectors } from "../../utils/copilot-selectors";

test.describe("[Integration] AWS Strands (TS) - Agentic Chat Reasoning", () => {
test("should show reasoning indicator and then the response", async ({
page,
}) => {
await page.goto("/aws-strands-typescript/feature/agentic_chat_reasoning");
await openChat(page);

await sendChatMessage(page, "What is the best car to buy?");
await awaitLLMResponseDone(page);

const reasoningIndicator = page.getByText(/Thought for/i);
await expect(reasoningIndicator).toBeVisible({ timeout: 10000 });

const lastAssistant = CopilotSelectors.assistantMessages(page).last();
await expect(lastAssistant).toContainText(
/Toyota|Honda|Mazda|recommendations|car|vehicle/i,
{ timeout: 10000 },
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { awaitLLMResponseDone } from "../../utils/copilot-actions";
import { test, expect } from "../../test-isolation-helper";
import { AgenticGenUIPage } from "../../pages/awsStrandsPages/AgenticUIGenPage";

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

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

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

await genUIAgent.sendMessage("give me a plan to make brownies");
await expect(genUIAgent.agentPlannerContainer).toBeVisible();
await genUIAgent.plan();
await awaitLLMResponseDone(page);
});

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

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

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

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

await expect(genUIAgent.agentPlannerContainer).toBeVisible();
await genUIAgent.plan();
await awaitLLMResponseDone(page);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test, expect } from "../../test-isolation-helper";

test("[StrandsTS] Backend Tool Rendering displays weather cards", async ({
page,
}) => {
test.setTimeout(30000);

await page.goto("/aws-strands-typescript/feature/backend_tool_rendering");

await expect(
page.getByRole("button", { name: "Weather in San Francisco" }),
).toBeVisible({
timeout: 5000,
});

await page.getByRole("button", { name: "Weather in San Francisco" }).click();

const weatherCard = page.getByTestId("weather-card");
const currentWeatherText = page.getByText("Current Weather");

try {
await expect(weatherCard).toBeVisible();
} catch {
await expect(currentWeatherText.first()).toBeVisible();
}

const hasHumidity = await page
.getByText("Humidity")
.isVisible()
.catch(() => false);
const hasWind = await page
.getByText("Wind")
.isVisible()
.catch(() => false);
const hasCityName = await page
.locator("h3")
.filter({ hasText: /San Francisco/i })
.isVisible()
.catch(() => false);

expect(hasHumidity || hasWind || hasCityName).toBeTruthy();

await page.getByRole("button", { name: "Weather in New York" }).click();
await page.waitForTimeout(2000);

const weatherElements = await page
.getByText(/Weather|Humidity|Wind|Temperature/i)
.count();
expect(weatherElements).toBeGreaterThan(0);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { test, expect } from "../../test-isolation-helper";
import { HumanInLoopPage } from "../../pages/awsStrandsPages/HumanInLoopPage";

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

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

await humanInLoop.openChat();

await humanInLoop.sendMessage("Hi");

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 expect(humanInLoop.plan).toBeVisible();

const itemText = "eggs";
await humanInLoop.uncheckItem(itemText);
await humanInLoop.performStepsAndAwait();

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

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

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

await humanInLoop.openChat();

await humanInLoop.sendMessage("Hi");
await humanInLoop.sendMessage(
"Plan a mission to Mars with the first step being Start The Planning",
);
await expect(humanInLoop.plan).toBeVisible();

const uncheckedItem = "Start The Planning";

await humanInLoop.uncheckItem(uncheckedItem);
await humanInLoop.performStepsAndAwait();

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

test.describe("Shared State Feature", () => {
test("[StrandsTS] should interact with the chat to get a recipe on prompt", async ({
page,
}) => {
const sharedStateAgent = new SharedStatePage(page);

await page.goto("/aws-strands-typescript/feature/shared_state");

await sharedStateAgent.openChat();
await sharedStateAgent.sendMessage(
'Please give me a pasta recipe of your choosing, but one of the ingredients should be "Pasta". Not a type of pasta, exactly the word "Pasta".',
);
await sharedStateAgent.loader();
await sharedStateAgent.awaitIngredientCard("Pasta");
await sharedStateAgent.getInstructionItems(
sharedStateAgent.instructionsContainer,
);
});

test("[StrandsTS] should share state between UI and chat", async ({
page,
}) => {
const sharedStateAgent = new SharedStatePage(page);

await page.goto("/aws-strands-typescript/feature/shared_state");

await sharedStateAgent.openChat();

await sharedStateAgent.addIngredient.click();

const newIngredientCard = page.locator(".ingredient-card").last();
await newIngredientCard.locator(".ingredient-name-input").fill("Potatoes");
await newIngredientCard.locator(".ingredient-amount-input").fill("12");

await page.waitForTimeout(1000);

await sharedStateAgent.sendMessage("Please list all of the ingredients");
await sharedStateAgent.loader();

await expect(
sharedStateAgent.agentMessage.getByText(/Potatoes/),
).toBeVisible();
await expect(sharedStateAgent.agentMessage.getByText(/12/)).toBeVisible();
await expect(
sharedStateAgent.agentMessage.getByText(/Carrots/),
).toBeVisible();
await expect(
sharedStateAgent.agentMessage.getByText(/All-Purpose Flour/),
).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { test, expect } from "../../test-isolation-helper";
import { ToolBaseGenUIPage } from "../../featurePages/ToolBaseGenUIPage";

const pageURL = "/aws-strands-typescript/feature/tool_based_generative_ui";

test("[StrandsTS] Haiku generation and display verification", async ({
page,
}) => {
await page.goto(pageURL);

const genAIAgent = new ToolBaseGenUIPage(page);

await expect(genAIAgent.haikuAgentIntro).toBeVisible();
await genAIAgent.generateHaiku('Generate Haiku for "I will always win"');
await genAIAgent.checkGeneratedHaiku();
await genAIAgent.checkHaikuDisplay(page);
});

test("[StrandsTS] Haiku generation and UI consistency for two different prompts", async ({
page,
}) => {
await page.goto(pageURL);

const genAIAgent = new ToolBaseGenUIPage(page);

await expect(genAIAgent.haikuAgentIntro).toBeVisible();

const prompt1 = 'Generate Haiku for "I will always win"';
await genAIAgent.generateHaiku(prompt1);
await genAIAgent.checkGeneratedHaiku();
await genAIAgent.checkHaikuDisplay(page);

const prompt2 = 'Generate Haiku for "The moon shines bright"';
await genAIAgent.generateHaiku(prompt2);
await genAIAgent.checkGeneratedHaiku();
await genAIAgent.checkHaikuDisplay(page);
});
Loading