Skip to content

Commit 2e64f70

Browse files
committed
Refactor passkey registration and authentication error handling across components to standardize user feedback. Replace specific error messages with a generic "Something went wrong. Try again!" message. Update tests to reflect these changes and ensure consistent error handling in the UI.
1 parent 7c727b2 commit 2e64f70

File tree

14 files changed

+52
-139
lines changed

14 files changed

+52
-139
lines changed

packages/template-retail-react-app/app/components/passkey-registration-modal/index.jsx

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ import {useCurrentCustomer} from '@salesforce/retail-react-app/app/hooks/use-cur
3333
// Utils
3434
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
3535
import {arrayBufferToBase64Url} from '@salesforce/retail-react-app/app/utils/utils'
36-
import {getPasskeyRegistrationErrorMessage} from '@salesforce/retail-react-app/app/utils/auth-utils'
3736

3837
// SDK
3938
import {AuthHelpers, useAuthHelper} from '@salesforce/commerce-sdk-react'
4039

40+
// Constants
41+
import {API_ERROR_MESSAGE, INVALID_TOKEN_ERROR_MESSAGE} from '@salesforce/retail-react-app/app/constants'
42+
4143
/**
4244
* Modal for registering a new passkey with a nickname
4345
*/
@@ -75,9 +77,7 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
7577
setIsOtpAuthOpen(true)
7678
} catch (err) {
7779
// Set error message for the passkey registration modal
78-
setError(formatMessage(getPasskeyRegistrationErrorMessage(err)))
79-
// Re-throw the error to be handled by the OTP auth modal
80-
throw err
80+
setError(formatMessage(API_ERROR_MESSAGE))
8181
} finally {
8282
setIsLoading(false)
8383
}
@@ -105,18 +105,7 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
105105

106106
// Step 4: navigator.credentials.create() will show a browser/system prompt
107107
// This may appear to hang if the user doesn't interact with the prompt
108-
let credential
109-
try {
110-
credential = await navigator.credentials.create({
111-
publicKey
112-
})
113-
} catch (createError) {
114-
// Handle user cancellation or other errors from the WebAuthn API
115-
if (createError.name === 'NotAllowedError' || createError.name === 'AbortError') {
116-
throw new Error('Passkey registration was cancelled or timed out')
117-
}
118-
throw createError
119-
}
108+
const credential = await navigator.credentials.create({publicKey})
120109

