How can I make Protractor NOT wait for $timeout?

后端 未结 2 1710
有刺的猬
有刺的猬 2021-01-12 13:22

I\'m testing my angular application with Protractor. Once the user is logged in to my app, I set a $timeout to do some job in one hour (so if the user was logged-in in 13:00

相关标签:
2条回答
  • 2021-01-12 13:51

    The solution is to use interceptors and modify the http request which is getting timeout and set custom timeout to some milliseconds(your desired) to that http request so that after sometime long running http request will get closed(because of new timeout) and then you can test immediate response.

    This is working well and promising.

    0 讨论(0)
  • 2021-01-12 14:01

    The solution will be to flush active timeouts (as @MBielski mentioned it in comments), but original flush method itself is available only in anuglar-mocks. To use angular-mocks directly you will have to include it on the page as a <script> tag and also you'll have to deal with all overrides it creates, it produces a lot of side effects. I was able to re-create flush without using angular-mocks by listening to any timeouts that get created and then reseting them on demand.

    For example, if you have a timeout in your Angular app:

    $timeout(function () {
        alert('Hello World');
    }, 10000); // say hello in 10 sec
    

    The test will look like:

    it('should reset timeouts', function () {
    
        browser.addMockModule('e2eFlushTimeouts', function () {
    
            angular
            .module('e2eFlushTimeouts', [])
            .run(function ($browser) {
    
                // store all created timeouts
                var timeouts = [];
    
                // listen to all timeouts created by overriding
                // a method responsible for that
                var originalDefer = $browser.defer;
    
                $browser.defer = function (fn, delay) {
                    // originally it returns timeout id
                    var timeoutId = originalDefer.apply($browser, arguments);
                    // store it to be able to remove it later
                    timeouts.push({ id: timeoutId, delay: delay });
                    // preserve original behavior
                    return timeoutId;
                };
    
                // compatibility with original method
                $browser.defer.cancel = originalDefer.cancel;
    
                // create a global method to flush timeouts greater than @delay
                // call it using browser.executeScript()
                window.e2eFlushTimeouts = function (delay) {
                    timeouts.forEach(function (timeout) {
                        if (timeout.delay >= delay) {
                            $browser.defer.cancel(timeout.id);
                        }
                    });
                };
    
            });
    
        });
    
    
        browser.get('example.com');
    
        // do test stuff
    
        browser.executeScript(function () {
            // flush everything that has a delay more that 6 sec
            window.e2eFlushTimeouts(6000); 
        });
    
        expect(something).toBe(true);
    });
    

    It's kinda experimental, I am not sure if it will work for your case. This code can also be simplified by moving browser.addMockModule to a separate node.js module. Also there may be problems if you'd want to remove short timeouts (like 100ms), it can cancel currently running Angular processes, therefore the test will break.

    0 讨论(0)
提交回复
热议问题