如何测试Angularjs路由在组件上的解析值?

时间:2016-11-21 09:48:14

标签: angularjs unit-testing angular-ui-router angularjs-components

我正在使用angular@1.5.8并在路由级别为我的某个组件解析某些资源。该组件按预期工作,但我的测试现在失败了。

错误

PhantomJS 2.1.1 (Linux 0.0.0) module ag.expense-claim ExpenseClaimController: should load data FAILED
        TypeError: undefined is not an object (evaluating 'vm.attachedReceipts.results') (line 16)
        ExpenseClaimViewController@app/expenses/expense_claim.js:16:50
        ExpenseClaimViewController@[native code]
        instantiate@node_modules/angular/angular.js:4733:61
        $controller@node_modules/angular/angular.js:10369:39
        node_modules/angular-mocks/angular-mocks.js:2221:21
        $componentController@node_modules/angular-mocks/angular-mocks.js:2264:25
        test/expenseSpec.js:18:40
        invoke@node_modules/angular/angular.js:4718:24
        workFn@node_modules/angular-mocks/angular-mocks.js:3085:26
        loaded@http://localhost:9876/context.js:151:17
        inject@node_modules/angular-mocks/angular-mocks.js:3051:28
        test/expenseSpec.js:14:26
        test/expenseSpec.js:11:13
        global code@test/expenseSpec.js:1:9
        Error: No pending request to flush ! in node_modules/angular-mocks/angular-mocks.js (line 1799)
        flush@node_modules/angular-mocks/angular-mocks.js:1799:76
        test/expenseSpec.js:53:31
        loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0): Executed 43 of 43 (1 FAILED) (0.257 secs / 0.387 secs)
error Command failed with exit code 1.

测试

describe('ExpenseClaimController:', function () {
    var $scope, ctrl, attachedReceipts;

    beforeEach(inject(function ($rootScope, $componentController, $stateParams) {
        var attachedReceipts = {results: [{}]};
        $scope = $rootScope.$new();
        $stateParams.expenseClaimId = 1;
        ctrl = $componentController('expenseClaim', {
            $scope: $scope,
            attachedReceipts: attachedReceipts
        });
    }));

    it('should load data', function () {
       …
    });

组件

angular.module('ag.expenses')
    .component('expenseClaim', {
        templateUrl: '…',
        controller: ExpenseClaimViewController,
        controllerAs: 'vm',
        bindings: {
            attachedReceipts: "<"
        }
    });

function ExpenseClaimViewController($stateParams, $uibModal, API, gettextCatalog, alert) {
    var vm = this;
    vm.attachedReceipts = vm.attachedReceipts.results;
    …
}

路线

 .state('expense-claim', {
        url: '/home_expense_report/:expenseClaimId',
        template: '<expense-claim attached-receipts="$resolve.attachedReceipts"></expense-claim>',
        resolve: {
            attachedReceipts: function (API, $stateParams) {
                return API.TransportCostAttachment.query({expenseClaimId: $stateParams.expenseClaimId}).$promise;
            }
        }
    })

问题

我基于How can I mock ui-router's resolve values when testing a state's configuration?实施我的解决方案,但仍无法使其正常运行。我错过了什么?

2 个答案:

答案 0 :(得分:1)

角度1.5的分辨率不是DI不像角度2, 因此,对于1.5,你应该将它作为绑定传递,如下所示:

var bindings = { attachedReceipts: attachedReceipts };
ctrl = $componentController('expenseClaim', {
            $scope: $scope
        }, bindings);

答案 1 :(得分:1)

除了Ameer的回复之外,我还想提供更多细节,因为我很难找到它们,如果你有一个组件,你需要直接对控制器进行单元测试,或者你想测试模板,你有两种方法来创建具有绑定的控制器(无论它们来自ui-router的解析与否都无关紧要)

- 对组件控制器进行单元测试:

就像Ameer所说,you should pass it as a binding

beforeEach(inject(function(_$componentController_) {
  $componentController = _$componentController_;
}));

it('should expose a `hero` object', function() {
  // Here we are passing actual bindings to the component
  var bindings = {hero: {name: 'Wolverine'}};
  var ctrl = $componentController('heroDetail', null, bindings);

  expect(ctrl.hero).toBeDefined();
  expect(ctrl.hero.name).toBe('Wolverine');
});

$ onInit方法:

如果您的控制器具有$ onInit()方法,它将不会像您预期的那样自动执行,您需要在创建控制器后手动调用该方法,有关此issue here的详细信息

- 单元测试组件的模板:

当单元测试组件的模板时,您仍然需要实例化控制器,这是你可以做的:

beforeEach(inject(($injector) => {
  $rootScope = $injector.get('$rootScope');
  $compile = $injector.get('$compile');
  scope = $rootScope.$new();
  scope.attachedReceipts = {results: [{}]};;

  template = $compile('<expense-claim attached-receipts="attachedReceipts"></expense-claim>')(scope);
  scope.$apply();
});

it('should test something', () => {
  //Example of something you could test
  expect(template.find('h3').html()).to.eq('this is our first content page');
});

使用第二种方法,将调用$ onInit()方法,因此您无需手动调用它。有关如何在组件can be found here

中单元测试模板的完整教程