11import React from "react" ;
22import { render , screen , waitFor } from "@testing-library/react" ;
3- import OktaSecurity from "./OktaSecurity" ;
3+ import OktaSecurity , {
4+ transformAuthState ,
5+ resetSessionCheckCache ,
6+ } from "./OktaSecurity" ;
47import * as madieUtil from "@madie/madie-util" ;
8+ import { OktaAuth , toRelativeUrl } from "@okta/okta-auth-js" ;
59import { Security } from "@okta/okta-react" ;
6- import { toRelativeUrl } from "@okta/okta-auth-js" ;
710import { MADIE_TIMEOUT_RETURN_URL } from "../services/timeoutReturnUrl" ;
811
912// Mock dependencies
@@ -16,7 +19,7 @@ jest.mock("@okta/okta-react", () => ({
1619 ) ) ,
1720} ) ) ;
1821jest . mock ( "@okta/okta-auth-js" , ( ) => ( {
19- OktaAuth : jest . fn ( ) . mockImplementation ( ( ) => ( { } ) ) ,
22+ OktaAuth : jest . fn ( ) . mockImplementation ( ( config ) => ( { options : config } ) ) ,
2023 toRelativeUrl : jest . fn ( ( uri ) => uri ) ,
2124} ) ) ;
2225jest . mock ( "./../router/Router" , ( ) =>
@@ -93,6 +96,20 @@ describe("OktaSecurity", () => {
9396 redirectUri : "http://localhost:3000/login/callback" ,
9497 scopes : [ "openid" , "profile" , "email" ] ,
9598 } ) ;
99+ render ( < OktaSecurity /> ) ;
100+ await waitFor ( ( ) => expect ( OktaAuth ) . toHaveBeenCalled ( ) ) ;
101+
102+ const config = ( OktaAuth as unknown as jest . Mock ) . mock . calls [ 0 ] [ 0 ] ;
103+ expect ( config . tokenManager ) . toEqual ( {
104+ autoRenew : true ,
105+ storage : "localStorage" ,
106+ } ) ;
107+ expect ( config . services ) . toEqual ( {
108+ autoRenew : true ,
109+ syncStorage : true ,
110+ renewOnTabActivation : true ,
111+ tabInactivityDuration : 1800 ,
112+ } ) ;
96113
97114 sessionStorage . setItem ( MADIE_TIMEOUT_RETURN_URL , "/libraries" ) ;
98115 render ( < OktaSecurity /> ) ;
@@ -153,4 +170,71 @@ describe("OktaSecurity", () => {
153170 window . location . origin
154171 ) ;
155172 } ) ;
173+
174+ describe ( "transformAuthState" , ( ) => {
175+ const buildOktaAuth = ( existsMock : jest . Mock ) => ( {
176+ session : { exists : existsMock } ,
177+ } ) ;
178+
179+ beforeEach ( ( ) => {
180+ resetSessionCheckCache ( ) ;
181+ } ) ;
182+
183+ it ( "returns the auth state untouched when not authenticated, without a session check" , async ( ) => {
184+ const exists = jest . fn ( ) ;
185+ const authState = { isAuthenticated : false } ;
186+
187+ const result = await transformAuthState ( buildOktaAuth ( exists ) , authState ) ;
188+
189+ expect ( result . isAuthenticated ) . toBe ( false ) ;
190+ expect ( exists ) . not . toHaveBeenCalled ( ) ;
191+ } ) ;
192+
193+ it ( "keeps the user authenticated when the Okta session exists" , async ( ) => {
194+ const exists = jest . fn ( ) . mockResolvedValue ( true ) ;
195+ const authState = { isAuthenticated : true } ;
196+
197+ const result = await transformAuthState ( buildOktaAuth ( exists ) , authState ) ;
198+
199+ expect ( result . isAuthenticated ) . toBe ( true ) ;
200+ expect ( exists ) . toHaveBeenCalledTimes ( 1 ) ;
201+ } ) ;
202+
203+ it ( "trusts a recent successful session check instead of re-verifying" , async ( ) => {
204+ const exists = jest . fn ( ) . mockResolvedValue ( true ) ;
205+ const oktaAuth = buildOktaAuth ( exists ) ;
206+
207+ await transformAuthState ( oktaAuth , { isAuthenticated : true } ) ;
208+ const result = await transformAuthState ( oktaAuth , {
209+ isAuthenticated : true ,
210+ } ) ;
211+
212+ // second call within the TTL should not hit the network again
213+ expect ( exists ) . toHaveBeenCalledTimes ( 1 ) ;
214+ expect ( result . isAuthenticated ) . toBe ( true ) ;
215+ } ) ;
216+
217+ it ( "retries once before dropping auth when the session check fails transiently" , async ( ) => {
218+ const exists = jest
219+ . fn ( )
220+ . mockResolvedValueOnce ( false ) // transient failure
221+ . mockResolvedValueOnce ( true ) ; // retry succeeds
222+ const authState = { isAuthenticated : true } ;
223+
224+ const result = await transformAuthState ( buildOktaAuth ( exists ) , authState ) ;
225+
226+ expect ( exists ) . toHaveBeenCalledTimes ( 2 ) ;
227+ expect ( result . isAuthenticated ) . toBe ( true ) ;
228+ } ) ;
229+
230+ it ( "drops authentication when the Okta session is really gone" , async ( ) => {
231+ const exists = jest . fn ( ) . mockResolvedValue ( false ) ;
232+ const authState = { isAuthenticated : true } ;
233+
234+ const result = await transformAuthState ( buildOktaAuth ( exists ) , authState ) ;
235+
236+ expect ( exists ) . toHaveBeenCalledTimes ( 2 ) ;
237+ expect ( result . isAuthenticated ) . toBe ( false ) ;
238+ } ) ;
239+ } ) ;
156240} ) ;
0 commit comments