@@ -238,6 +238,66 @@ testAgainstRunningApps({ withPattern: ['react.vite.withLegalConsent'] })(
238238 } ,
239239) ;
240240
241+ testAgainstRunningApps ( { withPattern : [ 'react.vite.withLegalConsent' ] } ) (
242+ 'oauth popup with hash-based routing @react' ,
243+ ( { app } ) => {
244+ test . describe . configure ( { mode : 'serial' } ) ;
245+
246+ let fakeUser : FakeUser ;
247+
248+ test . beforeAll ( async ( ) => {
249+ const client = createClerkClient ( {
250+ secretKey : instanceKeys . get ( 'oauth-provider' ) . sk ,
251+ publishableKey : instanceKeys . get ( 'oauth-provider' ) . pk ,
252+ } ) ;
253+ const users = createUserService ( client ) ;
254+ fakeUser = users . createFakeUser ( {
255+ withUsername : true ,
256+ } ) ;
257+ await users . createBapiUser ( fakeUser ) ;
258+ } ) ;
259+
260+ test . afterAll ( async ( ) => {
261+ const u = createTestUtils ( { app } ) ;
262+ await fakeUser . deleteIfExists ( ) ;
263+ await u . services . users . deleteIfExists ( { email : fakeUser . email } ) ;
264+ await app . teardown ( ) ;
265+ } ) ;
266+
267+ test ( 'popup OAuth navigates through sso-callback with hash-based routing' , async ( { page, context } ) => {
268+ const u = createTestUtils ( { app, page, context } ) ;
269+
270+ await u . page . goToRelative ( '/sign-in-hash-popup' ) ;
271+ await u . page . waitForClerkJsLoaded ( ) ;
272+ await u . po . signIn . waitForMounted ( ) ;
273+
274+ const popupPromise = context . waitForEvent ( 'page' ) ;
275+ await u . page . getByRole ( 'button' , { name : 'E2E OAuth Provider' } ) . click ( ) ;
276+ const popup = await popupPromise ;
277+ const popupUtils = createTestUtils ( { app, page : popup , context } ) ;
278+ await popupUtils . page . getByText ( 'Sign in to oauth-provider' ) . waitFor ( ) ;
279+
280+ // Complete OAuth in the popup
281+ await popupUtils . po . signIn . setIdentifier ( fakeUser . email ) ;
282+ await popupUtils . po . signIn . continue ( ) ;
283+ await popupUtils . po . signIn . enterTestOtpCode ( ) ;
284+
285+ // Because the user is new to the app and legal consent is required,
286+ // the sign-up can't complete in the popup. The popup sends return_url
287+ // back to the parent, which navigates to /sso-callback via pushState.
288+ // With hash routing, the HashRouter must detect this pushState change
289+ // to render the sso-callback route. hashchange does not fire for
290+ // pushState, so the router needs pushstate/replacestate listeners.
291+ await u . page . getByRole ( 'heading' , { name : 'Legal consent' } ) . waitFor ( ) ;
292+ await u . page . getByLabel ( / I a g r e e t o t h e / ) . check ( ) ;
293+ await u . po . signIn . continue ( ) ;
294+
295+ await u . page . getByText ( 'SignedIn' ) . waitFor ( ) ;
296+ await u . po . expect . toBeSignedIn ( ) ;
297+ } ) ;
298+ } ,
299+ ) ;
300+
241301testAgainstRunningApps ( { withEnv : [ appConfigs . envs . withLegalConsent ] } ) (
242302 'oauth flows with legal consent @nextjs' ,
243303 ( { app } ) => {
0 commit comments