Skip to content

Commit 970a557

Browse files
authored
Use e2e package for dojo testing on PRs (#295)
* Run e2e package instead of e2e2 for dojo * move to wait-on action * Adjust parallelization and reporting * remove bogus failure analysis * move to depot.dev 8 core runner * Annotate failing tests with fixme
1 parent fd99057 commit 970a557

File tree

49 files changed

+258
-236
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+258
-236
lines changed

.github/workflows/dojo-e2e.yml

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
jobs:
1010
e2e:
1111
name: E2E Tests
12-
runs-on: ubuntu-latest
12+
runs-on: depot-ubuntu-latest-8
1313

1414
steps:
1515
- name: Checkout code
@@ -52,10 +52,9 @@ jobs:
5252
run: node ./scripts/prep-dojo-everything.js -e2e
5353

5454
- name: Install e2e dependencies
55-
working-directory: typescript-sdk/apps/dojo/e2e2
55+
working-directory: typescript-sdk/apps/dojo/e2e
5656
run: |
57-
pnpm install --frozen-lockfile
58-
pnpm dlx playwright install --with-deps
57+
pnpm install
5958
6059
- name: write langgraph env files
6160
working-directory: typescript-sdk/integrations/langgraph
@@ -70,21 +69,38 @@ jobs:
7069
echo "OPENAI_API_KEY=${OPENAI_API_KEY}" > python/ag_ui_langgraph/.env
7170
echo "LANGSMITH_API_KEY=${LANGSMITH_API_KEY}" >> python/ag_ui_langgraph/.env
7271
73-
- name: Run dojo+agents and tests
74-
working-directory: typescript-sdk/apps/dojo/e2e2
72+
- name: Run dojo+agents
73+
uses: JarvusInnovations/background-action@v1
7574
env:
7675
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
7776
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
78-
run: |
79-
node ../scripts/run-dojo-everything.js &
80-
npx wait-port 9999
81-
sleep 10
82-
pnpm exec playwright test --reporter=dot
77+
with:
78+
run: |
79+
node ../scripts/run-dojo-everything.js
80+
working-directory: typescript-sdk/apps/dojo/e2e
81+
wait-on: |
82+
http://localhost:9999
83+
tcp:localhost:8000
84+
tcp:localhost:8001
85+
tcp:localhost:8002
86+
tcp:localhost:8003
87+
tcp:localhost:8004
88+
tcp:localhost:8005
89+
tcp:localhost:8006
90+
tcp:localhost:8007
91+
tcp:localhost:8008
92+
tcp:localhost:8009
93+
94+
- name: Run tests
95+
working-directory: typescript-sdk/apps/dojo/e2e
96+
env:
97+
BASE_URL: http://localhost:9999
98+
run: pnpm test
8399

84100
- name: Upload traces
85101
if: always() # Uploads artifacts even if tests fail
86102
uses: actions/upload-artifact@v4
87103
with:
88104
name: playwright-traces
89-
path: typescript-sdk/apps/dojo/e2e2/test-results/
105+
path: typescript-sdk/apps/dojo/e2e/test-results/
90106
retention-days: 7

typescript-sdk/apps/dojo/e2e/clean-reporter.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
function getTimestamp() {
2+
return (process.env.CI || process.env.VERBOSE)
3+
? new Date().toLocaleTimeString('en-US', { hour12: false })
4+
: '';
5+
}
6+
7+
function logStamp(...args) {
8+
console.log(getTimestamp(), ...args);
9+
}
10+
111
class CleanReporter {
212
onBegin(config, suite) {
313
console.log(`\n🎭 Running ${suite.allTests().length} tests...\n`);
@@ -15,9 +25,9 @@ class CleanReporter {
1525
.trim();
1626

1727
if (result.status === "passed") {
18-
console.log(`✅ ${cleanSuite}: ${testName}`);
28+
logStamp(`✅ ${cleanSuite}: ${testName}`);
1929
} else if (result.status === "failed") {
20-
console.log(`❌ ${cleanSuite}: ${testName}`);
30+
logStamp(`❌ ${cleanSuite}: ${testName}`);
2131

2232
// Extract the most relevant error info
2333
const error = result.error || result.errors?.[0];
@@ -60,15 +70,14 @@ class CleanReporter {
6070

6171
onEnd(result) {
6272
console.log("\n" + "=".repeat(60));
63-
console.log(`📊 TEST SUMMARY`);
73+
logStamp(`📊 TEST SUMMARY`);
6474
console.log("=".repeat(60));
6575

66-
console.log(`\n🔍 FAILURE ANALYSIS:`);
67-
console.log(`• Most failures appear to be AI service related`);
68-
console.log(`• Check API keys and service availability`);
69-
console.log(
70-
`• Run 'pnpm exec playwright show-report' for detailed HTML report`
71-
);
76+
if (!process.env.CI) {
77+
console.log(
78+
`• Run 'pnpm exec playwright show-report' for detailed HTML report`
79+
);
80+
}
7281

7382
console.log("=".repeat(60) + "\n");
7483
}

typescript-sdk/apps/dojo/e2e/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"private": true,
55
"description": "Scheduled Playwright smoke tests for CopilotKit demo apps",
66
"scripts": {
7+
"postinstall": "playwright install --with-deps",
78
"test": "playwright test",
89
"test:ui": "playwright test --ui"
910
},
Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,53 @@
1-
import { defineConfig } from "@playwright/test";
1+
import { defineConfig, ReporterDescription } from "@playwright/test";
22
import { generateSimpleLayout } from "./slack-layout-simple";
33

4+
5+
6+
function getReporters(): ReporterDescription[] {
7+
const videoReporter: ReporterDescription = [
8+
"./reporters/s3-video-reporter.ts",
9+
{
10+
outputFile: "test-results/video-urls.json",
11+
uploadVideos: true,
12+
},
13+
];
14+
const s3Reporter: ReporterDescription = [
15+
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
16+
{
17+
slackWebHookUrl: process.env.SLACK_WEBHOOK_URL,
18+
sendResults: "always", // always send results
19+
maxNumberOfFailuresToShow: 10,
20+
layout: generateSimpleLayout, // Use our simple layout
21+
},
22+
];
23+
const githubReporter: ReporterDescription = ["github"];
24+
const htmlReporter: ReporterDescription = ["html", { open: "never" }];
25+
const cleanReporter: ReporterDescription = ["./clean-reporter.js"];
26+
27+
const addVideoAndSlack = process.env.SLACK_WEBHOOK_URL && process.env.AWS_S3_BUCKET_NAME;
28+
29+
return [
30+
process.env.CI ? githubReporter : undefined,
31+
addVideoAndSlack ? videoReporter : undefined,
32+
addVideoAndSlack ? s3Reporter : undefined,
33+
htmlReporter,
34+
cleanReporter,
35+
].filter(Boolean) as ReporterDescription[];
36+
}
37+
38+
function getBaseUrl(): string {
39+
if (process.env.BASE_URL) {
40+
return new URL(process.env.BASE_URL).toString();
41+
}
42+
console.error("BASE_URL is not set");
43+
process.exit(1);
44+
}
45+
446
export default defineConfig({
547
timeout: process.env.CI ? 300_000 : 120_000, // 5min in CI, 2min locally for AI tests
6-
workers: 1, // Serial execution to avoid race conditions and AI service conflicts
748
testDir: "./tests",
8-
retries: process.env.CI ? 3 : 0, // More retries for flaky AI tests in CI, 0 for local
9-
fullyParallel: false, // Serial execution for deterministic AI test results
49+
retries: process.env.CI ? 1 : 0, // More retries for flaky AI tests in CI, 0 for local
50+
fullyParallel: true,
1051
use: {
1152
headless: true,
1253
viewport: { width: 1280, height: 720 },
@@ -20,6 +61,7 @@ export default defineConfig({
2061
actionTimeout: 60_000, // 1 minute for AI-driven actions (clicking, filling)
2162
// Test isolation - ensure clean state between tests
2263
testIdAttribute: "data-testid",
64+
baseURL: getBaseUrl(),
2365
},
2466
expect: {
2567
timeout: 90_000, // 1.5 minutes for AI-generated content to appear
@@ -38,53 +80,5 @@ export default defineConfig({
3880
},
3981
},
4082
],
41-
reporter: process.env.CI
42-
? [
43-
["github"],
44-
["html", { open: "never" }],
45-
// S3 video uploader (runs first to upload videos)
46-
[
47-
"./reporters/s3-video-reporter.ts",
48-
{
49-
outputFile: "test-results/video-urls.json",
50-
uploadVideos: true,
51-
},
52-
],
53-
// Slack notifications (runs after videos are uploaded)
54-
[
55-
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
56-
{
57-
slackWebHookUrl: process.env.SLACK_WEBHOOK_URL,
58-
sendResults: "always", // always send results
59-
maxNumberOfFailuresToShow: 10,
60-
layout: generateSimpleLayout, // Use our simple layout
61-
},
62-
],
63-
]
64-
: process.env.SLACK_WEBHOOK_URL && process.env.AWS_S3_BUCKET_NAME
65-
? [
66-
// Full local testing with S3 + Slack (when both are configured)
67-
[
68-
"./reporters/s3-video-reporter.ts",
69-
{
70-
outputFile: "test-results/video-urls.json",
71-
uploadVideos: true,
72-
},
73-
],
74-
[
75-
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
76-
{
77-
slackWebHookUrl: process.env.SLACK_WEBHOOK_URL,
78-
sendResults: "always",
79-
maxNumberOfFailuresToShow: 10,
80-
layout: generateSimpleLayout,
81-
},
82-
],
83-
["html", { open: "never" }],
84-
]
85-
: [
86-
// Standard local testing
87-
["./clean-reporter.js"],
88-
["html", { open: "never" }],
89-
],
83+
reporter: getReporters(),
9084
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
packages:
2+
- '.'

typescript-sdk/apps/dojo/e2e/tests/agnoTests/agenticChatPage.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ test("[Agno] Agentic Chat sends and receives a greeting message", async ({
1111
}) => {
1212
await retryOnAIFailure(async () => {
1313
await page.goto(
14-
"https://ag-ui-dojo-nine.vercel.app/agno/feature/agentic_chat"
14+
"/agno/feature/agentic_chat"
1515
);
1616

1717
const chat = new AgenticChatPage(page);
@@ -31,7 +31,7 @@ test("[Agno] Agentic Chat provides stock price information", async ({
3131
}) => {
3232
await retryOnAIFailure(async () => {
3333
await page.goto(
34-
"https://ag-ui-dojo-nine.vercel.app/agno/feature/agentic_chat"
34+
"/agno/feature/agentic_chat"
3535
);
3636

3737
const chat = new AgenticChatPage(page);
@@ -54,7 +54,7 @@ test("[Agno] Agentic Chat retains memory of previous questions", async ({
5454
}) => {
5555
await retryOnAIFailure(async () => {
5656
await page.goto(
57-
"https://ag-ui-dojo-nine.vercel.app/agno/feature/agentic_chat"
57+
"/agno/feature/agentic_chat"
5858
);
5959

6060
const chat = new AgenticChatPage(page);
@@ -72,7 +72,7 @@ test("[Agno] Agentic Chat retains memory of previous questions", async ({
7272
await chat.sendMessage("What was my first question");
7373
await chat.assertUserMessageVisible("What was my first question");
7474
await waitForAIResponse(page);
75-
75+
7676
// Check if the agent remembers the first question about AAPL stock price
7777
await chat.assertAgentReplyVisible(/Hi/i);
7878
});
@@ -83,7 +83,7 @@ test("[Agno] Agentic Chat retains memory of user messages during a conversation"
8383
}) => {
8484
await retryOnAIFailure(async () => {
8585
await page.goto(
86-
"https://ag-ui-dojo-nine.vercel.app/agno/feature/agentic_chat"
86+
"/agno/feature/agentic_chat"
8787
);
8888

8989
const chat = new AgenticChatPage(page);

typescript-sdk/apps/dojo/e2e/tests/agnoTests/toolBasedGenUIPage.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { test, expect } from "@playwright/test";
22
import { ToolBaseGenUIPage } from "../../pages/agnoPages/ToolBaseGenUIPage";
33

44
const pageURL =
5-
"https://ag-ui-dojo-nine.vercel.app/agno/feature/tool_based_generative_ui";
5+
"/agno/feature/tool_based_generative_ui";
66

7-
test('[Agno] Haiku generation and display verification', async ({
7+
test.fixme('[Agno] Haiku generation and display verification', async ({
88
page,
99
}) => {
1010
await page.goto(pageURL);
@@ -17,7 +17,7 @@ test('[Agno] Haiku generation and display verification', async ({
1717
await genAIAgent.checkHaikuDisplay(page);
1818
});
1919

20-
test('[Agno] Haiku generation and UI consistency for two different prompts', async ({
20+
test.fixme('[Agno] Haiku generation and UI consistency for two different prompts', async ({
2121
page,
2222
}) => {
2323
await page.goto(pageURL);

typescript-sdk/apps/dojo/e2e/tests/crewAITests/agenticChatPage.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ test("[CrewAI] Agentic Chat sends and receives a message", async ({
1111
}) => {
1212
await retryOnAIFailure(async () => {
1313
await page.goto(
14-
"https://ag-ui-dojo-nine.vercel.app/crewai/feature/agentic_chat"
14+
"/crewai/feature/agentic_chat"
1515
);
1616

1717
const chat = new AgenticChatPage(page);
@@ -26,12 +26,12 @@ test("[CrewAI] Agentic Chat sends and receives a message", async ({
2626
});
2727
});
2828

29-
test("[CrewAI] Agentic Chat changes background on message and reset", async ({
29+
test.fixme("[CrewAI] Agentic Chat changes background on message and reset", async ({
3030
page,
3131
}) => {
3232
await retryOnAIFailure(async () => {
3333
await page.goto(
34-
"https://ag-ui-dojo-nine.vercel.app/crewai/feature/agentic_chat"
34+
"/crewai/feature/agentic_chat"
3535
);
3636

3737
const chat = new AgenticChatPage(page);
@@ -42,7 +42,7 @@ test("[CrewAI] Agentic Chat changes background on message and reset", async ({
4242
// Store initial background color
4343
const initialBackground = await chat.getBackground();
4444
console.log("Initial background color:", initialBackground);
45-
45+
4646
// 1. Send message to change background to blue
4747
await chat.sendMessage("Hi change the background color to blue");
4848
await chat.assertUserMessageVisible(
@@ -79,7 +79,7 @@ test("[CrewAI] Agentic Chat retains memory of user messages during a conversatio
7979
}) => {
8080
await retryOnAIFailure(async () => {
8181
await page.goto(
82-
"https://ag-ui-dojo-nine.vercel.app/crewai/feature/agentic_chat"
82+
"/crewai/feature/agentic_chat"
8383
);
8484

8585
const chat = new AgenticChatPage(page);

0 commit comments

Comments
 (0)