@@ -18,6 +18,7 @@ import {
1818import { Passkey } from 'fxa-auth-client/browser' ;
1919import { AppContext } from '../../../models' ;
2020import { mockAppContext } from '../../../models/mocks' ;
21+ import { AuthUiErrors } from '../../../lib/auth-errors/auth-errors' ;
2122import { mockAuthClient } from './mock' ;
2223import { LocationProvider } from '@reach/router' ;
2324
@@ -28,6 +29,10 @@ const mockAlertBar = {
2829 info : jest . fn ( ) ,
2930} ;
3031
32+ let mockAccount = {
33+ deletePasskey : jest . fn ( ) ,
34+ } ;
35+
3136jest . mock ( '../../../lib/cache' , ( ) => ( {
3237 ...jest . requireActual ( '../../../lib/cache' ) ,
3338 JwtTokenCache : {
@@ -42,6 +47,7 @@ jest.mock('../../../models', () => ({
4247 ...jest . requireActual ( '../../../models' ) ,
4348 useAuthClient : ( ) => mockAuthClient ,
4449 useAlertBar : ( ) => mockAlertBar ,
50+ useAccount : ( ) => mockAccount ,
4551} ) ) ;
4652
4753describe ( 'SubRow' , ( ) => {
@@ -280,22 +286,17 @@ describe('PasskeySubRow', () => {
280286 prfEnabled : true ,
281287 } ;
282288
283- const mockDeletePasskey = jest . fn ( ) ;
284-
285289 beforeEach ( ( ) => {
286- mockDeletePasskey . mockClear ( ) ;
290+ mockAccount . deletePasskey . mockClear ( ) ;
287291 mockAlertBar . success . mockClear ( ) ;
288292 mockAlertBar . error . mockClear ( ) ;
289293 } ) ;
290294
291- const renderPasskeySubRow = (
292- passkey : Passkey = mockPasskey ,
293- deletePasskey = mockDeletePasskey
294- ) => {
295+ const renderPasskeySubRow = ( passkey : Passkey = mockPasskey ) => {
295296 return render (
296297 < LocationProvider >
297298 < AppContext . Provider value = { mockAppContext ( ) } >
298- < PasskeySubRow passkey = { passkey } deletePasskey = { deletePasskey } />
299+ < PasskeySubRow passkey = { passkey } />
299300 </ AppContext . Provider >
300301 </ LocationProvider >
301302 ) ;
@@ -350,7 +351,7 @@ describe('PasskeySubRow', () => {
350351 } ) ;
351352
352353 it ( 'calls deletePasskey when confirm button is clicked' , async ( ) => {
353- mockDeletePasskey . mockResolvedValue ( undefined ) ;
354+ mockAccount . deletePasskey . mockResolvedValue ( undefined ) ;
354355 renderPasskeySubRow ( ) ;
355356
356357 const deleteButtons = screen . getAllByTitle ( / D e l e t e p a s s k e y / ) ;
@@ -361,13 +362,11 @@ describe('PasskeySubRow', () => {
361362 const confirmButton = screen . getByTestId ( 'confirm-delete-passkey-button' ) ;
362363 await userEvent . click ( confirmButton ) ;
363364
364- await waitFor ( ( ) => {
365- expect ( mockDeletePasskey ) . toHaveBeenCalledWith ( 'passkey-1' ) ;
366- } ) ;
365+ expect ( mockAccount . deletePasskey ) . toHaveBeenCalledWith ( 'passkey-1' ) ;
367366 } ) ;
368367
369368 it ( 'shows success banner when deletion succeeds' , async ( ) => {
370- mockDeletePasskey . mockResolvedValue ( undefined ) ;
369+ mockAccount . deletePasskey . mockResolvedValue ( undefined ) ;
371370 renderPasskeySubRow ( ) ;
372371
373372 const deleteButtons = screen . getAllByTitle ( / D e l e t e p a s s k e y / ) ;
@@ -389,8 +388,8 @@ describe('PasskeySubRow', () => {
389388 } ) ;
390389 } ) ;
391390
392- it ( 'shows error banner when deletion fails' , async ( ) => {
393- mockDeletePasskey . mockRejectedValue ( new Error ( 'Some error' ) ) ;
391+ it ( 'shows generic error banner when deletion fails with an unexpected error ' , async ( ) => {
392+ mockAccount . deletePasskey . mockRejectedValue ( new Error ( 'Some error' ) ) ;
394393 renderPasskeySubRow ( ) ;
395394
396395 const deleteButtons = screen . getAllByTitle ( / D e l e t e p a s s k e y / ) ;
@@ -413,4 +412,27 @@ describe('PasskeySubRow', () => {
413412 ) . not . toBeInTheDocument ( ) ;
414413 } ) ;
415414 } ) ;
415+
416+ it ( 'shows "Passkey not found" error when passkey no longer exists' , async ( ) => {
417+ mockAccount . deletePasskey . mockRejectedValue ( AuthUiErrors . PASSKEY_NOT_FOUND ) ;
418+ renderPasskeySubRow ( ) ;
419+
420+ const deleteButtons = screen . getAllByTitle ( / D e l e t e p a s s k e y / ) ;
421+ await userEvent . click ( deleteButtons [ 0 ] ) ;
422+
423+ expect ( await screen . findByText ( 'Delete your passkey?' ) ) . toBeInTheDocument ( ) ;
424+
425+ const confirmButton = screen . getByTestId ( 'confirm-delete-passkey-button' ) ;
426+ await userEvent . click ( confirmButton ) ;
427+
428+ await waitFor ( ( ) => {
429+ expect ( mockAlertBar . error ) . toHaveBeenCalledWith ( 'Passkey not found' ) ;
430+ } ) ;
431+
432+ await waitFor ( ( ) => {
433+ expect (
434+ screen . queryByText ( 'Delete your passkey?' )
435+ ) . not . toBeInTheDocument ( ) ;
436+ } ) ;
437+ } ) ;
416438} ) ;
0 commit comments