I'm using ng2-idle to auto logout users after a period of time. I initialise it in my appComponent constructor:
import {Idle, DEFAULT_INTERRUPTSOURCES} from '@ng-idle/core';
export class AppComponent {
constructor(
private idle:Idle) {
idle.setIdle(21600);
idle.setTimeout(1);
idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
idle.onTimeout.subscribe(() => { this.logout(); });
};
Upon successful login I start it up in my LoginComponent using this.idle.watch()
(Idle is injected into the constructor).
This all works fine but when I go to run my protractor tests they timeout, I think because protractor is left waiting for the timeout to end which will take a while since I set ng2-idle to 6 hours!
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
If I don't initialise using Idle.watch()
then the tests run.
What I want to do is to set Idle.stop();
in the onPrepare
block in my protractor config file and reset it to Idle.watch();
after the tests are complete in my onComplete
block.
I have tried var idle = require('@ng-idle/core');
in the protractor conf file but it throws me back the following:
ReferenceError: document is not defined
So how can I require the ng2-idle module in protractors config file?
I cannot provide you a solution for the question you asked. But I will provide you a different approach to solve this problem. While setting up Protractor for my team, I encountered the same issue after implementing a session timeout strategy using ng-idle. After some heartburn on how to solve this, I realized Angular zone API can be used to resolve this. Here is my appcomponent with a solution. See runOutsideAngular and run methods in the zone.
Notice that all state changes are wrapped inside the run method. If not, the change detection will not work and none of the state fields including count down timer will not update UI.
This solution involves modifying the application which uses ng-idle as this cannot be done within Protractor in my current understanding.
this.ngZone.runOutsideAngular
@Component( {
selector : 'app-root',
templateUrl: './app.component.html',
styleUrls : [ './app.component.scss' ]
} )
export class AppComponent implements OnInit, OnDestroy{
idleState = 'Not started.';
idleStateTitle = '';
idleStateBtnText = '';
timedOut = false;
@ViewChild( DialogComponent ) dialog: DialogComponent;
constructor( private idle: Idle,
private locationStrategy: LocationStrategy,
private authUtils: AuthUtils,
private ngZone: NgZone ){
this.ngZone.runOutsideAngular(() => {
//Idle timer is set to 28 minutes and timeout count down timer will run for 2 minutes.
idle.setIdle( 28 * 60 );
idle.setTimeout( 120 );
});
//When idling starts display the dialog with count down timer
idle.onIdleStart.subscribe( () =>{
this.idleState = '';
this.idleStateTitle = 'Your session is about to expire.';
this.idleStateBtnText = 'Stay Logged In';
this.ngZone.run(() => this.dialog.show());
} );
//User stopped idling
idle.onIdleEnd.subscribe( () =>{
this.idleState = 'No longer idle.';
} );
//Show timeout warning two minutes before expiry
idle.onTimeoutWarning.subscribe( ( countdown ) =>{
this.ngZone.run(() => { this.idleState = 'Your session will time out in ' + countdown + ' seconds! '});
} );
//Session Timed out
idle.onTimeout.subscribe( () =>{
this.ngZone.run( () =>{
this.idleStateTitle = "Your session has expired.";
this.idleState = 'To Continue, log back in';
this.timedOut = true;
this.idleStateBtnText = 'Log in Again';
} );
});
}
reset(){
this.ngZone.runOutsideAngular(() => {
this.idle.watch();
});
this.ngZone.run( () =>{
this.idleState = 'Started.';
this.idleStateTitle = "";
this.idleStateBtnText = '';
this.timedOut = false;
});
}
title = 'Projects';
/**
* <p>Refresh Token by getting user token from the user service. Also reset the idle state timer here.</p>
*/
refreshToken(){
this.authUtils.refreshToken();
this.reset();
}
/**
* Handle timeout
*/
processTimeout(){
this.dialog.hide( null );
if( this.timedOut ){
AuthUtils.invalidateSession();
let origin = window.location.origin;
window.location.href = origin + this.locationStrategy.getBaseHref() + "?_="+ (Math.floor(Math.random() * 10000));
}
else{
this.refreshToken();
}
}
ngOnInit(): void{
this.reset();
}
ngOnDestroy(): void{
this.ngZone.runOutsideAngular(() =>{
this.idle.stop();
});
}
}
I had some partial success using browser.waitForAngularEnabled(false)
and disabling and enabling them within beforeEach
and afterEach
jasmine routines. but they were flaky and did not work for all tests.
Edit: I checked ng2-idle issue tracker and found there is an open defect for this here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With