@@ -97,279 +97,6 @@ define(function (require, exports, module) {
9797 // Note: We can't easily reset login state, so tests should handle this
9898 } ) ;
9999
100- describe ( "Browser Login Flow" , function ( ) {
101-
102- it ( "should complete browser login flow successfully" , async function ( ) {
103- // Ensure user starts logged out
104- const initialLoginState = LoginServiceExports . LoginService . isLoggedIn ( ) ;
105- if ( initialLoginState ) {
106- throw new Error ( "Login browser tests require user to be logged out. Please log out before running these tests." ) ;
107- }
108- expect ( initialLoginState ) . toBe ( false ) ;
109-
110- // Step 1: Click profile icon to open login popup
111- const $profileButton = testWindow . $ ( "#user-profile-button" ) ;
112- expect ( $profileButton . length ) . toBe ( 1 ) ;
113-
114- // Debug: Check if the button is visible and clickable
115- expect ( $profileButton . is ( ':visible' ) ) . toBe ( true ) ;
116-
117- // Try jQuery trigger first
118- $profileButton . trigger ( 'click' ) ;
119-
120- // Step 2: Wait for login popup to appear (check both modal and profile-popup)
121- await awaitsFor (
122- function ( ) {
123- return testWindow . $ ( '.modal' ) . length > 0 || testWindow . $ ( '.profile-popup' ) . length > 0 ;
124- } ,
125- "Login popup to appear" ,
126- 3000
127- ) ;
128-
129- // Get the popup content (could be modal or profile-popup)
130- let popupContent = testWindow . $ ( '.modal' ) ;
131- if ( popupContent . length === 0 ) {
132- popupContent = testWindow . $ ( '.profile-popup' ) ;
133- }
134- expect ( testWindow . $ ( '.profile-popup' ) . is ( ':visible' ) ) . toBe ( true ) ;
135-
136- // Verify it's the login popup (contains sign in button)
137- const signInButton = popupContent . find ( '#phoenix-signin-btn' ) ;
138- expect ( signInButton . length ) . toBe ( 1 ) ;
139- expect ( signInButton . text ( ) . trim ( ) . toLocaleLowerCase ( ) ) . toContain ( 'sign in' ) ;
140-
141- // Step 3: Mock successful login response FIRST (using login-browser test exports)
142- console . log ( "llgT: Setting up fetch mock EARLY using login-browser exports" ) ;
143- console . log ( "llgT: LoginBrowserExports.setFetchFn available?" , ! ! LoginBrowserExports . setFetchFn ) ;
144-
145- // Track sign out state for proper mock responses
146- let userSignedOut = false ;
147-
148- LoginBrowserExports . setFetchFn ( ( url , options ) => {
149- console . log ( "llgT: login-browser fetchFn called with URL:" , url ) ;
150- console . log ( "llgT: login-browser fetchFn called with options:" , options ) ;
151-
152- // Handle different endpoints
153- if ( url . includes ( '/resolveBrowserSession' ) ) {
154- // Login verification endpoint
155- if ( userSignedOut ) {
156- console . log ( "llgT: User is signed out, returning 401 for resolveBrowserSession" ) ;
157- return Promise . resolve ( {
158- ok : false ,
159- status : 401 , // Unauthorized - user is logged out
160- json : ( ) => Promise . resolve ( {
161- isSuccess : false
162- } )
163- } ) ;
164- } else {
165- console . log ( "llgT: User is signed in, returning success for resolveBrowserSession" ) ;
166- return Promise . resolve ( {
167- ok : true ,
168- status : 200 ,
169- json : ( ) => Promise . resolve ( {
170- isSuccess : true ,
171- 172- firstName : "Test" ,
173- lastName : "User" ,
174- customerID : "test-customer-id" ,
175- loginTime : Date . now ( ) ,
176- profileIcon : {
177- initials : "TU" ,
178- color : "#14b8a6"
179- }
180- } )
181- } ) ;
182- }
183- } else if ( url . includes ( '/signOut' ) ) {
184- // Logout endpoint - set signed out state
185- console . log ( "llgT: Handling signOut endpoint call, marking user as signed out" ) ;
186- userSignedOut = true ;
187- return Promise . resolve ( {
188- ok : true ,
189- status : 200 ,
190- json : ( ) => Promise . resolve ( {
191- isSuccess : true
192- } )
193- } ) ;
194- } else {
195- // Default response for any other endpoints
196- console . log ( "llgT: Unknown endpoint, returning default response" ) ;
197- return Promise . resolve ( {
198- ok : true ,
199- status : 200 ,
200- json : ( ) => Promise . resolve ( {
201- isSuccess : true
202- } )
203- } ) ;
204- }
205- } ) ;
206- console . log ( "llgT: login-browser fetch mock set up successfully for all endpoints" ) ;
207-
208- // Step 4: Mock window.open to capture account URL opening
209- let capturedURL = null ;
210- let capturedTarget = null ;
211- testWindow . open = function ( url , target ) {
212- capturedURL = url ;
213- capturedTarget = target ;
214- // Return a mock window object with focus method
215- return {
216- focus : function ( ) { } ,
217- close : function ( ) { } ,
218- closed : false
219- } ;
220- } ;
221-
222- // Step 5: Click the sign in button
223- console . log ( "llgT: About to click sign in button" ) ;
224- signInButton . trigger ( 'click' ) ;
225-
226- // Verify window.open was called with the account URL
227- expect ( capturedURL ) . toBeDefined ( ) ;
228- expect ( capturedURL ) . toContain ( 'phcode.dev' ) ; // Should contain account domain
229- expect ( capturedTarget ) . toBe ( '_blank' ) ;
230-
231- // Step 6: Wait for login waiting dialog to appear
232- await testWindow . __PR . waitForModalDialog ( ".browser-login-waiting-dialog" ) ;
233-
234- // Get waiting dialog content
235- console . log ( "llgT: Looking for waiting dialog..." ) ;
236- let waitingDialog = testWindow . $ ( '.modal' ) ;
237- if ( waitingDialog . length === 0 ) {
238- // Look for the waiting dialog by its unique button
239- waitingDialog = testWindow . $ ( '[data-button-id="check"]' ) . closest ( 'div' ) ;
240- }
241- console . log ( "llgT: Waiting dialog found:" , waitingDialog . length ) ;
242- expect ( waitingDialog . length ) . toBeGreaterThan ( 0 ) ;
243-
244- // Verify waiting dialog content
245- const checkNowButton = testWindow . $ ( '[data-button-id="check"]' ) ;
246- expect ( checkNowButton . length ) . toBe ( 1 ) ;
247- expect ( checkNowButton . text ( ) . trim ( ) ) . toContain ( 'Check Now' ) ;
248-
249- // Step 7: Click "Check Now" button to verify login (in iframe testWindow)
250- // Click the Check Now button
251- console . log ( "llgT: Clicking Check Now button" ) ;
252- checkNowButton . trigger ( 'click' ) ;
253-
254- // Wait for login verification to complete and success message
255- await awaitsFor (
256- function ( ) {
257- const isLoggedIn = LoginServiceExports . LoginService . isLoggedIn ( ) ;
258- if ( isLoggedIn ) {
259- console . log ( "llgT: User is now logged in!" ) ;
260- }
261- return isLoggedIn ;
262- } ,
263- "User to be logged in" ,
264- 5000
265- ) ;
266-
267- // Verify user is now logged in
268- expect ( LoginServiceExports . LoginService . isLoggedIn ( ) ) . toBe ( true ) ;
269-
270- // Verify profile icon has been updated with user initials
271- const $profileIcon = testWindow . $ ( "#user-profile-button" ) ;
272- const profileIconContent = $profileIcon . html ( ) ;
273- expect ( profileIconContent ) . toContain ( 'svg' ) ; // Should contain SVG element
274- expect ( profileIconContent ) . toContain ( 'TU' ) ; // Should contain user initials
275-
276- // Step 8: Wait for login dialog to close automatically (or close it manually)
277- await awaitsFor (
278- function ( ) {
279- return testWindow . $ ( '.modal:visible' ) . length === 0 &&
280- testWindow . $ ( '[data-button-id="check"]:visible' ) . length === 0 ;
281- } ,
282- "Login dialog to close" ,
283- 3000
284- ) ;
285-
286- // Step 9: Click profile icon again to verify profile popup appears
287- $profileButton . trigger ( 'click' ) ;
288-
289- // Wait for profile popup (not login popup) to appear
290- await awaitsFor (
291- function ( ) {
292- return testWindow . $ ( '.modal' ) . length > 0 ||
293- testWindow . $ ( '.profile-popup' ) . length > 0 ;
294- } ,
295- "Profile popup to appear" ,
296- 3000
297- ) ;
298-
299- // Get the new popup content
300- let newPopupContent = testWindow . $ ( '.modal' ) ;
301- if ( newPopupContent . length === 0 ) {
302- newPopupContent = testWindow . $ ( '.profile-popup' ) ;
303- }
304-
305- // Verify it's the profile popup (contains sign out button, not sign in)
306- const signOutButton = newPopupContent . find ( '#phoenix-signout-btn' ) ;
307- const newSignInButton = newPopupContent . find ( '#phoenix-signin-btn' ) ;
308-
309- expect ( signOutButton . length ) . toBe ( 1 ) ; // Should have sign out button
310- expect ( newSignInButton . length ) . toBe ( 0 ) ; // Should NOT have sign in button
311-
312- // Step 10: Test sign out functionality
313- console . log ( "llgT: About to click sign out button" ) ;
314- console . log ( "llgT: Login state before sign out:" , LoginServiceExports . LoginService . isLoggedIn ( ) ) ;
315-
316- signOutButton . trigger ( 'click' ) ;
317-
318- // Wait for sign out dialog to appear and dismiss it
319- console . log ( "llgT: Waiting for sign out confirmation dialog" ) ;
320- await testWindow . __PR . waitForModalDialog ( ".modal" ) ;
321-
322- // Dismiss the "you have been signed out" dialog with OK button
323- console . log ( "llgT: Dismissing sign out confirmation dialog" ) ;
324- testWindow . __PR . clickDialogButtonID ( testWindow . __PR . Dialogs . DIALOG_BTN_OK ) ;
325- await testWindow . __PR . waitForModalDialogClosed ( ".modal" ) ;
326-
327- // Wait for sign out to complete
328- console . log ( "llgT: Waiting for user to be signed out..." ) ;
329- await awaitsFor (
330- function ( ) {
331- return ! LoginServiceExports . LoginService . isLoggedIn ( ) ;
332- } ,
333- "User to be signed out" ,
334- 10000 // Increase timeout to see if it's just taking longer
335- ) ;
336-
337- // Verify profile icon has been updated (should be empty again)
338- const $profileIconAfterSignout = testWindow . $ ( "#user-profile-button" ) ;
339- const profileIconContentAfterSignout = $profileIconAfterSignout . html ( ) ;
340- console . log ( "llgT: Profile icon after signout:" , profileIconContentAfterSignout ) ;
341-
342- // Step 11: Verify clicking profile icon again shows login popup (not profile popup)
343- console . log ( "llgT: Clicking profile icon after sign out to verify login popup appears" ) ;
344- $profileIconAfterSignout . trigger ( 'click' ) ;
345-
346- // Wait for login popup to appear again
347- await awaitsFor (
348- function ( ) {
349- return testWindow . $ ( '.modal' ) . length > 0 || testWindow . $ ( '.profile-popup' ) . length > 0 ;
350- } ,
351- "Login popup to appear after signout" ,
352- 3000
353- ) ;
354-
355- // Get the popup content after signout
356- let finalPopupContent = testWindow . $ ( '.modal' ) ;
357- if ( finalPopupContent . length === 0 ) {
358- finalPopupContent = testWindow . $ ( '.profile-popup' ) ;
359- }
360-
361- // Verify it's back to login popup (has sign in button, no sign out button)
362- const finalSignInButton = finalPopupContent . find ( '#phoenix-signin-btn' ) ;
363- const finalSignOutButton = finalPopupContent . find ( '#phoenix-signout-btn' ) ;
364-
365- expect ( finalSignInButton . length ) . toBe ( 1 ) ; // Should have sign in button again
366- expect ( finalSignOutButton . length ) . toBe ( 0 ) ; // Should NOT have sign out button
367-
368- // just click outside or use popup close method
369- $profileIconAfterSignout . trigger ( 'click' ) ; // Toggle to close
370- } ) ;
371- } ) ;
372-
373100 // Helper functions for promotion testing (browser-specific)
374101 async function setupTrialState ( daysRemaining ) {
375102 const PromotionExports = testWindow . _test_promo_login_exports ;
@@ -686,16 +413,103 @@ define(function (require, exports, module) {
686413 ) ;
687414 }
688415
689- describe ( "Browser Login Promotion Tests" , function ( ) {
416+ describe ( "Browser Login Tests" , function ( ) {
690417
691418 beforeEach ( async function ( ) {
692419 // Ensure clean state before each test
693420 if ( LoginServiceExports . LoginService . isLoggedIn ( ) ) {
694- throw new Error ( "Promotion tests require user to be logged out at start. Please log out before running these tests." ) ;
421+ throw new Error ( "browser login tests require user to be logged out at start. Please log out before running these tests." ) ;
695422 }
696423 await cleanupTrialState ( ) ;
697424 } ) ;
698425
426+ it ( "should complete login and logout flow" , async function ( ) {
427+ // Setup basic user mock
428+ setupProUserMock ( false ) ;
429+
430+ // Perform full login flow
431+ await performFullLoginFlow ( ) ;
432+ expect ( LoginServiceExports . LoginService . isLoggedIn ( ) ) . toBe ( true ) ;
433+
434+ // Perform full logout flow
435+ await performFullLogoutFlow ( ) ;
436+ expect ( LoginServiceExports . LoginService . isLoggedIn ( ) ) . toBe ( false ) ;
437+ } ) ;
438+
439+ it ( "should update profile icon after login" , async function ( ) {
440+ // Setup basic user mock
441+ setupProUserMock ( false ) ;
442+
443+ // Verify initial state
444+ const $profileIcon = testWindow . $ ( "#user-profile-button" ) ;
445+ const initialContent = $profileIcon . html ( ) ;
446+ expect ( initialContent ) . not . toContain ( 'TU' ) ;
447+
448+ // Perform login
449+ await performFullLoginFlow ( ) ;
450+
451+ // Verify profile icon updated with user initials
452+ const updatedContent = $profileIcon . html ( ) ;
453+ expect ( updatedContent ) . toContain ( 'svg' ) ;
454+ expect ( updatedContent ) . toContain ( 'TU' ) ;
455+
456+ // Logout for cleanup
457+ await performFullLogoutFlow ( ) ;
458+ } ) ;
459+
460+ it ( "should show correct popup states" , async function ( ) {
461+ // Setup basic user mock
462+ setupProUserMock ( false ) ;
463+
464+ const $profileButton = testWindow . $ ( "#user-profile-button" ) ;
465+
466+ // Test initial state - should show signin popup
467+ $profileButton . trigger ( 'click' ) ;
468+ await popupToAppear ( SIGNIN_POPUP ) ;
469+
470+ let popupContent = testWindow . $ ( '.profile-popup' ) ;
471+ const signInButton = popupContent . find ( '#phoenix-signin-btn' ) ;
472+ const signOutButton = popupContent . find ( '#phoenix-signout-btn' ) ;
473+
474+ expect ( signInButton . length ) . toBe ( 1 ) ;
475+ expect ( signOutButton . length ) . toBe ( 0 ) ;
476+
477+ // Close popup
478+ $profileButton . trigger ( 'click' ) ;
479+
480+ // Perform login
481+ await performFullLoginFlow ( ) ;
482+
483+ // Test logged in state - should show profile popup
484+ $profileButton . trigger ( 'click' ) ;
485+ await popupToAppear ( PROFILE_POPUP ) ;
486+
487+ popupContent = testWindow . $ ( '.profile-popup' ) ;
488+ const newSignInButton = popupContent . find ( '#phoenix-signin-btn' ) ;
489+ const newSignOutButton = popupContent . find ( '#phoenix-signout-btn' ) ;
490+
491+ expect ( newSignInButton . length ) . toBe ( 0 ) ;
492+ expect ( newSignOutButton . length ) . toBe ( 1 ) ;
493+
494+ // Close popup and logout for cleanup
495+ $profileButton . trigger ( 'click' ) ;
496+ await performFullLogoutFlow ( ) ;
497+
498+ // Test final state - should be back to signin popup
499+ $profileButton . trigger ( 'click' ) ;
500+ await popupToAppear ( SIGNIN_POPUP ) ;
501+
502+ popupContent = testWindow . $ ( '.profile-popup' ) ;
503+ const finalSignInButton = popupContent . find ( '#phoenix-signin-btn' ) ;
504+ const finalSignOutButton = popupContent . find ( '#phoenix-signout-btn' ) ;
505+
506+ expect ( finalSignInButton . length ) . toBe ( 1 ) ;
507+ expect ( finalSignOutButton . length ) . toBe ( 0 ) ;
508+
509+ // Close popup
510+ $profileButton . trigger ( 'click' ) ;
511+ } ) ;
512+
699513 it ( "should show pro branding for user with pro subscription (expired trial)" , async function ( ) {
700514 console . log ( "llgT: Starting browser pro user with expired trial test" ) ;
701515
0 commit comments