如何在 angular config inc. 中正确使用全局变量。测试

How to properly use a global variable in angular config inc. testing

我正在尝试为一个 wordpress 网站编写一个 angular 主题,并且我正在关注 wordpress/angular 'pattern' 使用 functions.php定义一个指向views/partials文件夹的全局变量,这样它就可以被路由引用。

functions.php中:

wp_localize_script( 'appJs', 'localized',
    array (
        'partials' => get_stylesheet_directory_uri() . '/views'
    )
);

还有我的 angular 配置 class:

function AngularConfig($routeProvider, $locationProvider) {
    $locationProvider.html5Mode(true);

    $routeProvider
        .when('/', {
            templateUrl: localized.partials + '/home.html',
            controller: 'HomeController'
        })
        .when('/projects/', {
            templateUrl: localized.partials + '/projects.html',
            controller: 'ProjectsController'
        })
        .when('/contact/', {
            templateUrl: localized.partials + '/contact.html',
            controller: 'ContactController'
        })
        .otherwise({
            redirectTo: '/'
        });
}

export default AngularConfig;

在运行时这是可行的,因为 localized 是全局的,属性 为 partials。但是,我的测试(karma、jasmine、phantomjs)失败了,因为全局尚未在其环境中定义。 (此外,以这种方式直接引用全局变量是令人讨厌的并且不利于整个 DI 运动等)

我(认为)我想将 `windowProvider' 注入配置 class,并从那里获取变量。像这样:

function AngularConfig($routeProvider, $locationProvider, $windowProvider) {
    $locationProvider.html5Mode(true);

    let partialsRoot = $windowProvider.$get().localized.partials;

    $routeProvider
        .when('/', {
            templateUrl: partialsRoot + '/home.html',
            controller: 'HomeController'
        })
        .when('/projects/', {
            templateUrl: partialsRoot + '/projects.html',
            controller: 'ProjectsController'
        })
        .when('/contact/', {
            templateUrl: partialsRoot + '/contact.html',
            controller: 'ContactController'
        })
        .otherwise({
            redirectTo: '/'
        });
}

export default AngularConfig;

但我不知道如何在测试启动模块之前修改 window/windowProvider
我试过这个:

beforeEach(module(MODULE_NAME, function ($windowProvider) {
    let $window = $windowProvider.$get();
    $window.localized = {
        partials: 'some-path/'
    };
    console.log("WINDOW:", $window);
}));

但是,除非我不在配置 class 中引用 .localized.partials,否则 console.log 不会执行 - 这让我觉得模块(和配置)正在在函数实例化之前修改window

如有任何帮助或指点,我们将不胜感激。
谢谢

之所以有$window服务,是因为可以stubbed/mocked,服务污染了就没必要拆掉真正的window

原始 $window 服务指的是 window 以及 $windowProvider.$get(),因此它们可以与 window.

互换使用

由于 Angular 服务是单例,注入 $window 服务的好处是它可以在整个应用程序中被模拟和使用,并引用同一个模拟对象。一般$window可以这样mock

// module order matters
module(($provide) => {
  $provide.factory('$window', () => {});
}, 'app');

当 Angular DI 被 $windowProvider.$get() 滥用时,情况并非如此。当这样调用时,它将引用不同的对象而不是模拟对象 $window,除了调用它的函数范围之外,无法从任何地方访问该对象。

可以通过像这样模拟 $window 来修复此行为:

beforeEach(() => {
  module({ $window: {} }, 'app');
  ...

这边

  • $windowProvider 在注入应用程序之前被模拟 config
  • $windowProvider.$get$window 指的是同一个 {} 对象,因为该对象是在服务定义上创建的,没有包装在工厂函数中
  • 每个规格重新发布 {} 对象。

但是正确的方法是使用 constant:

app.constant('localized', window.localized);

正是为此而生。通过 DI 摆脱全局常量并在配置和 运行 阶段使用它们。它可以像任何其他服务一样被模拟

module(($provide) => {
  $provide.constant('localized', {});
}, 'app');