我如何测试 locationStrategy.onPopState?

How can I test locationStrategy.onPopState?

我需要测试我的功能,但我遇到了困难。

我无法做到100%的覆盖率,我的难点在于通过函数onPopState调用的函数history.pushState。

有人可以帮助我吗?

    // This line is never being covered by my tests
    this.locationStrategy.onPopState(() => {
                history.pushState(null, null, url);
    });

我的服务代码:

    export class MyService {
        constructor(private readonly locationStrategy: LocationStrategy) { }
     
        blockNavigator(url: string) {
            history.pushState(null, null, urlAtual);
     
            // This line is never being covered by my tests
            this.locationStrategy.onPopState(() => {
                history.pushState(null, null, url);
            });
        }
    }

我的服务测试代码:

    describe('MyService ', () => {
        let myService: MyService;
        let locationStrategyMock: LocationStrategy;
    
    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                BloqueioNavegacaoService,
                {
                    provide: LocationStrategy,
                    useValue: jasmine.createSpyObj('LocationStrategy', ['onPopState'])
                }
            ]
        });
    
        myService = getTestBed().inject(MyService);
        locationStrategyMock = getTestBed().inject(LocationStrategy);
    });
    
    
    describe('Methods:', () => {    
        it('.....', () => {
            spyOn(myService , 'blockNavigator').and.callThrough();
    
            locationStrategyMock.onPopState = jasmine.createSpy()
                .and.callFake(() => {
                    // window.history.pushState(null, null, 'url');
                });
    
            myService.blockNavigator(url);
    
            expect(myService.blockNavigator).toHaveBeenCalledTimes(1);
            expect(window.history.state).toBeNull();
            expect(window.history.length).toBeGreaterThanOrEqual(0);
        });
    });

我认为您可以利用 .calls.mostRecent().args[0] 获取函数参数的句柄并显式调用该函数然后断言。

看看下面,还有评论。

    describe('MyService ', () => {
        let myService: MyService;
        let locationStrategyMock: LocationStrategy;
        // Add this line
        let mockLocationStrategy: jasmine.SpyObj<LocationStrategy>;
    
    beforeEach(() => {
        // Add this line
        mockLocationStrategy = jasmine.createSpyObj('LocationStrategy', ['onPopState']);
        TestBed.configureTestingModule({
            providers: [
                BloqueioNavegacaoService,
                {
                    provide: LocationStrategy,
                    // change useValue here
                    useValue: mockLocationStrategy
                }
            ]
        });
    
        myService = getTestBed().inject(MyService);
        locationStrategyMock = getTestBed().inject(LocationStrategy);
    });
    
    
    describe('Methods:', () => {    
        it('.....', () => {
            // This line is not needed, we call it explicitly
            // spyOn(myService , 'blockNavigator').and.callThrough();
    
       
            myService.blockNavigator(url);
            // This line is not needed, we call it explicitly (asserting nothing)
            // expect(myService.blockNavigator).toHaveBeenCalledTimes(1);
            
           // get a handle of the function (first argument) of onPopState
           // when it is called (i.e. () => {
                // history.pushState(null, null, url);
           // }
            const callBackFunction = mockLocationStrategy.onPopState.calls.mostRecent().args[0];
            // Call the function
            callBackFunction();
            // Hopefully the bottom assertions work
            expect(window.history.state).toBeNull();
            expect(window.history.length).toBeGreaterThanOrEqual(0);
        });
    });