【问题标题】:How do I mock $window injected manually in provider private function?如何模拟在提供者私有函数中手动注入的 $window?
【发布时间】:2014-09-02 07:57:03
【问题描述】:

我有以下提供者:

angular.module('MyApp').provider('MyDevice', function () {

    var ngInjector = angular.injector(['ng']),
        $window = ngInjector.get('$window');

    function isMobileDevice () {
        return (/iPhone|iPod|iPad|Silk|Android|BlackBerry|Opera Mini|IEMobile/)
            .test($window.navigator.userAgent || $window.navigator.vendor || $window.opera);
    }

    this.$get = function () {
        return {
            isDesktop: function () {
                return !isMobileDevice();
            },
            isMobile: function () {
                return isMobileDevice();  
            }
        };
    };

});

以及以下测试规范:

describe('MyDeviceProvider', function () {

    var myDevice;

    beforeEach(function () {
        inject(['MyDevice', function (_myDevice_) {
            myDevice = _myDevice_;
        }]);
    });

    it('Test #1', function () {
        // Mock '$window.navigator.userAgent' to "desktop"
        expect(myDevice.isDesktop()).toEqual(true);
        expect(myDevice.isMobile()).toEqual(false);
    });

    it('Test #2', function () {
        // Mock '$window.navigator.userAgent' to "mobile"
        expect(myDevice.isDesktop()).toEqual(false);
        expect(myDevice.isMobile()).toEqual(true);
    });

});

我的问题是,我如何在 Test #1Test #2 中模拟 $window 以便它们成功? 我已经尝试过使用 $provide.valuespyOn 处理无数对象,但我似乎无法模拟 $window.navigator.userAgent 的值来运行我的测试。

我该如何解决这个问题?

P.S:以上代码仅作为我的问题的演示,由于应用程序的特殊要求,我无法将提供程序更改为服务。

【问题讨论】:

    标签: angularjs unit-testing karma-jasmine angular-mock


    【解决方案1】:

    非常粗略,您可以执行以下操作:

    describe('MyDeviceProvider', function () {
    
        var myDevice,
            $window,
            navigator;
    
        beforeEach(function () {
            inject(['MyDevice', '$window', function (_myDevice_, _$window_) {
                myDevice = _myDevice_;
                $window = _$window_;
            }]);
    
            // Save the original navigator object
            navigator = $window.navigator;
        });
    
        afterEach(function () {
            $window.navigator = navigator;
        });
    
        it('Test #1', function () {
            // Mock the entire navigator object to "desktop"
            $window.navigator = {
                userAgent: "desktop" // Use a real "desktop" user agent
            };
    
            // Mock '$window.navigator.userAgent' to "desktop"
            expect(myDevice.isDesktop()).toEqual(true);
            expect(myDevice.isMobile()).toEqual(false);
        });
    
        it('Test #2', function () {
            // Mock the entire navigator object to "desktop"
            $window.navigator = {
                userAgent: "mobile" // Use a real "mobile" user agent
            };
            // Mock '$window.navigator.userAgent' to "mobile"
            expect(myDevice.isDesktop()).toEqual(false);
            expect(myDevice.isMobile()).toEqual(true);
        });
    
    });
    

    您也应该测试模仿不同浏览器的不同模拟。

    【讨论】:

    • 你帮了我很多:)
    • 我相信,inject([...]) 周围的功能是多余的。
    • 其实在 jasmine 中应该够了:window.navigator = Object.create(window.navigator); window.navigator.userAgent = 'foo'; 每次测试后记得恢复原来的UA。
    猜你喜欢
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多