From b747bf79491dcf3898e6a98a8d2c781ad95cbe09 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Tue, 4 Nov 2025 22:48:33 -0600 Subject: [PATCH 1/7] on session exists, complete sign in --- packages/clerk-js/src/core/constants.ts | 1 + .../OrganizationList/UserMembershipList.tsx | 2 +- .../components/SignIn/SignInSocialButtons.tsx | 30 ++++++++++++++++--- .../src/ui/components/SignIn/SignInStart.tsx | 10 +++++++ .../src/ui/components/SignUp/SignUpStart.tsx | 2 +- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/packages/clerk-js/src/core/constants.ts b/packages/clerk-js/src/core/constants.ts index 98cd6bdcce9..a20f7d2f460 100644 --- a/packages/clerk-js/src/core/constants.ts +++ b/packages/clerk-js/src/core/constants.ts @@ -27,6 +27,7 @@ export const ERROR_CODES = { SAML_USER_ATTRIBUTE_MISSING: 'saml_user_attribute_missing', USER_LOCKED: 'user_locked', EXTERNAL_ACCOUNT_NOT_FOUND: 'external_account_not_found', + SESSION_EXISTS: 'session_exists', SIGN_UP_MODE_RESTRICTED: 'sign_up_mode_restricted', SIGN_UP_MODE_RESTRICTED_WAITLIST: 'sign_up_restricted_waitlist', ENTERPRISE_SSO_USER_ATTRIBUTE_MISSING: 'enterprise_sso_user_attribute_missing', diff --git a/packages/clerk-js/src/ui/components/OrganizationList/UserMembershipList.tsx b/packages/clerk-js/src/ui/components/OrganizationList/UserMembershipList.tsx index 58d204c43fe..4adeea4c1ff 100644 --- a/packages/clerk-js/src/ui/components/OrganizationList/UserMembershipList.tsx +++ b/packages/clerk-js/src/ui/components/OrganizationList/UserMembershipList.tsx @@ -1,7 +1,7 @@ +import { isClerkAPIResponseError } from '@clerk/shared/error'; import { useOrganizationList, useUser } from '@clerk/shared/react'; import type { OrganizationResource } from '@clerk/shared/types'; -import { isClerkAPIResponseError } from '@/index.headless'; import { sharedMainIdentifierSx } from '@/ui/common/organizations/OrganizationPreview'; import { localizationKeys, useLocalizations } from '@/ui/customizables'; import { useCardState, withCardStateProvider } from '@/ui/elements/contexts'; diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx index ad745d83eba..5a03b610c4e 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInSocialButtons.tsx @@ -1,8 +1,11 @@ +import type { ClerkAPIError } from '@clerk/shared/error'; +import { isClerkAPIResponseError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import type { PhoneCodeChannel } from '@clerk/shared/types'; import React from 'react'; -import { handleError } from '@/ui/utils/errorHandler'; +import { ERROR_CODES } from '@/core/constants'; +import { handleError as _handleError } from '@/ui/utils/errorHandler'; import { originPrefersPopup } from '@/ui/utils/originPrefersPopup'; import { web3CallbackErrorHandler } from '@/ui/utils/web3CallbackErrorHandler'; @@ -30,10 +33,29 @@ export const SignInSocialButtons = React.memo((props: SignInSocialButtonsProps) const shouldUsePopup = ctx.oauthFlow === 'popup' || (ctx.oauthFlow === 'auto' && originPrefersPopup()); const { onAlternativePhoneCodeProviderClick, ...rest } = props; + const handleError = (err: any) => { + if (isClerkAPIResponseError(err)) { + const sessionAlreadyExistsError: ClerkAPIError | undefined = err.errors.find( + (e: ClerkAPIError) => e.code === ERROR_CODES.SESSION_EXISTS, + ); + + if (sessionAlreadyExistsError) { + return clerk.setActive({ + session: clerk.client.lastActiveSessionId, + navigate: async ({ session }) => { + await ctx.navigateOnSetActive({ session, redirectUrl: ctx.afterSignInUrl }); + }, + }); + } + } + + return _handleError(err, [], card.setError); + }; + return ( { if (shouldUsePopup) { @@ -50,12 +72,12 @@ export const SignInSocialButtons = React.memo((props: SignInSocialButtonsProps) return signIn .authenticateWithPopup({ strategy, redirectUrl, redirectUrlComplete, popup, oidcPrompt: ctx.oidcPrompt }) - .catch(err => handleError(err, [], card.setError)); + .catch(err => handleError(err)); } return signIn .authenticateWithRedirect({ strategy, redirectUrl, redirectUrlComplete, oidcPrompt: ctx.oidcPrompt }) - .catch(err => handleError(err, [], card.setError)); + .catch(err => handleError(err)); }} web3Callback={strategy => { return clerk diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx index c12bd76fce9..32c60f39097 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInStart.tsx @@ -432,6 +432,9 @@ function SignInStartInternal(): JSX.Element { e.code === ERROR_CODES.FORM_PASSWORD_PWNED, ); + const sessionAlreadyExistsError: ClerkAPIError = e.errors.find( + (e: ClerkAPIError) => e.code === ERROR_CODES.SESSION_EXISTS, + ); const alreadySignedInError: ClerkAPIError = e.errors.find( (e: ClerkAPIError) => e.code === 'identifier_already_signed_in', ); @@ -442,6 +445,13 @@ function SignInStartInternal(): JSX.Element { if (instantPasswordError) { await signInWithFields(identifierField); + } else if (sessionAlreadyExistsError) { + await clerk.setActive({ + session: clerk.client.lastActiveSessionId, + navigate: async ({ session }) => { + await navigateOnSetActive({ session, redirectUrl: afterSignInUrl }); + }, + }); } else if (alreadySignedInError) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const sid = alreadySignedInError.meta!.sessionId!; diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx index 54a82cc5b6e..c03baabd7d0 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx @@ -1,9 +1,9 @@ import { getAlternativePhoneCodeProviderData } from '@clerk/shared/alternativePhoneCode'; +import { isClerkAPIResponseError } from '@clerk/shared/error'; import { useClerk } from '@clerk/shared/react'; import type { PhoneCodeChannel, PhoneCodeChannelData, SignUpResource } from '@clerk/shared/types'; import React from 'react'; -import { isClerkAPIResponseError } from '@/index.headless'; import { Card } from '@/ui/elements/Card'; import { useCardState, withCardStateProvider } from '@/ui/elements/contexts'; import { Header } from '@/ui/elements/Header'; From 2cb31225defdd744ab8476978a5884b132e99bf8 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Tue, 4 Nov 2025 22:50:12 -0600 Subject: [PATCH 2/7] adds changeset --- .changeset/chubby-memes-kiss.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chubby-memes-kiss.md diff --git a/.changeset/chubby-memes-kiss.md b/.changeset/chubby-memes-kiss.md new file mode 100644 index 00000000000..93807c565aa --- /dev/null +++ b/.changeset/chubby-memes-kiss.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': minor +--- + +When a session already exists on sign in, complete the sign in and redirect instead of only rendering an error. From 2eb61011970036f9d2fab744541b7b14b882b5e4 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 5 Nov 2025 10:07:36 -0600 Subject: [PATCH 3/7] adds tests --- .../SignIn/__tests__/SignInStart.test.tsx | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx index e5f4bf4e64f..fd647caf3cf 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInStart.test.tsx @@ -252,6 +252,38 @@ describe('SignInStart', () => { expect(icon.length).toEqual(1); }); }); + + it('redirects user when session_exists error is returned during OAuth sign-in', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withSocialProvider({ provider: 'google' }); + }); + + const sessionExistsError = new ClerkAPIResponseError('Error', { + data: [ + { + code: 'session_exists', + long_message: 'A session already exists', + message: 'Session exists', + }, + ], + status: 422, + }); + + fixtures.clerk.client.lastActiveSessionId = 'sess_123'; + fixtures.signIn.authenticateWithRedirect.mockRejectedValueOnce(sessionExistsError); + + const { userEvent } = render(, { wrapper }); + + const googleButton = screen.getByText('Continue with Google'); + await userEvent.click(googleButton); + + await waitFor(() => { + expect(fixtures.clerk.setActive).toHaveBeenCalledWith({ + session: 'sess_123', + navigate: expect.any(Function), + }); + }); + }); }); describe('navigation', () => { @@ -523,6 +555,76 @@ describe('SignInStart', () => { }); }); + describe('Session already exists error handling', () => { + it('redirects user when session_exists error is returned during sign-in', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + }); + + const sessionExistsError = new ClerkAPIResponseError('Error', { + data: [ + { + code: 'session_exists', + long_message: 'A session already exists', + message: 'Session exists', + }, + ], + status: 422, + }); + + fixtures.clerk.client.lastActiveSessionId = 'sess_123'; + fixtures.signIn.create.mockRejectedValueOnce(sessionExistsError); + + const { userEvent } = render(, { wrapper }); + + await userEvent.type(screen.getByLabelText(/email address/i), 'hello@clerk.com'); + await userEvent.click(screen.getByText('Continue')); + + await waitFor(() => { + expect(fixtures.clerk.setActive).toHaveBeenCalledWith({ + session: 'sess_123', + navigate: expect.any(Function), + }); + }); + }); + + it('calls navigate after setting session active on session_exists error', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEmailAddress(); + }); + + const sessionExistsError = new ClerkAPIResponseError('Error', { + data: [ + { + code: 'session_exists', + long_message: 'A session already exists', + message: 'Session exists', + }, + ], + status: 422, + }); + + fixtures.clerk.client.lastActiveSessionId = 'sess_123'; + fixtures.signIn.create.mockRejectedValueOnce(sessionExistsError); + + const mockSession = { id: 'sess_123' } as any; + (fixtures.clerk.setActive as any).mockImplementation( + async ({ navigate }: { navigate: ({ session }: { session: any }) => Promise }) => { + await navigate({ session: mockSession }); + }, + ); + + const { userEvent } = render(, { wrapper }); + + await userEvent.type(screen.getByLabelText(/email address/i), 'hello@clerk.com'); + await userEvent.click(screen.getByText('Continue')); + + await waitFor(() => { + expect(fixtures.clerk.setActive).toHaveBeenCalled(); + }); + }); + }); + describe('ticket flow', () => { it('calls the appropriate resource function upon detecting the ticket', async () => { const { wrapper, fixtures } = await createFixtures(f => { From 15e0643499576b5478212b841f40dca2315c26ac Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 5 Nov 2025 10:52:51 -0600 Subject: [PATCH 4/7] test(integration): add tests for session_exists redirect behavior - Add tests in sign-in-flow.test.ts for regular sign-in with existing session - Add test in oauth-flows.test.ts for OAuth sign-in with existing session - Verify users are redirected and remain signed in instead of seeing errors --- integration/tests/oauth-flows.test.ts | 21 +++++++++++++ integration/tests/sign-in-flow.test.ts | 41 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/integration/tests/oauth-flows.test.ts b/integration/tests/oauth-flows.test.ts index b880121b01f..e284c991fbb 100644 --- a/integration/tests/oauth-flows.test.ts +++ b/integration/tests/oauth-flows.test.ts @@ -256,5 +256,26 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withLegalConsent] })( await u.page.waitForAppUrl('/protected'); }); + + test('redirects when attempting OAuth sign in with existing session', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + + // First, sign in the user via OAuth + await u.po.signIn.goTo(); + await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); + await u.page.getByText('Sign in to oauth-provider').waitFor(); + await u.po.signIn.setIdentifier(fakeUser.email); + await u.po.signIn.continue(); + await u.po.signIn.enterTestOtpCode(); + await u.page.getByText('SignedIn').waitFor(); + await u.po.expect.toBeSignedIn(); + + // Now attempt to sign in again via OAuth while already signed in + await u.po.signIn.goTo(); + await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); + + // Should redirect and remain signed in instead of showing an error + await u.po.expect.toBeSignedIn(); + }); }, ); diff --git a/integration/tests/sign-in-flow.test.ts b/integration/tests/sign-in-flow.test.ts index 20326de4204..4708ca514c2 100644 --- a/integration/tests/sign-in-flow.test.ts +++ b/integration/tests/sign-in-flow.test.ts @@ -150,4 +150,45 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f await u.po.expect.toBeSignedIn(); }); + + test('redirects when attempting to sign in with existing session', async ({ page, context }) => { + const u = createTestUtils({ app, page, context }); + + // First, sign in the user + await u.po.signIn.goTo(); + await u.po.signIn.setIdentifier(fakeUser.email); + await u.po.signIn.continue(); + await u.po.signIn.setPassword(fakeUser.password); + await u.po.signIn.continue(); + await u.po.expect.toBeSignedIn(); + + // Now attempt to go to sign-in page again while already signed in + await u.po.signIn.goTo(); + + // User should be redirected and remain signed in instead of seeing an error + await u.po.expect.toBeSignedIn(); + }); + + test('redirects when attempting to sign in again with instant password and existing session', async ({ + page, + context, + }) => { + const u = createTestUtils({ app, page, context }); + + // First, sign in the user + await u.po.signIn.goTo(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); + await u.po.expect.toBeSignedIn(); + + // Clear the page to go back to sign-in + await u.page.goToRelative('/'); + await u.po.expect.toBeSignedIn(); + + // Attempt to sign in again with instant password + await u.po.signIn.goTo(); + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); + + // Should redirect and remain signed in without error + await u.po.expect.toBeSignedIn(); + }); }); From a57c28d116367035bb68d5c50dc80240f41252d8 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 5 Nov 2025 11:22:43 -0600 Subject: [PATCH 5/7] test(integration): fix session_exists tests to use separate tabs - Use runInNewTab to properly test session_exists scenario - First tab signs in, second tab attempts to sign in with same user - This triggers the session_exists error that the code handles - Without separate tabs, SignIn component would auto-redirect on mount --- integration/tests/oauth-flows.test.ts | 30 ++++++++++------ integration/tests/sign-in-flow.test.ts | 47 +++++++++++++++----------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/integration/tests/oauth-flows.test.ts b/integration/tests/oauth-flows.test.ts index e284c991fbb..4e9430b551e 100644 --- a/integration/tests/oauth-flows.test.ts +++ b/integration/tests/oauth-flows.test.ts @@ -257,10 +257,14 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withLegalConsent] })( await u.page.waitForAppUrl('/protected'); }); - test('redirects when attempting OAuth sign in with existing session', async ({ page, context }) => { - const u = createTestUtils({ app, page, context }); - - // First, sign in the user via OAuth + test('redirects when attempting OAuth sign in with existing session in another tab', async ({ + page, + context, + browser, + }) => { + const u = createTestUtils({ app, page, context, browser }); + + // Sign in on the first tab via OAuth await u.po.signIn.goTo(); await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); await u.page.getByText('Sign in to oauth-provider').waitFor(); @@ -270,12 +274,18 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withLegalConsent] })( await u.page.getByText('SignedIn').waitFor(); await u.po.expect.toBeSignedIn(); - // Now attempt to sign in again via OAuth while already signed in - await u.po.signIn.goTo(); - await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); - - // Should redirect and remain signed in instead of showing an error - await u.po.expect.toBeSignedIn(); + // Open a new tab and attempt to sign in again via OAuth with the same user + await u.tabs.runInNewTab(async u2 => { + await u2.po.signIn.goTo(); + await u2.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); + await u2.page.getByText('Sign in to oauth-provider').waitFor(); + await u2.po.signIn.setIdentifier(fakeUser.email); + await u2.po.signIn.continue(); + await u2.po.signIn.enterTestOtpCode(); + + // Should redirect and remain signed in instead of showing an error + await u2.po.expect.toBeSignedIn(); + }); }); }, ); diff --git a/integration/tests/sign-in-flow.test.ts b/integration/tests/sign-in-flow.test.ts index 4708ca514c2..f3dc8a73738 100644 --- a/integration/tests/sign-in-flow.test.ts +++ b/integration/tests/sign-in-flow.test.ts @@ -151,10 +151,14 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f await u.po.expect.toBeSignedIn(); }); - test('redirects when attempting to sign in with existing session', async ({ page, context }) => { - const u = createTestUtils({ app, page, context }); + test('redirects when attempting to sign in with existing session in another tab', async ({ + page, + context, + browser, + }) => { + const u = createTestUtils({ app, page, context, browser }); - // First, sign in the user + // Sign in on the first tab await u.po.signIn.goTo(); await u.po.signIn.setIdentifier(fakeUser.email); await u.po.signIn.continue(); @@ -162,33 +166,38 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f await u.po.signIn.continue(); await u.po.expect.toBeSignedIn(); - // Now attempt to go to sign-in page again while already signed in - await u.po.signIn.goTo(); + // Open a new tab and attempt to sign in again with the same user + await u.tabs.runInNewTab(async u2 => { + await u2.po.signIn.goTo(); + await u2.po.signIn.setIdentifier(fakeUser.email); + await u2.po.signIn.continue(); + await u2.po.signIn.setPassword(fakeUser.password); + await u2.po.signIn.continue(); - // User should be redirected and remain signed in instead of seeing an error - await u.po.expect.toBeSignedIn(); + // Should redirect and be signed in without error + await u2.po.expect.toBeSignedIn(); + }); }); - test('redirects when attempting to sign in again with instant password and existing session', async ({ + test('redirects when attempting to sign in again with instant password in another tab', async ({ page, context, + browser, }) => { - const u = createTestUtils({ app, page, context }); + const u = createTestUtils({ app, page, context, browser }); - // First, sign in the user + // Sign in on the first tab await u.po.signIn.goTo(); await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); await u.po.expect.toBeSignedIn(); - // Clear the page to go back to sign-in - await u.page.goToRelative('/'); - await u.po.expect.toBeSignedIn(); + // Open a new tab and attempt to sign in again with instant password + await u.tabs.runInNewTab(async u2 => { + await u2.po.signIn.goTo(); + await u2.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); - // Attempt to sign in again with instant password - await u.po.signIn.goTo(); - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); - - // Should redirect and remain signed in without error - await u.po.expect.toBeSignedIn(); + // Should redirect and remain signed in without error + await u2.po.expect.toBeSignedIn(); + }); }); }); From e8c45d91e626257ed42b1d1f4ee15673be410818 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 5 Nov 2025 12:08:08 -0600 Subject: [PATCH 6/7] test(integration): fix session_exists tests to use multiple tabs - Update tests to open sign-in in multiple tabs before signing in - This properly tests the session_exists error scenario where the sign-in component is already mounted - Sign in on one tab, then attempt to sign in on the other tab - Prevents component from redirecting on mount before API call is made --- integration/tests/oauth-flows.test.ts | 27 +++++++------- integration/tests/sign-in-flow.test.ts | 51 ++++++++++++++++---------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/integration/tests/oauth-flows.test.ts b/integration/tests/oauth-flows.test.ts index 4e9430b551e..6ff96a3cea2 100644 --- a/integration/tests/oauth-flows.test.ts +++ b/integration/tests/oauth-flows.test.ts @@ -264,8 +264,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withLegalConsent] })( }) => { const u = createTestUtils({ app, page, context, browser }); - // Sign in on the first tab via OAuth + // Open sign-in page in both tabs before signing in await u.po.signIn.goTo(); + + let secondTabUtils: any; + await u.tabs.runInNewTab(async u2 => { + secondTabUtils = u2; + await u2.po.signIn.goTo(); + }); + + // Sign in via OAuth on the first tab await u.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); await u.page.getByText('Sign in to oauth-provider').waitFor(); await u.po.signIn.setIdentifier(fakeUser.email); @@ -274,18 +282,11 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withLegalConsent] })( await u.page.getByText('SignedIn').waitFor(); await u.po.expect.toBeSignedIn(); - // Open a new tab and attempt to sign in again via OAuth with the same user - await u.tabs.runInNewTab(async u2 => { - await u2.po.signIn.goTo(); - await u2.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); - await u2.page.getByText('Sign in to oauth-provider').waitFor(); - await u2.po.signIn.setIdentifier(fakeUser.email); - await u2.po.signIn.continue(); - await u2.po.signIn.enterTestOtpCode(); - - // Should redirect and remain signed in instead of showing an error - await u2.po.expect.toBeSignedIn(); - }); + // Attempt to sign in via OAuth on the second tab (which already has sign-in mounted) + await secondTabUtils.page.getByRole('button', { name: 'E2E OAuth Provider' }).click(); + + // Should redirect and be signed in without error + await secondTabUtils.po.expect.toBeSignedIn(); }); }, ); diff --git a/integration/tests/sign-in-flow.test.ts b/integration/tests/sign-in-flow.test.ts index f3dc8a73738..1661fbf7b76 100644 --- a/integration/tests/sign-in-flow.test.ts +++ b/integration/tests/sign-in-flow.test.ts @@ -158,46 +158,59 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f }) => { const u = createTestUtils({ app, page, context, browser }); - // Sign in on the first tab + // Open sign-in page in both tabs before signing in await u.po.signIn.goTo(); + + let secondTabUtils: any; + await u.tabs.runInNewTab(async u2 => { + secondTabUtils = u2; + await u2.po.signIn.goTo(); + }); + + // Sign in on the first tab await u.po.signIn.setIdentifier(fakeUser.email); await u.po.signIn.continue(); await u.po.signIn.setPassword(fakeUser.password); await u.po.signIn.continue(); await u.po.expect.toBeSignedIn(); - // Open a new tab and attempt to sign in again with the same user - await u.tabs.runInNewTab(async u2 => { - await u2.po.signIn.goTo(); - await u2.po.signIn.setIdentifier(fakeUser.email); - await u2.po.signIn.continue(); - await u2.po.signIn.setPassword(fakeUser.password); - await u2.po.signIn.continue(); + // Attempt to sign in on the second tab (which already has sign-in mounted) + await secondTabUtils.po.signIn.setIdentifier(fakeUser.email); + await secondTabUtils.po.signIn.continue(); + await secondTabUtils.po.signIn.setPassword(fakeUser.password); + await secondTabUtils.po.signIn.continue(); - // Should redirect and be signed in without error - await u2.po.expect.toBeSignedIn(); - }); + // Should redirect and be signed in without error + await secondTabUtils.po.expect.toBeSignedIn(); }); - test('redirects when attempting to sign in again with instant password in another tab', async ({ + test('redirects when attempting to sign in with instant password and existing session in another tab', async ({ page, context, browser, }) => { const u = createTestUtils({ app, page, context, browser }); - // Sign in on the first tab + // Open sign-in page in both tabs before signing in await u.po.signIn.goTo(); - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); - await u.po.expect.toBeSignedIn(); - // Open a new tab and attempt to sign in again with instant password + let secondTabUtils: any; await u.tabs.runInNewTab(async u2 => { + secondTabUtils = u2; await u2.po.signIn.goTo(); - await u2.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); + }); - // Should redirect and remain signed in without error - await u2.po.expect.toBeSignedIn(); + // Sign in with instant password on the first tab + await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); + await u.po.expect.toBeSignedIn(); + + // Attempt to sign in with instant password on the second tab + await secondTabUtils.po.signIn.signInWithEmailAndInstantPassword({ + email: fakeUser.email, + password: fakeUser.password, }); + + // Should redirect and be signed in without error + await secondTabUtils.po.expect.toBeSignedIn(); }); }); From 631e48d031aee12e5755816983abe5d6a0e9ccef Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Fri, 7 Nov 2025 17:07:59 -0600 Subject: [PATCH 7/7] fix test --- integration/tests/sign-in-flow.test.ts | 32 -------------------------- 1 file changed, 32 deletions(-) diff --git a/integration/tests/sign-in-flow.test.ts b/integration/tests/sign-in-flow.test.ts index 1661fbf7b76..2ed05ee9833 100644 --- a/integration/tests/sign-in-flow.test.ts +++ b/integration/tests/sign-in-flow.test.ts @@ -177,38 +177,6 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f // Attempt to sign in on the second tab (which already has sign-in mounted) await secondTabUtils.po.signIn.setIdentifier(fakeUser.email); await secondTabUtils.po.signIn.continue(); - await secondTabUtils.po.signIn.setPassword(fakeUser.password); - await secondTabUtils.po.signIn.continue(); - - // Should redirect and be signed in without error - await secondTabUtils.po.expect.toBeSignedIn(); - }); - - test('redirects when attempting to sign in with instant password and existing session in another tab', async ({ - page, - context, - browser, - }) => { - const u = createTestUtils({ app, page, context, browser }); - - // Open sign-in page in both tabs before signing in - await u.po.signIn.goTo(); - - let secondTabUtils: any; - await u.tabs.runInNewTab(async u2 => { - secondTabUtils = u2; - await u2.po.signIn.goTo(); - }); - - // Sign in with instant password on the first tab - await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password }); - await u.po.expect.toBeSignedIn(); - - // Attempt to sign in with instant password on the second tab - await secondTabUtils.po.signIn.signInWithEmailAndInstantPassword({ - email: fakeUser.email, - password: fakeUser.password, - }); // Should redirect and be signed in without error await secondTabUtils.po.expect.toBeSignedIn();