@@ -19,6 +19,33 @@ import Registration from '@salesforce/retail-react-app/app/pages/registration'
1919import ResetPassword from '@salesforce/retail-react-app/app/pages/reset-password'
2020import mockConfig from '@salesforce/retail-react-app/config/mocks/default'
2121import { mockedRegisteredCustomer } from '@salesforce/retail-react-app/app/mocks/mock-data'
22+ import { getConfig } from '@salesforce/pwa-kit-runtime/utils/ssr-config'
23+
24+ // Mock getConfig for passkey tests
25+ jest . mock ( '@salesforce/pwa-kit-runtime/utils/ssr-config' , ( ) => ( {
26+ getConfig : jest . fn ( )
27+ } ) )
28+
29+ // Mock Commerce SDK Auth Helpers
30+ const mockStartWebauthnAuthentication = jest . fn ( )
31+ const mockFinishWebauthnAuthentication = jest . fn ( )
32+
33+ jest . mock ( '@salesforce/commerce-sdk-react' , ( ) => {
34+ const actual = jest . requireActual ( '@salesforce/commerce-sdk-react' )
35+ return {
36+ ...actual ,
37+ useAuthHelper : ( helperType ) => {
38+ if ( helperType === actual . AuthHelpers . StartWebauthnAuthentication ) {
39+ return { mutateAsync : mockStartWebauthnAuthentication }
40+ }
41+ if ( helperType === actual . AuthHelpers . FinishWebauthnAuthentication ) {
42+ return { mutateAsync : mockFinishWebauthnAuthentication }
43+ }
44+ // Return actual for other helper types
45+ return actual . useAuthHelper ( helperType )
46+ }
47+ }
48+ } )
2249
2350const mockMergedBasket = {
2451 basketId : 'a10ff320829cb0eef93ca5310a' ,
@@ -53,6 +80,8 @@ const MockedComponent = () => {
5380// Set up and clean up
5481beforeEach ( ( ) => {
5582 jest . resetModules ( )
83+ // Setup getConfig mock with default config for all tests
84+ getConfig . mockReturnValue ( mockConfig )
5685 global . server . use (
5786 rest . post ( '*/customers' , ( req , res , ctx ) => {
5887 return res ( ctx . delay ( 0 ) , ctx . status ( 200 ) , ctx . json ( mockedRegisteredCustomer ) )
@@ -269,14 +298,17 @@ describe('Error while logging in', function () {
269298 } )
270299} )
271300describe ( 'Passkey login' , ( ) => {
272- let mockStartWebauthnAuthentication
273- let mockFinishWebauthnAuthentication
274301 let mockCredentialsGet
275302 let mockPublicKeyCredential
276303
277304 beforeEach ( ( ) => {
278- // Mock WebAuthn API
279- mockCredentialsGet = jest . fn ( )
305+ // Clear all mocks
306+ jest . clearAllMocks ( )
307+ mockStartWebauthnAuthentication . mockClear ( )
308+ mockFinishWebauthnAuthentication . mockClear ( )
309+
310+ // Mock WebAuthn API - default to never resolving (simulating no user action)
311+ mockCredentialsGet = jest . fn ( ) . mockImplementation ( ( ) => new Promise ( ( ) => { } ) )
280312 mockPublicKeyCredential = {
281313 parseRequestOptionsFromJSON : jest . fn ( ) ,
282314 isConditionalMediationAvailable : jest . fn ( ) . mockResolvedValue ( true ) ,
@@ -291,6 +323,26 @@ describe('Passkey login', () => {
291323
292324 // Clear localStorage
293325 localStorage . clear ( )
326+
327+ // Setup mock responses for auth helpers
328+ mockStartWebauthnAuthentication . mockResolvedValue ( {
329+ publicKey : {
330+ challenge : 'mock-challenge-data' ,
331+ rpId : 'example.com' ,
332+ allowCredentials : [ ] ,
333+ timeout : 60000
334+ }
335+ } )
336+
337+ mockFinishWebauthnAuthentication . mockResolvedValue ( {
338+ customer_id : 'customerid_passkey' ,
339+ access_token :
340+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXQiOiJHVUlEIiwic2NwIjoic2ZjYy5zaG9wcGVyLW15YWNjb3VudC5iYXNrZXRzIHNmY2Muc2hvcHBlci1teWFjY291bnQuYWRkcmVzc2VzIHNmY2Muc2hvcHBlci1wcm9kdWN0cyBzZmNjLnNob3BwZXItZGlzY292ZXJ5LXNlYXJjaCBzZmNjLnNob3BwZXItbXlhY2NvdW50LnJ3IHNmY2Muc2hvcHBlci1teWFjY291bnQucGF5bWVudGluc3RydW1lbnRzIHNmY2Muc2hvcHBlci1jdXN0b21lcnMubG9naW4gc2ZjYy5zaG9wcGVyLWV4cGVyaWVuY2Ugc2ZjYy5zaG9wcGVyLW15YWNjb3VudC5vcmRlcnMgc2ZjYy5zaG9wcGVyLWN1c3RvbWVycy5yZWdpc3RlciBzZmNjLnNob3BwZXItYmFza2V0cy1vcmRlcnMgc2ZjYy5zaG9wcGVyLW15YWNjb3VudC5hZGRyZXNzZXMucncgc2ZjYy5zaG9wcGVyLW15YWNjb3VudC5wcm9kdWN0bGlzdHMucncgc2ZjYy5zaG9wcGVyLXByb2R1Y3RsaXN0cyBzZmNjLnNob3BwZXItcHJvbW90aW9ucyBzZmNjLnNob3BwZXItYmFza2V0cy1vcmRlcnMucncgc2ZjYy5zaG9wcGVyLW15YWNjb3VudC5wYXltZW50aW5zdHJ1bWVudHMucncgc2ZjYy5zaG9wcGVyLWdpZnQtY2VydGlmaWNhdGVzIHNmY2Muc2hvcHBlci1wcm9kdWN0LXNlYXJjaCBzZmNjLnNob3BwZXItbXlhY2NvdW50LnByb2R1Y3RsaXN0cyBzZmNjLnNob3BwZXItY2F0ZWdvcmllcyBzZmNjLnNob3BwZXItbXlhY2NvdW50Iiwic3ViIjoiY2Mtc2xhczo6enpyZl8wMDE6OnNjaWQ6YzljNDViZmQtMGVkMy00YWEyLTk5NzEtNDBmODg5NjJiODM2Ojp1c2lkOjhlODgzOTczLTY4ZWItNDFmZS1hM2M1LTc1NjIzMjY1MmZmNSIsImN0eCI6InNsYXMiLCJpc3MiOiJzbGFzL3Byb2QvenpyZl8wMDEiLCJpc3QiOjEsImF1ZCI6ImNvbW1lcmNlY2xvdWQvcHJvZC96enJmXzAwMSIsIm5iZiI6MTY3ODgzNDI3MSwic3R5IjoiVXNlciIsImlzYiI6InVpZG86ZWNvbTo6dXBuOmtldjVAdGVzdC5jb206OnVpZG46a2V2aW4gaGU6OmdjaWQ6YWJtZXMybWJrM2xYa1JsSEZKd0dZWWt1eEo6OnJjaWQ6YWJVTXNhdnBEOVk2alcwMGRpMlNqeEdDTVU6OmNoaWQ6UmVmQXJjaEdsb2JhbCIsImV4cCI6MjY3ODgzNjEwMSwiaWF0IjoxNjc4ODM0MzAxLCJqdGkiOiJDMkM0ODU2MjAxODYwLTE4OTA2Nzg5MDM0ODA1ODMyNTcwNjY2NTQyIn0._tUrxeXdFYPj6ZoY-GILFRd3-aD1RGPkZX6TqHeS494' ,
341+ refresh_token : 'testrefeshtoken_passkey' ,
342+ usid : 'testusid_passkey' ,
343+ enc_user_id : 'testEncUserId_passkey' ,
344+ id_token : 'testIdToken_passkey'
345+ } )
294346 } )
295347
296348 afterEach ( ( ) => {
@@ -423,10 +475,18 @@ describe('Passkey login', () => {
423475 await user . type ( screen . getByLabelText ( 'Email' ) , 'test@salesforce.com' )
424476 await user . click ( screen . getByRole ( 'button' , { name : / s i g n i n / i} ) )
425477
426- // Should redirect to account page after successful passkey login
478+ // Should trigger passkey authentication with credentials.get
427479 await waitFor (
428480 ( ) => {
429- expect ( mockFinishWebauthnAuthentication ) . toHaveBeenCalled ( )
481+ expect ( mockCredentialsGet ) . toHaveBeenCalled ( )
482+ } ,
483+ { timeout : 5000 }
484+ )
485+
486+ // After successful passkey login, should redirect to account page
487+ await waitFor (
488+ ( ) => {
489+ expect ( window . location . pathname ) . toBe ( '/uk/en-GB/account' )
430490 } ,
431491 { timeout : 5000 }
432492 )
@@ -441,6 +501,12 @@ describe('Passkey login', () => {
441501 }
442502 }
443503
504+ // Override getConfig to return config with passkey disabled
505+ getConfig . mockReturnValue ( {
506+ ...mockConfig ,
507+ app : mockAppConfig
508+ } )
509+
444510 renderWithProviders ( < MockedComponent /> , {
445511 wrapperProps : {
446512 siteAlias : 'uk' ,
@@ -454,8 +520,13 @@ describe('Passkey login', () => {
454520 expect ( screen . getByTestId ( 'login-page' ) ) . toBeInTheDocument ( )
455521 } )
456522
523+ // Give it a moment for any async effects to run
524+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) )
525+
457526 // Should not call credentials API when passkey is disabled
458527 expect ( mockCredentialsGet ) . not . toHaveBeenCalled ( )
528+ // Should not call auth helpers when passkey is disabled
529+ expect ( mockStartWebauthnAuthentication ) . not . toHaveBeenCalled ( )
459530 } )
460531
461532 test ( 'Handles passkey login cancellation gracefully' , async ( ) => {
0 commit comments