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 : / t r a v e l .* p l a n n e r | s u b g r a p h s / i } ) ;
41- this . agentGreeting = page . getByText ( / t r a v e l .* p l a n n i n g | s u p e r v i s o r .* c o o r d i n a t e / 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 ( / K L M .* \$ 6 5 0 .* 1 1 h 3 0 m / ) ;
50- this . unitedFlightOption = page . getByText ( / U n i t e d .* \$ 7 2 0 .* 1 2 h 1 5 m / ) ;
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 ( / H o t e l Z e p h y r .* F i s h e r m a n \' s W h a r f .* \$ 2 8 0 / ) ;
56- this . ritzCarltonOption = page . getByText ( / R i t z - C a r l t o n .* N o b H i l l .* \$ 5 5 0 / ) ;
57- this . hotelZoeOption = page . getByText ( / H o t e l Z o e .* U n i o n S q u a r e .* \$ 3 2 0 / ) ;
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 ( / f l i g h t .* o p t i o n s | A m s t e r d a m .* S a n F r a n c i s c o | K L M | U n i t e d / 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 ( / h o t e l .* o p t i o n s | a c c o m m o d a t i o n | Z e p h y r | R i t z - C a r l t o n | H o t e l Z o e / 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 ( / e x p e r i e n c e | a c t i v i t i e s | r e s t a u r a n t | P i e r 3 9 | G o l d e n G a t e | S w a n O y s t e r | T a r t i n e / 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 ( / K L M .* \$ 6 5 0 .* 1 1 h 3 0 m / ) . first ( ) ) . toBeVisible ( ) ;
143- await expect ( this . page . getByText ( / U n i t e d .* \$ 7 2 0 .* 1 2 h 1 5 m / ) . first ( ) ) . toBeVisible ( ) ;
144- }
145-
146- async verifyStaticHotelData ( ) {
147- // Verify the hardcoded hotel options are present
148- await expect ( this . page . getByText ( / H o t e l Z e p h y r .* \$ 2 8 0 / ) . first ( ) ) . toBeVisible ( ) ;
149- await expect ( this . page . getByText ( / R i t z - C a r l t o n .* \$ 5 5 0 / ) . first ( ) ) . toBeVisible ( ) ;
150- await expect ( this . page . getByText ( / H o t e l Z o e .* \$ 3 2 0 / ) . first ( ) ) . toBeVisible ( ) ;
151- }
152-
153- async verifyStaticExperienceData ( ) {
154- // Verify the hardcoded experience options are mentioned
155- const experienceText = this . page . getByText ( / P i e r 3 9 | G o l d e n G a t e B r i d g e | S w a n O y s t e r D e p o t | T a r t i n e B a k e r y / 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 ( / s u p e r v i s o r | c o o r d i n a t e | s p e c i a l i s t | r o u t i n g / 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 ( / c o m p l e t e | f i n i s h e d | p l a n n i n g .* d o n e | i t i n e r a r y .* r e a d y / i) . first ( )
189- ) . toBeVisible ( { timeout : 30000 } ) ;
190- }
191- }
1+ export { SubgraphsPage } from '../langGraphPages/SubgraphsPage'
0 commit comments