From 5f83471295099750b14850b9c0a07d9f993a56ea Mon Sep 17 00:00:00 2001 From: Malte Finsterwalder <malte@holi.team> Date: Wed, 2 Apr 2025 19:25:43 +0200 Subject: [PATCH] HOLI-10744 fix social login during registration --- .../{test_helpers.test.ts => helpers.test.ts} | 0 core/auth/helpers/auth/common.ts | 10 ++++++++ core/auth/helpers/axios.ts | 5 +++- core/auth/screens/Login.tsx | 13 +++------- .../onboarding/__tests__/Onboarding.test.tsx | 1 + .../onboarding/steps/CreateAccount.tsx | 25 +++++++++++++------ .../steps/__tests__/CreateAccount.test.tsx | 21 +++++++++++----- jest.config.cjs | 2 +- 8 files changed, 53 insertions(+), 24 deletions(-) rename core/auth/helpers/__tests__/{test_helpers.test.ts => helpers.test.ts} (100%) diff --git a/core/auth/helpers/__tests__/test_helpers.test.ts b/core/auth/helpers/__tests__/helpers.test.ts similarity index 100% rename from core/auth/helpers/__tests__/test_helpers.test.ts rename to core/auth/helpers/__tests__/helpers.test.ts diff --git a/core/auth/helpers/auth/common.ts b/core/auth/helpers/auth/common.ts index 9cf7893b2b..58c8ac4fe1 100644 --- a/core/auth/helpers/auth/common.ts +++ b/core/auth/helpers/auth/common.ts @@ -18,6 +18,10 @@ import { } from '@holi/core/auth/helpers/auth/helpers' import type { VerificationFlowData, VerificationFlowState } from '@holi/core/auth/helpers/useVerificationFlowData' import { HoliError } from '@holi/core/errors/classes/HoliError' +import { ApolloClient } from '@apollo/client' +import type { OrySessionContext } from '@holi/core/auth/helpers/sdk' +import { setLoginStateLoggedIn } from '@holi/core/auth/loginState' +import { clearGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' export const hasIdentifier = ( loginFlowBody: VerificationFlowData | UpdateLoginFlowWithPasswordMethod @@ -69,6 +73,12 @@ export const login = async ({ } } +export const doLogin = async (client: ApolloClient<object>, data: OrySessionContext) => { + await client.clearStore() + await setLoginStateLoggedIn(data) + await clearGuestMode() +} + export const getOrCreateVerificationFlow = async (flowData?: VerificationFlowData) => { if (!flowData) throw new HoliError('[Onboarding] no verification flow has been found') diff --git a/core/auth/helpers/axios.ts b/core/auth/helpers/axios.ts index ff80f1435c..9b6c830a53 100644 --- a/core/auth/helpers/axios.ts +++ b/core/auth/helpers/axios.ts @@ -21,7 +21,10 @@ export const resilience = (axios: AxiosInstance) => { if ( error.response && - (error.response.status == 400 || error.response.status == 401 || error.response.status == 403) + (error.response.status == 400 || + error.response.status == 401 || + error.response.status == 403 || + error.response.status == 422) // 422 is used by Ory for browser redirects ) { logger.debug('auth', 'network request failed with response code ' + error.response.status, { error, diff --git a/core/auth/screens/Login.tsx b/core/auth/screens/Login.tsx index 3aff21589c..c9b86f081f 100644 --- a/core/auth/screens/Login.tsx +++ b/core/auth/screens/Login.tsx @@ -6,11 +6,11 @@ import { Platform, StyleSheet, View } from 'react-native' import FormBuilder from '@holi/core/auth/components/FormBuilder' import RegistrationButton from '@holi/core/auth/components/RegistrationButton' -import { doBrowserLogin, hasIdentifier, initLoginFlow, submitLoginFlow } from '@holi/core/auth/helpers/auth' +import { doBrowserLogin, doLogin, hasIdentifier, initLoginFlow, submitLoginFlow } from '@holi/core/auth/helpers/auth' import { handleFormSubmitError, isUnverifiedUserError } from '@holi/core/auth/helpers/form' import type { OrySessionContext } from '@holi/core/auth/helpers/sdk' import { setVerificationFlowData } from '@holi/core/auth/helpers/useVerificationFlowData' -import { setLoginStateLoggedIn, useLoginState } from '@holi/core/auth/loginState' +import { useLoginState } from '@holi/core/auth/loginState' import DefaultLayout from '@holi/core/components/DefaultLayout' import { HoliTextLinkTracked } from '@holi/core/components/Trackable' import { useErrorHandling } from '@holi/core/errors/hooks' @@ -28,7 +28,6 @@ import HoliLoader, { useLoader } from '@holi/ui/components/molecules/HoliLoader' import { Screen } from '@holi/core/components/Screen' import { useRedirect } from '@holi/core/navigation/hooks/useRedirect' import HoliContainer from '@holi/ui/components/atoms/HoliContainer' -import { clearGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' import useRouting from '@holi/core/navigation/hooks/useRouting' import { getBrowserRedirect } from '@holi/core/auth/helpers/helper' @@ -89,9 +88,7 @@ const Login = () => { try { const { data }: { data: OrySessionContext } = await submitLoginFlow(flow, payload, undefined) - await client.clearStore() - await setLoginStateLoggedIn(data) - await clearGuestMode() + await doLogin(client, data) storeOnboardingState('finished') redirect(true) } catch (err) { @@ -102,9 +99,7 @@ const Login = () => { } else { const data = await doBrowserLogin(url, flow) if (data) { - await client.clearStore() - await setLoginStateLoggedIn(data) - await clearGuestMode() + await doLogin(client, data) storeOnboardingState('finished') redirect(true) } diff --git a/core/screens/onboarding/__tests__/Onboarding.test.tsx b/core/screens/onboarding/__tests__/Onboarding.test.tsx index e83470a0fe..8443e2190b 100644 --- a/core/screens/onboarding/__tests__/Onboarding.test.tsx +++ b/core/screens/onboarding/__tests__/Onboarding.test.tsx @@ -87,6 +87,7 @@ jest.mock('@holi/core/auth/helpers/auth', () => ({ getOrCreateVerificationFlow: jest.fn(), submitVerificationFlow: jest.fn(), hasIdentifier: jest.fn(), + doLogin: jest.fn(), })) const mockNewKratosSdk = newKratosSdk as jest.Mock diff --git a/core/screens/onboarding/steps/CreateAccount.tsx b/core/screens/onboarding/steps/CreateAccount.tsx index b66d11df0d..59f5f77d44 100644 --- a/core/screens/onboarding/steps/CreateAccount.tsx +++ b/core/screens/onboarding/steps/CreateAccount.tsx @@ -6,11 +6,16 @@ import { Keyboard, Platform, StyleSheet, View } from 'react-native' import AlreadyHaveAccountText from '@holi/core/auth/components/AlreadyHaveAccountText' import FormBuilder from '@holi/core/auth/components/FormBuilder' -import { getVerificationFlowFromRegistration, initRegistrationFlow } from '@holi/core/auth/helpers/auth' +import { + doBrowserLogin, + doLogin, + getVerificationFlowFromRegistration, + initRegistrationFlow, +} from '@holi/core/auth/helpers/auth' import { handleFormSubmitError } from '@holi/core/auth/helpers/form' import { newKratosSdk, type OrySessionContext } from '@holi/core/auth/helpers/sdk' import { setVerificationFlowData } from '@holi/core/auth/helpers/useVerificationFlowData' -import { setLoginStateLoggedIn, useLoginState } from '@holi/core/auth/loginState' +import { useLoginState } from '@holi/core/auth/loginState' import { ButtonTracked } from '@holi/core/components/Trackable' import { HoliOnboardingError } from '@holi/core/errors/classes/HoliOnboardingError' import { useErrorHandling } from '@holi/core/errors/hooks' @@ -26,7 +31,7 @@ import HoliLogo from '@holi/ui/components/atoms/HoliLogo' import HoliLoader, { useLoader } from '@holi/ui/components/molecules/HoliLoader' import { type HoliTheme, useTheme } from '@holi/ui/styles/theme' import { Text } from 'holi-bricks/components/text' -import { clearGuestMode, storeGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' +import { storeGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' import useRouting from '@holi/core/navigation/hooks/useRouting' import { getBrowserRedirect } from '@holi/core/auth/helpers/helper' @@ -108,9 +113,7 @@ export const CreateAccount = ({ const verificationFlowData = getVerificationFlowFromRegistration(data) setVerificationFlowData(verificationFlowData) - await client.clearStore() - await clearGuestMode() - await setLoginStateLoggedIn({ + await doLogin(client, { session: data.session, session_token: data.session_token, } as OrySessionContext) @@ -119,7 +122,15 @@ export const CreateAccount = ({ } catch (err) { const url = getBrowserRedirect(err) if (url) { - navigate(url) + if (Platform.OS === 'web') { + navigate(url) + } else { + const data = await doBrowserLogin(url, flow) + if (data) { + await doLogin(client, data) + onRegister() + } + } } else { handleFormSubmitError( setFlow, diff --git a/core/screens/onboarding/steps/__tests__/CreateAccount.test.tsx b/core/screens/onboarding/steps/__tests__/CreateAccount.test.tsx index 33a51d3e46..4f0520e262 100644 --- a/core/screens/onboarding/steps/__tests__/CreateAccount.test.tsx +++ b/core/screens/onboarding/steps/__tests__/CreateAccount.test.tsx @@ -1,5 +1,10 @@ import { MockedProvider } from '@apollo/client/testing' -import { getVerificationFlowFromRegistration, initRegistrationFlow } from '@holi/core/auth/helpers/auth' +import { + doBrowserLogin, + doLogin, + getVerificationFlowFromRegistration, + initRegistrationFlow, +} from '@holi/core/auth/helpers/auth' import { setLoginStateLoggedIn, useLoginState } from '@holi/core/auth/loginState' import { useErrorHandling } from '@holi/core/errors/hooks' import { CreateAccount, type CreateAccountProps } from '@holi/core/screens/onboarding/steps/CreateAccount' @@ -10,8 +15,9 @@ import { TrackingEvent } from '@holi/core/tracking' import useTracking from '@holi/core/tracking/hooks/useTracking' import { newKratosSdk } from '@holi/core/auth/helpers/sdk' import { setVerificationFlowData } from '@holi/core/auth/helpers/useVerificationFlowData' -import { clearGuestMode, storeGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' +import { storeGuestMode } from '@holi/core/screens/onboarding/helpers/guestModeAsyncStore' import useRouting from '@holi/core/navigation/hooks/useRouting' +import { ApolloClient } from '@apollo/client' const mockUseErrorHandling = useErrorHandling as jest.Mock jest.mock('@holi/core/errors/hooks', () => ({ @@ -33,9 +39,13 @@ jest.mock('@holi/core/auth/loginState', () => ({ const mockInitRegistrationFlow = initRegistrationFlow as jest.Mock const mockGetVerificationFlowFromRegistration = getVerificationFlowFromRegistration as jest.Mock +const mockDoBrowserLogin = doBrowserLogin as jest.Mock +const mockDoLogin = doLogin as jest.Mock jest.mock('@holi/core/auth/helpers/auth', () => ({ initRegistrationFlow: jest.fn(), getVerificationFlowFromRegistration: jest.fn(), + doBrowserLogin: jest.fn(), + doLogin: jest.fn(), })) const mockSetVerificationFlowData = setVerificationFlowData as unknown as jest.Mock @@ -48,7 +58,6 @@ jest.mock('@holi/core/auth/helpers/sdk', () => ({ newKratosSdk: jest.fn(), })) -const mockClearGuestMode = clearGuestMode as jest.Mock const mockStoreGuestMode = storeGuestMode as jest.Mock jest.mock('@holi/core/screens/onboarding/helpers/guestModeAsyncStore', () => ({ clearGuestMode: jest.fn(), @@ -165,7 +174,7 @@ describe('CreateAccount', () => { it('should clear guest mode', async () => { await submitForm() - expect(mockClearGuestMode).toHaveBeenCalled() + expect(mockDoLogin).toHaveBeenCalled() }) it('should handle misconfiguration', async () => { @@ -206,7 +215,7 @@ describe('CreateAccount', () => { await submitForm() - expect(navigate).toHaveBeenCalledWith('someUrl') + expect(mockDoBrowserLogin).toHaveBeenCalledWith('someUrl', registrationFlow) }) it('should set verification flow data', async () => { @@ -218,7 +227,7 @@ describe('CreateAccount', () => { it('should set the login state', async () => { await submitForm() - expect(mockSetLoginStateLoggedIn).toHaveBeenCalledWith(registrationResponse) + expect(mockDoLogin).toHaveBeenCalledWith(expect.any(ApolloClient), registrationResponse) }) it('should call onRegister callback', async () => { diff --git a/jest.config.cjs b/jest.config.cjs index 8a2a3b4a4f..a9f78e1074 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -9,7 +9,7 @@ module.exports = { }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], modulePathIgnorePatterns: ['e2e', 'testData', 'mocks.ts', 'TestBed.tsx', 'testutils.ts'], - testPathIgnorePatterns: ['/node_modules/', '__tests__/helpers'], + testPathIgnorePatterns: ['/node_modules/', '__tests__/helpers.ts', '__tests__/helpers/.*'], moduleNameMapper: { '\\.(css|scss)$': '<rootDir>/jest.styleMock.cjs', // Force module uuid to resolve with the CJS entry point, because Jest does not support package.json.exports. See https://github.com/uuidjs/uuid/issues/451 -- GitLab