121110
if (!credential) {
122111
throw new Error('Failed to create credential: user cancelled or operation failed')
@@ -159,10 +148,13 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
159148
return {success: true}
160149
} catch (err) {
161150
console.error('Error registering passkey:', err)
151+
const message = /Unauthorized/i.test(err.message)
152+
? formatMessage(INVALID_TOKEN_ERROR_MESSAGE)
153+
: formatMessage(API_ERROR_MESSAGE)
162154
// Return error result for OTP component to display
163155
return {
164156
success: false,
165-
error: formatMessage(getPasskeyRegistrationErrorMessage(err))
157+
error: message
166158
}
167159
} finally {
168160
setIsLoading(false)

packages/template-retail-react-app/app/components/passkey-registration-modal/index.test.js

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ describe('PasskeyRegistrationModal', () => {
223223
await user.click(registerButton)
224224

225225
await waitFor(() => {
226-
expect(screen.getByText(errorMessage)).toBeInTheDocument()
226+
expect(screen.getByText('Something went wrong. Try again!')).toBeInTheDocument()
227227
})
228228
})
229229

@@ -457,7 +457,7 @@ describe('PasskeyRegistrationModal', () => {
457457

458458
expect(result).toEqual({
459459
success: false,
460-
error: errorMessage
460+
error: 'Something went wrong. Try again!'
461461
})
462462

463463
// Verify modals are not closed on error
@@ -498,7 +498,7 @@ describe('PasskeyRegistrationModal', () => {
498498

499499
expect(result).toEqual({
500500
success: false,
501-
error: 'WebAuthn API not available in this browser'
501+
error: 'Something went wrong. Try again!'
502502
})
503503
})
504504

@@ -537,7 +537,7 @@ describe('PasskeyRegistrationModal', () => {
537537

538538
expect(result).toEqual({
539539
success: false,
540-
error: 'Passkey registration was cancelled or timed out'
540+
error: 'Something went wrong. Try again!'
541541
})
542542
})
543543

@@ -573,7 +573,7 @@ describe('PasskeyRegistrationModal', () => {
573573

574574
expect(result).toEqual({
575575
success: false,
576-
error: 'Failed to create credential: user cancelled or operation failed'
576+
error: 'Something went wrong. Try again!'
577577
})
578578
})
579579

@@ -622,7 +622,7 @@ describe('PasskeyRegistrationModal', () => {
622622

623623
expect(result).toEqual({
624624
success: false,
625-
error: errorMessage
625+
error: 'Something went wrong. Try again!'
626626
})
627627
})
628628

@@ -661,7 +661,34 @@ describe('PasskeyRegistrationModal', () => {
661661

662662
expect(result).toEqual({
663663
success: false,
664-
error: 'Passkey registration was cancelled or timed out'
664+
error: 'Something went wrong. Try again!'
665+
})
666+
})
667+
668+
test('returns INVALID_TOKEN_ERROR_MESSAGE when startWebauthnUserRegistration fails with Unauthorized', async () => {
669+
const otpCode = '12345678'
670+
671+
mockStartWebauthnRegistration.mockRejectedValue(new Error('Unauthorized'))
672+
673+
const {user} = renderWithProviders(
674+
<PasskeyRegistrationModal isOpen={true} onClose={mockOnClose} />,
675+
{
676+
wrapperProps: {appConfig: mockConfig.app}
677+
}
678+
)
679+
680+
const registerButton = screen.getByText('Register Passkey')
681+
await user.click(registerButton)
682+
683+
await waitFor(() => {
684+
expect(otpVerificationHandler).toBeTruthy()
685+
})
686+
687+
const result = await otpVerificationHandler(otpCode)
688+
689+
expect(result).toEqual({
690+
success: false,
691+
error: 'Invalid token, please try again.'
665692
})
666693
})
667694
})

packages/template-retail-react-app/app/hooks/use-auth-modal.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,8 @@ export const AuthModal = ({
239239
setCurrentView(initialView)
240240
form.reset()
241241
// Prompt user to login without username (discoverable credentials)
242-
loginWithPasskey().catch((error) => {
243-
const message = formatMessage(getPasskeyAuthenticateErrorMessage(error))
244-
form.setError('global', {type: 'manual', message})
245-
console.error('Error authenticating passkey:', error)
242+
loginWithPasskey().catch(() => {
243+
form.setError('global', {type: 'manual', message:formatMessage(API_ERROR_MESSAGE)})
246244
})
247245
}
248246
}, [isOpen])

packages/template-retail-react-app/app/hooks/use-auth-modal.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ describe('Passkey login', () => {
816816
// Should show error - 401 error from WebAuthn API should be caught and converted to user-friendly message
817817
await waitFor(() => {
818818
expect(
819-
screen.getByText(/This feature is not currently available./i)
819+
screen.getByText(/Something went wrong. Try again!/i)
820820
).toBeInTheDocument()
821821
})
822822
})

packages/template-retail-react-app/app/hooks/use-passkey-login.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export const usePasskeyLogin = () => {
7171
if (error.name == 'NotAllowedError') {
7272
return
7373
}
74+
console.error('Error getting passkey credential from browser:', error)
7475
throw error
7576
}
7677

packages/template-retail-react-app/app/pages/login/index.jsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ import {isServer, noop} from '@salesforce/retail-react-app/app/utils/utils'
3434
import {
3535
getAuthorizePasswordlessErrorMessage,
3636
getLoginPasswordlessErrorMessage,
37-
getPasswordlessCallbackUrl,
38-
getPasskeyAuthenticateErrorMessage
37+
getPasswordlessCallbackUrl
3938
} from '@salesforce/retail-react-app/app/utils/auth-utils'
4039
import {getConfig} from '@salesforce/pwa-kit-runtime/utils/ssr-config'
4140
import useMultiSite from '@salesforce/retail-react-app/app/hooks/use-multi-site'
@@ -192,10 +191,8 @@ const Login = ({initialView = LOGIN_VIEW}) => {
192191
}, [isRegistered, redirectPath])
193192

194193
useEffect(() => {
195-
loginWithPasskey().catch((error) => {
196-
const message = formatMessage(getPasskeyAuthenticateErrorMessage(error))
197-
form.setError('global', {type: 'manual', message})
198-
console.error('Error authenticating passkey:', error)
194+
loginWithPasskey().catch(() => {
195+
form.setError('global', {type: 'manual', message: formatMessage(API_ERROR_MESSAGE)})
199196
})
200197
}, [])
201198

packages/template-retail-react-app/app/pages/login/index.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ describe('Passkey login', () => {
629629
// Should show error - 401 error from WebAuthn API should be caught and converted to user-friendly message
630630
await waitFor(() => {
631631
expect(
632-
screen.getByText(/This feature is not currently available./i)
632+
screen.getByText(/Something went wrong. Try again!/i)
633633
).toBeInTheDocument()
634634
})
635635
})

packages/template-retail-react-app/app/static/translations/compiled/en-GB.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,12 +2091,6 @@
20912091
"value": "Invalid token, please try again."
20922092
}
20932093
],
2094-
"global.error.passkey_feature_unavailable": [
2095-
{
2096-
"type": 0,
2097-
"value": "The passkey feature is currently unavailable"
2098-
}
2099-
],
21002094
"global.error.something_went_wrong": [
21012095
{
21022096
"type": 0,

packages/template-retail-react-app/app/static/translations/compiled/en-US.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,12 +2091,6 @@
20912091
"value": "Invalid token, please try again."
20922092
}
20932093
],
2094-
"global.error.passkey_feature_unavailable": [
2095-
{
2096-
"type": 0,
2097-
"value": "The passkey feature is currently unavailable"
2098-
}
2099-
],
21002094
"global.error.something_went_wrong": [
21012095
{
21022096
"type": 0,

packages/template-retail-react-app/app/static/translations/compiled/en-XA.json

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4347,20 +4347,6 @@
43474347
"value": "]"
43484348
}
43494349
],
4350-
"global.error.passkey_feature_unavailable": [
4351-
{
4352-
"type": 0,
4353-
"value": "["
4354-
},
4355-
{
4356-
"type": 0,
4357-
"value": "Ŧħḗḗ ƥȧȧşşķḗḗẏ ƒḗḗȧȧŧŭŭřḗḗ īş ƈŭŭřřḗḗƞŧŀẏ ŭŭƞȧȧṽȧȧīŀȧȧƀŀḗḗ"
4358-
},
4359-
{
4360-
"type": 0,
4361-
"value": "]"
4362-
}
4363-
],
43644350
"global.error.something_went_wrong": [
43654351
{
43664352
"type": 0,

0 commit comments

Comments
 (0)