'Angular jasmine how to spy an async spy method

I am new to writing test with async/await in angular. I have the following code. The service method is an async method. The test fails saying component.options.length is 0.

Can anyone please help me how to fix the error so the options has got the value i set in spy?

Thanks

spec.ts

spySideNavService = jasmine.createSpyObj('SideNavService', [], {
            setOrgUserDetails: () => {},
            loadMenus: () =>
                [
                    {
                        id: 'my-menu',
                        label: 'My Menu',
                        icon: 'far fa-envelope fa-2x',
                        url: 'url'
                    }
                ] as NavOption[]
        });
        
    describe('ngOnInit', () => {
        it('should add navigation options', () => {
            expect(component.options.length).toBeGreaterThan(0);
        });
    });

component:

ngOnInit(): void {
    this.options = await this.sideNavService.loadMenus();   
}
    

SideNavService:

async loadMenus(): Promise<NavOption[]> {
//logic
}

Tried answer given below but still not working:

describe('ngOnInit', () => {
    it('should add navigation options', fakeAsync(() => {
        // !! call tick(); to tell the test to resolve all promises
        // before coming to my expect line
        tick();
        expect(component.options.length).toBeGreaterThan(0);
    }));
});


Solution 1:[1]

You need to use fakeAsync/tick to control promises.

// !! add fakeAsync
it('should add navigation options', fakeAsync(() => {
            // !! call tick(); to tell the test to resolve all promises
            // before coming to my expect line
            // !! call ngOnInit
            component.ngOnInit();
            console.log(component.options);
            tick();
            console.log(component.options);
            expect(component.options.length).toBeGreaterThan(0);
        }));

Before, the test would go to the await line and go back to the test for the expect because the await is saying to do this later. Now with the tick, we are saying if they are any promises created, resolve them before moving forward.

Also, I think you're missing a Promise.resolve on loadMenus.

loadMenus: () => Promise.resolve(
                [
                    {
                        id: 'my-menu',
                        label: 'My Menu',
                        icon: 'far fa-envelope fa-2x',
                        url: 'url'
                    }
                ] as NavOption[])

I am thinking the Promise.resolve is required so it can be awaited.

edit I don't think the done callback will help you.

You can try using await fixture.whenStable() to wait for the promise(s). Try this:

describe('ngOnInit', () => {
    it('should add navigation options', async () => {
        component.ngOnInit();  
        await fixture.whenStable();
        expect(component.options.length).toBeGreaterThan(0);
    });
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1