Skip to content

Commit 1787adb

Browse files
committed
chore: fix flaky test
1 parent f68485e commit 1787adb

File tree

3 files changed

+5
-195
lines changed

3 files changed

+5
-195
lines changed
Lines changed: 1 addition & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,191 +1 @@
1-
import { Page, Locator, expect } from '@playwright/test';
2-
3-
export class SubgraphsPage {
4-
readonly page: Page;
5-
readonly travelPlannerButton: Locator;
6-
readonly chatInput: Locator;
7-
readonly sendButton: Locator;
8-
readonly agentGreeting: Locator;
9-
readonly agentMessage: Locator;
10-
readonly userMessage: Locator;
11-
12-
// Flight-related elements
13-
readonly flightOptions: Locator;
14-
readonly klmFlightOption: Locator;
15-
readonly unitedFlightOption: Locator;
16-
readonly flightSelectionInterface: Locator;
17-
18-
// Hotel-related elements
19-
readonly hotelOptions: Locator;
20-
readonly hotelZephyrOption: Locator;
21-
readonly ritzCarltonOption: Locator;
22-
readonly hotelZoeOption: Locator;
23-
readonly hotelSelectionInterface: Locator;
24-
25-
// Itinerary and state elements
26-
readonly itineraryDisplay: Locator;
27-
readonly selectedFlight: Locator;
28-
readonly selectedHotel: Locator;
29-
readonly experienceRecommendations: Locator;
30-
31-
// Subgraph activity indicators
32-
readonly activeAgent: Locator;
33-
readonly supervisorIndicator: Locator;
34-
readonly flightsAgentIndicator: Locator;
35-
readonly hotelsAgentIndicator: Locator;
36-
readonly experiencesAgentIndicator: Locator;
37-
38-
constructor(page: Page) {
39-
this.page = page;
40-
this.travelPlannerButton = page.getByRole('button', { name: /travel.*planner|subgraphs/i });
41-
this.agentGreeting = page.getByText(/travel.*planning|supervisor.*coordinate/i);
42-
this.chatInput = page.getByRole('textbox', { name: 'Type a message...' });
43-
this.sendButton = page.locator('[data-test-id="copilot-chat-ready"]');
44-
this.agentMessage = page.locator('.copilotKitAssistantMessage');
45-
this.userMessage = page.locator('.copilotKitUserMessage');
46-
47-
// Flight selection elements
48-
this.flightOptions = page.locator('[data-testid*="flight"], .flight-option');
49-
this.klmFlightOption = page.getByText(/KLM.*\$650.*11h 30m/);
50-
this.unitedFlightOption = page.getByText(/United.*\$720.*12h 15m/);
51-
this.flightSelectionInterface = page.locator('[data-testid*="flight-select"], .flight-selection');
52-
53-
// Hotel selection elements
54-
this.hotelOptions = page.locator('[data-testid*="hotel"], .hotel-option');
55-
this.hotelZephyrOption = page.getByText(/Hotel Zephyr.*Fisherman\'s Wharf.*\$280/);
56-
this.ritzCarltonOption = page.getByText(/Ritz-Carlton.*Nob Hill.*\$550/);
57-
this.hotelZoeOption = page.getByText(/Hotel Zoe.*Union Square.*\$320/);
58-
this.hotelSelectionInterface = page.locator('[data-testid*="hotel-select"], .hotel-selection');
59-
60-
// Itinerary elements
61-
this.itineraryDisplay = page.locator('[data-testid*="itinerary"], .itinerary');
62-
this.selectedFlight = page.locator('[data-testid*="selected-flight"], .selected-flight');
63-
this.selectedHotel = page.locator('[data-testid*="selected-hotel"], .selected-hotel');
64-
this.experienceRecommendations = page.locator('[data-testid*="experience"], .experience');
65-
66-
// Agent activity indicators
67-
this.activeAgent = page.locator('[data-testid*="active-agent"], .active-agent');
68-
this.supervisorIndicator = page.locator('[data-testid*="supervisor"], .supervisor-active');
69-
this.flightsAgentIndicator = page.locator('[data-testid*="flights-agent"], .flights-agent-active');
70-
this.hotelsAgentIndicator = page.locator('[data-testid*="hotels-agent"], .hotels-agent-active');
71-
this.experiencesAgentIndicator = page.locator('[data-testid*="experiences-agent"], .experiences-agent-active');
72-
}
73-
74-
async openChat() {
75-
await this.travelPlannerButton.click();
76-
}
77-
78-
async sendMessage(message: string) {
79-
await this.chatInput.click();
80-
await this.chatInput.fill(message);
81-
await this.sendButton.click();
82-
}
83-
84-
async selectFlight(airline: 'KLM' | 'United') {
85-
const flightOption = airline === 'KLM' ? this.klmFlightOption : this.unitedFlightOption;
86-
87-
// Wait for flight options to be presented
88-
await expect(this.flightOptions.first()).toBeVisible({ timeout: 15000 });
89-
90-
// Click on the desired flight option
91-
await flightOption.click();
92-
}
93-
94-
async selectHotel(hotel: 'Zephyr' | 'Ritz-Carlton' | 'Zoe') {
95-
let hotelOption: Locator;
96-
97-
switch (hotel) {
98-
case 'Zephyr':
99-
hotelOption = this.hotelZephyrOption;
100-
break;
101-
case 'Ritz-Carlton':
102-
hotelOption = this.ritzCarltonOption;
103-
break;
104-
case 'Zoe':
105-
hotelOption = this.hotelZoeOption;
106-
break;
107-
}
108-
109-
// Wait for hotel options to be presented
110-
await expect(this.hotelOptions.first()).toBeVisible({ timeout: 15000 });
111-
112-
// Click on the desired hotel option
113-
await hotelOption.click();
114-
}
115-
116-
async waitForFlightsAgent() {
117-
// Wait for flights agent to become active (or look for flight-related content)
118-
// Use .first() to handle multiple matches in strict mode
119-
await expect(
120-
this.page.getByText(/flight.*options|Amsterdam.*San Francisco|KLM|United/i).first()
121-
).toBeVisible({ timeout: 20000 });
122-
}
123-
124-
async waitForHotelsAgent() {
125-
// Wait for hotels agent to become active (or look for hotel-related content)
126-
// Use .first() to handle multiple matches in strict mode
127-
await expect(
128-
this.page.getByText(/hotel.*options|accommodation|Zephyr|Ritz-Carlton|Hotel Zoe/i).first()
129-
).toBeVisible({ timeout: 20000 });
130-
}
131-
132-
async waitForExperiencesAgent() {
133-
// Wait for experiences agent to become active (or look for experience-related content)
134-
// Use .first() to handle multiple matches in strict mode
135-
await expect(
136-
this.page.getByText(/experience|activities|restaurant|Pier 39|Golden Gate|Swan Oyster|Tartine/i).first()
137-
).toBeVisible({ timeout: 20000 });
138-
}
139-
140-
async verifyStaticFlightData() {
141-
// Verify the hardcoded flight options are present
142-
await expect(this.page.getByText(/KLM.*\$650.*11h 30m/).first()).toBeVisible();
143-
await expect(this.page.getByText(/United.*\$720.*12h 15m/).first()).toBeVisible();
144-
}
145-
146-
async verifyStaticHotelData() {
147-
// Verify the hardcoded hotel options are present
148-
await expect(this.page.getByText(/Hotel Zephyr.*\$280/).first()).toBeVisible();
149-
await expect(this.page.getByText(/Ritz-Carlton.*\$550/).first()).toBeVisible();
150-
await expect(this.page.getByText(/Hotel Zoe.*\$320/).first()).toBeVisible();
151-
}
152-
153-
async verifyStaticExperienceData() {
154-
// Verify the hardcoded experience options are mentioned
155-
const experienceText = this.page.getByText(/Pier 39|Golden Gate Bridge|Swan Oyster Depot|Tartine Bakery/i);
156-
await expect(experienceText.first()).toBeVisible();
157-
}
158-
159-
async verifyItineraryContainsFlight(airline: 'KLM' | 'United') {
160-
// Check that the selected flight appears in the itinerary or conversation
161-
await expect(this.page.getByText(new RegExp(airline, 'i'))).toBeVisible();
162-
}
163-
164-
async verifyItineraryContainsHotel(hotel: 'Zephyr' | 'Ritz-Carlton' | 'Zoe') {
165-
// Check that the selected hotel appears in the itinerary or conversation
166-
const hotelName = hotel === 'Ritz-Carlton' ? 'Ritz-Carlton' : `Hotel ${hotel}`;
167-
await expect(this.page.getByText(new RegExp(hotelName, 'i'))).toBeVisible();
168-
}
169-
170-
async assertAgentReplyVisible(expectedText: RegExp) {
171-
await expect(this.agentMessage.last().getByText(expectedText)).toBeVisible();
172-
}
173-
174-
async assertUserMessageVisible(message: string) {
175-
await expect(this.page.getByText(message)).toBeVisible();
176-
}
177-
178-
async waitForSupervisorCoordination() {
179-
// Wait for supervisor to appear in the conversation
180-
await expect(
181-
this.page.getByText(/supervisor|coordinate|specialist|routing/i).first()
182-
).toBeVisible({ timeout: 15000 });
183-
}
184-
185-
async waitForAgentCompletion() {
186-
// Wait for the travel planning process to complete
187-
await expect(
188-
this.page.getByText(/complete|finished|planning.*done|itinerary.*ready/i).first()
189-
).toBeVisible({ timeout: 30000 });
190-
}
191-
}
1+
export { SubgraphsPage } from '../langGraphPages/SubgraphsPage'

typescript-sdk/apps/dojo/e2e/tests/langgraphFastAPITests/subgraphsPage.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { SubgraphsPage } from "../../pages/langGraphPages/SubgraphsPage";
33

44
test.describe("Subgraphs Travel Agent Feature", () => {
55
test("[LangGraph] should complete full travel planning flow with feature validation", async ({
6-
page,
7-
}) => {
6+
page,
7+
}) => {
88
await retryOnAIFailure(async () => {
99
const subgraphsPage = new SubgraphsPage(page);
1010

@@ -81,7 +81,7 @@ test.describe("Subgraphs Travel Agent Feature", () => {
8181
await retryOnAIFailure(async () => {
8282
const subgraphsPage = new SubgraphsPage(page);
8383

84-
await page.goto("/langgraph-fastapi/feature/subgraphs");
84+
await page.goto("/langgraph/feature/subgraphs");
8585

8686
await subgraphsPage.openChat();
8787

typescript-sdk/apps/dojo/e2e/tests/langgraphTests/subgraphsPage.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,4 @@ test.describe("Subgraphs Travel Agent Feature", () => {
145145
await subgraphsPage.verifyStaticExperienceData(); // Experiences provided based on selections
146146
});
147147
});
148-
});
148+
});

0 commit comments

Comments
 (0)