@@ -16,7 +16,9 @@ import {
1616 expectEmailOfType ,
1717 expectHttpResponseToEqual ,
1818 expectToEqual ,
19+ FTConnectError ,
1920 frontRoutes ,
21+ ManagedFTConnectError ,
2022 noAgencyDashboards ,
2123 noEstablishmentDashboard ,
2224 queryParamsAsString ,
@@ -62,6 +64,7 @@ import { processEventsForEmailToBeSent } from "../../../../utils/processEventsFo
6264
6365describe ( "auth router" , ( ) => {
6466 const immersionDomain = "immersion.fr" ;
67+ const now = new Date ( ) ;
6568
6669 let authRoutesClient : HttpClient < AuthRoutes > ;
6770 let technicalRoutesClient : HttpClient < TechnicalRoutes > ;
@@ -99,7 +102,7 @@ describe("auth router", () => {
99102 technicalRoutes ,
100103 request ,
101104 ) ;
102- gateways . timeGateway . setNextDate ( new Date ( ) ) ;
105+ gateways . timeGateway . setNextDate ( now ) ;
103106 } ) ;
104107
105108 describe ( "user connexion flow" , ( ) => {
@@ -148,6 +151,7 @@ describe("auth router", () => {
148151 ) ;
149152
150153 gateways . proConnectOAuthGateway . setAccessTokenResponse ( {
154+ type : "proConnect" ,
151155 accessToken : proConnectToken ,
152156 idToken,
153157 expire : 1 ,
@@ -247,6 +251,7 @@ describe("auth router", () => {
247251 inMemoryUow . agencyRepository . agencies = [ toAgencyWithRights ( agency ) ] ;
248252
249253 gateways . proConnectOAuthGateway . setAccessTokenResponse ( {
254+ type : "proConnect" ,
250255 accessToken : proConnectToken ,
251256 expire : 1 ,
252257 idToken,
@@ -404,6 +409,208 @@ describe("auth router", () => {
404409 } ) ;
405410 } ) ;
406411
412+ describe ( "Right path with FT Connect" , ( ) => {
413+ const ftConnectAuthCode = "ft-connect-auth-code" ;
414+ const ftConnectAccessToken = "ft-connect-token" ;
415+ const ftConnectIdToken = "ft-connect-id-token" ;
416+ const ftConnectExternalId = "ft-connect-external-id" ;
417+ const conventionDraftId = "ft-connect-convention-draft-id" ;
418+
419+ describe ( displayRouteName ( authRoutes . initiateLoginByOAuth ) , ( ) => {
420+ it ( "redirects to FT Connect login and stores ongoing OAuth" , async ( ) => {
421+ const uuids = [ nonce , state ] ;
422+ uuidGenerator . new = ( ) => uuids . shift ( ) ?? "no-uuid-provided" ;
423+
424+ expectHttpResponseToEqual (
425+ await authRoutesClient . initiateLoginByOAuth ( {
426+ queryParams : {
427+ provider : "peConnect" ,
428+ redirectUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
429+ } ,
430+ } ) ,
431+ {
432+ body : { } ,
433+ status : 302 ,
434+ headers : {
435+ location : encodeURI (
436+ `https://fake-ft-connect-login-url?${ queryParamsAsString ( {
437+ nonce,
438+ state,
439+ } ) } `,
440+ ) ,
441+ } ,
442+ } ,
443+ ) ;
444+
445+ expectToEqual ( inMemoryUow . ongoingOAuthRepository . ongoingOAuths , [
446+ {
447+ provider : "peConnect" ,
448+ nonce,
449+ state,
450+ usedAt : null ,
451+ fromUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
452+ } ,
453+ ] ) ;
454+ } ) ;
455+ } ) ;
456+
457+ describe ( displayRouteName ( authRoutes . afterFTConnectOAuthLogin ) , ( ) => {
458+ it ( "redirects to convention immersion page with convention draft id" , async ( ) => {
459+ uuidGenerator . new = ( ) => conventionDraftId ;
460+ inMemoryUow . ongoingOAuthRepository . ongoingOAuths = [
461+ {
462+ provider : "peConnect" ,
463+ nonce,
464+ state,
465+ usedAt : null ,
466+ fromUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
467+ } ,
468+ ] ;
469+ gateways . ftConnectGateway . setAccessTokenResult ( {
470+ type : "ftConnect" ,
471+ accessToken : ftConnectAccessToken ,
472+ expire : 1 ,
473+ idToken : ftConnectIdToken ,
474+ payload : { nonce } ,
475+ } ) ;
476+ gateways . ftConnectGateway . setUser ( {
477+ isJobseeker : true ,
478+ firstName : "Jean" ,
479+ lastName : "Dupont" ,
480+ birthdate : "1990-01-01" ,
481+ peExternalId : ftConnectExternalId ,
482+ } ) ;
483+ gateways . ftConnectGateway . setAdvisors ( [
484+ {
485+ type : "PLACEMENT" ,
486+ firstName : "Alice" ,
487+ lastName : "Martin" ,
488+ email : "conseiller@francetravail.fr" ,
489+ } ,
490+ ] ) ;
491+
492+ const response = await authRoutesClient . afterFTConnectOAuthLogin ( {
493+ queryParams : {
494+ code : ftConnectAuthCode ,
495+ state,
496+ } ,
497+ } ) ;
498+
499+ expectHttpResponseToEqual ( response , {
500+ body : { } ,
501+ status : 302 ,
502+ headers : {
503+ location : `${ appConfig . immersionFacileBaseUrl } /${ frontRoutes . conventionImmersionRoute } ?conventionDraftId=${ conventionDraftId } ` ,
504+ } ,
505+ } ) ;
506+
507+ expectToEqual ( inMemoryUow . ongoingOAuthRepository . ongoingOAuths , [
508+ {
509+ provider : "peConnect" ,
510+ nonce,
511+ state,
512+ usedAt : now ,
513+ accessToken : ftConnectAccessToken ,
514+ fromUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
515+ } ,
516+ ] ) ;
517+ expectToEqual (
518+ inMemoryUow . conventionDraftRepository . conventionDrafts ,
519+ [
520+ {
521+ id : conventionDraftId ,
522+ internshipKind : "immersion" ,
523+ fromPeConnectedUser : true ,
524+ updatedAt : gateways . timeGateway . now ( ) . toISOString ( ) ,
525+ signatories : {
526+ beneficiary : {
527+ firstName : "Jean" ,
528+ lastName : "Dupont" ,
529+ birthdate : "1990-01-01" ,
530+ federatedIdentity : {
531+ provider : "peConnect" ,
532+ token : ftConnectExternalId ,
533+ } ,
534+ } ,
535+ } ,
536+ validators : {
537+ agencyCounsellor : {
538+ firstname : "Alice" ,
539+ lastname : "Martin" ,
540+ } ,
541+ } ,
542+ } ,
543+ ] ,
544+ ) ;
545+ } ) ;
546+
547+ it ( "redirects to managed FT Connect error page when FT Connect throws a managed error" , async ( ) => {
548+ inMemoryUow . ongoingOAuthRepository . ongoingOAuths = [
549+ {
550+ provider : "peConnect" ,
551+ nonce,
552+ state,
553+ usedAt : null ,
554+ fromUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
555+ } ,
556+ ] ;
557+ gateways . ftConnectGateway . getAccessToken = async ( ) => {
558+ throw new ManagedFTConnectError ( "peConnectNoAuthorisation" ) ;
559+ } ;
560+
561+ const response = await authRoutesClient . afterFTConnectOAuthLogin ( {
562+ queryParams : {
563+ code : ftConnectAuthCode ,
564+ state,
565+ } ,
566+ } ) ;
567+
568+ expectHttpResponseToEqual ( response , {
569+ body : { } ,
570+ status : 302 ,
571+ headers : {
572+ location : `${ appConfig . immersionFacileBaseUrl } /${ frontRoutes . error } ?kind=peConnectNoAuthorisation` ,
573+ } ,
574+ } ) ;
575+ } ) ;
576+
577+ it ( "redirects to raw FT Connect error page when FT Connect throws a raw error" , async ( ) => {
578+ const rawErrorTitle = "Erreur France Travail" ;
579+ const rawErrorMessage = "Le service France Travail est indisponible" ;
580+ inMemoryUow . ongoingOAuthRepository . ongoingOAuths = [
581+ {
582+ provider : "peConnect" ,
583+ nonce,
584+ state,
585+ usedAt : null ,
586+ fromUri : `/${ frontRoutes . conventionImmersionRoute } ` ,
587+ } ,
588+ ] ;
589+ gateways . ftConnectGateway . getAccessToken = async ( ) => {
590+ throw new FTConnectError ( rawErrorTitle , rawErrorMessage ) ;
591+ } ;
592+
593+ const response = await authRoutesClient . afterFTConnectOAuthLogin ( {
594+ queryParams : {
595+ code : ftConnectAuthCode ,
596+ state,
597+ } ,
598+ } ) ;
599+
600+ const { params } = decodeURIWithParams (
601+ response . headers . location as string ,
602+ ) ;
603+ expect ( response . headers . location ) . toContain (
604+ `${ appConfig . immersionFacileBaseUrl } /${ frontRoutes . error } ` ,
605+ ) ;
606+ expectToEqual ( params , {
607+ title : encodeURIComponent ( rawErrorTitle ) ,
608+ message : encodeURIComponent ( rawErrorMessage ) ,
609+ } ) ;
610+ } ) ;
611+ } ) ;
612+ } ) ;
613+
407614 describe ( `${ displayRouteName (
408615 authRoutes . getOAuthLogoutUrl ,
409616 ) } returns the logout url`, ( ) => {
0 commit comments