3

I'm pulling my hair out trying to get my tests working to no avail. I am getting:

"Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL."

On every test in the suite. Then if I try to manually put it outside of Angulars home zone with ngZone.RunOutsideAngular or even the fakeAsync/tick combo in Jasmine I'm not getting any further.

Ideally I'd just like to set the intervals tick to something small in the BeforeEach which contains my test bed, but I'm not having any luck. I'm hoping maybe someone can help.

The offending code called in ngOnInit looks like this (interval in code is 30 seconds which is greater than jasmines 5 second timeout default):

protected initAutoSave(interval: number): void {
    if (this.canAutoSave()) {
        Observable.interval(interval)
            .debounceTime(250)
            .takeUntil(this.ngUnsubscribe)
            .subscribe(() => {
                this.DoTheDangThang();
            });
    }
}

This code works, but it's making Jasmine's Async "Proxy Zone" throw fits. In fact since it's in ngOnInit it seems to be crashing the TestBed and breaking every test in the suite.

My TestBed looks like something like this (minus the obfuscated names):

describe('MyContainerComponent', () => {
beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [MyContainerComponent],
        schemas: [NO_ERRORS_SCHEMA],
        providers: [
            {provide: MyService, useValue: myServiceStub},
            {provide: MyStateService, useValue: myStateServiceStub},
            {provide: MyContainerService, useValue: myContainerServiceStub},
            {provide: OtherService, useValue: otherServiceStub},
            {provide: YetAnotherService, useValue: yetAnotherServiceStub},
            FormBuilder,
            {
                provide: ActivatedRoute, useClass: FakeActivatedRoute
            }],
        imports: [TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader, useClass: FakeTranslateLoader
            }
        })]
    })
        .compileComponents().then(() => {
        fixture = TestBed.createComponent(MyContainerComponent);
        component = fixture.componentInstance;
        //**************************************************************
        //Attempt to change interval so jasmine won't time-out         *
        //but this line is not being honored (am I doing it too late?).*
        component.autoSaveInterval = 100;                              *
        //**************************************************************

        component.translations = {
            'Lang.App.Hello': 'Lang.App.Hello',
        };

        component.model = new ContainerModel(<Component>MyContainerComponent, MyApp.lang.title);
        component.model.dataBag = {myItem: MyModelMock.mockMyModel()};

        fixture.detectChanges();

        translateService = fixture.debugElement.injector.get(TranslateService);
        containerService = fixture.debugElement.injector.get(ContainerService);
        stateService = fixture.debugElement.injector.get(ContainerStateService);
        myThingService = fixture.debugElement.injector.get(MyThingService);
        translateService.use('en');
    }).catch((error) => {
        console.log('error in MyContainerComponent');
        console.log(error.message);
        console.log(error.stack);
    });
}));

Like I said above, I was hoping I could set the autoSaveInterval to something small in the test bed as not to cause jasmine to time-out, but I'm not having much luck and still getting the timeout error.

Tried fakeAsync\tick with no luck too, but would prefer just to set the interval lower in testbed sut if that can fix it. I suspect I'm just setting it in the wrong place however.

P.S. Setting jasmine.DEFAULT_TIMOUT_INTERVAL to 30 seconds isn't very realistic in this scenario due to number of tests in suite.

Any ideas?

iHazCode
  • 622
  • 4
  • 15
  • 2
    Have a look at the `VirtualTimeScheduler` - see [this answer](https://stackoverflow.com/a/43108109/6680611). – cartant Jan 26 '18 at 01:23
  • 1
    BTW, if you're able to use it to solve your problem, please add a [self answer](https://stackoverflow.com/help/self-answer). – cartant Jan 26 '18 at 01:46
  • Absolutely... I've been trying but it's driving me nuts. I've looked at the self timer, but I guess I'm REALLY wondering if anyone knows a way I can change the interval at the time of the fixture creation. Sometime before the ngOnInit fires so that it can just run, but maybe for only a tenth of a second or so. – iHazCode Jan 26 '18 at 01:52
  • That link seems helpful, but I specifically am trying to determine where this can go within my beforeEach that sets up my TestBed and calls detectChanges/onInit. It seems like the interval is not being honored, or is being set too late where I have it in the code above. Any help or suggestion would be appreciated. – iHazCode Jan 26 '18 at 04:41
  • Still hoping to get more feedback on this, but in the meantime I got the tests running by manually flushing the periodic task queue after the detectChanges runs. However I still want to write a few tests around the actual interval callback and the fakeAsync zone and tick are causing problems. – iHazCode Jan 27 '18 at 18:23
  • It's likely that `fakeAsync` won't help with an RxJS `interval` for the same reason as [this](https://stackoverflow.com/a/48264151/6680611). – cartant Jan 27 '18 at 22:10

0 Answers0