Open Fusekki opened 3 years ago
@staffordp You can ignore the WARN
.
The error message
AuthSdkError: OAuth flow timed out
does like some mock is missing, can you provide any test case that fails, then I can look into the issue you have.
Looks like this one produced the error a minute or two after it reported success:
it('should perform an external redirect to domain if userDetails is something and rolename is something', fakeAsync(() => {
spyOn(authService.authClient.token, 'getWithoutPrompt').and.callFake(() => {
return new Promise(resolve => resolve(null));
});
spyOn(authService, 'resetPasswordAttempts').and.callFake(() => {
return Promise.resolve(CONFIG.clearPasswordAttemptResponse);
});
spyOn(userPreferencesService, 'getPreference').and.callFake(
(): Observable<any> => {
return of(configNotLocal.something);
}
);
const spy: jasmine.Spy = spyOn(router, 'navigate');
moveSharedService.updateData(usersDetails[2]);
fixture.detectChanges();
fixture.ngZone.run(() => { // Prevent "Navigation triggered outside Angular zone" warning
component.onLoginResponse(CONFIG.mockedwidgetResponse);
tick(500);
expect(spy).toHaveBeenCalledWith(['/externalRedirect',
Object({ externalUrl: 'https://somewebsite/' }) ],
Object({ skipLocationChange: true }));
});
}));
I also noticed, I get intermittent failures on this test:
it('call the store cookies on a OnWidget response success', fakeAsync (() => {
console.info('test', 8);
spyOn(authService, 'resetPasswordAttempts').and.callFake(() => {
return Promise.resolve(CONFIG.clearPasswordAttemptResponse);
});
spyOn(authService.authClient.token, 'getWithoutPrompt').and.callFake(() => {
return new Promise(resolve => resolve(null));
});
const spy = spyOn(cookieService, 'set').and.callThrough();
moveSharedService.updateData(usersDetails[1]);
fixture.detectChanges();
fixture.ngZone.run(() => { // Prevent " triggered outside Angular zone" warning
component.onLoginResponse(CONFIG.mockedwidgetResponse);
});
tick(500);
expect(spy).toHaveBeenCalledTimes(3);
}));
Error I receive is
Error: Cannot make XHRs from within a fake async test. Request URL: https://cartus.oktapreview.com/oauth2/auspye2nuzSGJ0Kje0h7/.well-known/openid-configuration
error properties: Object({ longStack: 'Error: Cannot make XHRs from within a fake async test. Request URL: https://cartus.oktapreview.com/oauth2/auspye2nuzSGJ0Kje0h7/.well-known/openid-configuration
at FakeAsyncTestZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.FakeAsyncTestZoneSpec.onScheduleTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:1334:1)
But usually it passes fine. I suspect this code may be causing the failure and my mock of it, but not sure:
this.authSvc.authClient.tokenManager.setTokens(
{accessToken: res.tokens.idToken,
idToken: res.tokens.accessToken}
);
mocked client:
mockedOktaClient: {
signInWithCredentials() {
return new Promise(resolve => resolve( CONFIG.mockedAuthToken.transaction));
},
token: {
async getWithoutPrompt(): Promise<any> {
return new Promise(resolve => resolve( CONFIG.oktaToken ));
},
async getUserInfo() {
return CONFIG.getUserDetails;
}
},
async revokeAccessToken() {
},
async signOut() {
return;
},
closeSession() {
return Promise.resolve(true);
},
isAuthenticated() {
return Promise.resolve(true);
},
tokenManager: {
add(tokenType, token) {
return [
CONFIG.validationToken
];
},
setTokens() {}
},
async updateAuthState() {
return Promise.resolve({
isPending: false,
isAuthenticated: true,
accessToken: accessToken,
idToken: idToken,
error: ''
});
},
authStateManager: {
async updateAuthState() {
return Promise.resolve({
isPending: false,
isAuthenticated: true,
accessToken: accessToken,
idToken: idToken,
error: ''
});
},
},
},
Actually, I am not sure if this library can even be mocked any more. I've tried using both
{ provide: OktaAuth, useValue: CONFIG.mockedOktaClient },
{ provide: OktaAuth, useClass: CONFIG.mockedOktaStub },
and neither seem to work. Has anyone had success with this for testing via Jasmine?
@staffordp I'm not sure about your last problem (not being able to mock), but the earlier problems may be the result of the "autoRenew" feature, which runs in the background to renew tokens. This will attempt to hit XHR and update auth state. You can disable this feature by setting autoRenew
to false
tokenManager: {
autoRenew: false
}
@aakashyadav-okta
I don't get the XHR error any more after ensuring I callFake() on every function call for each test. However, I am still experiencing this quite repeatedly:
ERROR: AuthSdkError: OAuth flow timed out
AuthSdkError: OAuth flow timed out
at http://localhost:9876/_karma_webpack_/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js:339:3557
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:391:1)
at ProxyZoneSpec.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.onInvokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:339:1)
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:390:1)
at Object.onInvokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:273:1)
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:390:1)
at Object.onInvokeTask (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/fesm2015/core.js:39680:1)
at ZoneDelegate.invokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:390:1)
at Zone.runTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:168:1)
at invokeTask (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:465:1)
@staffordp In version 4.6 we did add a new feature, which is to use fetch
instead of XHR, if it is available. This did cause some problems in tests for us as well. The quickest solution is to set window.fetch = null
in your test. window.fetch
can also be mocked.
I tried doing a quick upgrade to 4.6 and it blew a ton of my tests away. I think I'll stick with working on 4.5 for now since I am no longer receiving the XHR errors. The only one I see now is below and it's very intermittent. Usually pops up at the end of running the tests:
ERROR: AuthSdkError: OAuth flow timed out AuthSdkError: OAuth flow timed out at http://localhost:9876/_karma_webpack_/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js:339:3557
@staffordp The OAuth flow timed out error is often seen when calling token.getWithoutPrompt
which opens an iframe and waits for a message of success or failure from the embedded page. This method is called when calling token.renew
. It could happen automatically if tokenManager.autoRenew
is not set to false
@aaronbrodersen-okta As of version 3.x, was autoRenew defaulted to true? or false?
I also set autoRenew: false in the config and I still get this error:
ERROR: AuthSdkError: OAuth flow timed out
AuthSdkError: OAuth flow timed out
at http://localhost:9876/_karma_webpack_/node_modules/@okta/okta-auth-js/dist/okta-auth-js.umd.js:339:3557
My config:
this.authClient = new OktaAuth({
clientId: this.appConfig.getConfig('oktaClientId').toString(),
issuer: this.appConfig.getConfig('oktaUrl').toString(),
redirectUri: this.appConfig.getConfig('oktaRedirectUri').toString(),
postLogoutRedirectUri: this.appConfig.getConfig('oktaRedirectUri').toString(),
tokenManager: {
storage: 'sessionStorage',
autoRenew: false
},
});
@staffordp The error is thrown here. The post message listener is added when tokens are being retrieved by iframe or popup window. Most likely case is iframe due to token renewal.
If the error is happening in a test, you could add a spy/mock to authClient.token.getWithoutPrompt
to throw immediately. Then you should see which piece of code is calling it.
@aaronbrodersen-okta Thanks. I have been doing the spy callFake for each test that includes a call to authClient.token.getWithoutPrompt. I am still progressing through it...
@aaronbrodersen-okta Noticed a few of the tests had leaks that were calling authClient.token.getWithoutPrompt and were not being spied upon with a callFake return. After plugging those leaks, I've seen the error message disappear. Am still running tests continually to verify nothing is left open, but appears to be fine at this point. Am still curious if anyone has been able to successfully mock the library either with a stub or a mock with useClass or useValue for the providers. As it is, I am not including the OAuth provider in the spec file.
I've noticed an additional issue in attempting to Spy on all functions in the specs.
I have noticed issues with callFake on closeSession() calls.
In my beforeEach segment, I have the following to fake the call:
spyOn(authService.authClient, 'closeSession').and.callFake(() => {
return new Promise<any>(resolve => resolve(null));
});
I've noticed when the first test runs and closeSession is called, no network call is attempted in the network calls debug page of Chrome. However, subsequent calls to this method in different tests using this same spec with the same spyOn above, I am seeing network calls:
From the image, it appears it is not using the CallFake method. Does anyone know a fix for this? I'd rather avoid unnecessary network calls for UTs.
@staffordp /sessions/me
is part of our sessions api. It is not called internally by the okta-auth-js
SDK. Possibly you have some code calling session.get
or session.exists
? This piece of code:
async getUserInfo() {
return CONFIG.getUserDetails;
}
hints that getUserInfo
may called. Internally this calls. /sessions/me
.
Back to your original question. Why is it hitting live endpoints? Why is it executing any Okta logic at all?
Is the object mocked or not mocked? If OktaAuth
is fully mocked, including the constructor, then it should not even try to hit any live endpoints; there is no Okta logic involved. This is the recommended approach. You don't need to TEST Okta AuthJS, you only need to mock the parts of the API you are using and verify it is being called correctly.
However if a live AuthJS instance is used, with some methods spied/mocked then the constructor will run and this is where the config is applied. So IF you want to use a live instance of okta-auth-js, with some methods spied/mocked, be sure to set tokenManager.autoRenew to false
to prevent background token logic. I think this is the likely source of the issue you are seeing.
By mocking the object completely (or by setting tokenManager.autoRenew
config), you should be able to avoid any attempts at network requests.
However, in the cases where you DO want to mock network responses, then I think the most likely reason code would be hitting live endpoints (which were otherwise mocked) is because it ended prematurely. Be sure to mark the test as async
and wait for all expected network calls to complete before resolving the test as successful. Time-dependent logic is usually handled best by mocking the clock using jasmine
, jest
, sinon
or some other testing library.
I'm trying to mock the login in cypress. But token.getWithoutPrompt() is throwing OAuthError. Does anyone have any idea about this?
Currently we need something similar for our application as well. Is there any solution to mock okta auth out for e2e tests?
I am currently working on an app using Angular 8 with the okta-auth-js library version 4.5.
Previously, in the 3.x and earlier, I was easily able to mock the okta library, however, with this one I am facing difficulties. Here is the current mock I am trying to use:
And in the spec.ts I am doing this:
Yet when trying to implement tests for this component, I am getting intermittent failures. Sometimes, I get a
WARN: '[okta-auth-sdk] WARN: updateAuthState is an asynchronous method with no return, please subscribe to the latest authState update with authStateManager.subscribe(handler) method before calling updateAuthState.'
or
or the tests just fail. Anyone had better success with it? I can post more of the file if needed.