【问题标题】:How to test Angularjs route's resolve value on component?如何在组件上测试 Angularjs 路由的解析值?
【发布时间】:2017-04-04 16:05:49
【问题描述】:

我正在使用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? 实现了我的解决方案,但仍然无法使其正常工作。我错过了什么?

【问题讨论】:

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


【解决方案1】:

角度 1.5 中的解析不是 DI 不像 角度 2, 因此对于 1.5,您应该将其作为绑定传递,如下所示:

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

【讨论】:

    【解决方案2】:

    除了 Ameer 的回复之外,如果您有一个组件并且需要直接对控制器进行单元测试,或者如果您想测试模板,我想提供更多详细信息,因为我费了很大力气才找到它们,您有两种方法可以创建具有绑定的控制器(无论它们是否来自 ui-router 的解析都无关紧要)

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

    就像阿米尔说的,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

    【讨论】:

      猜你喜欢
      • 2020-04-04
      • 1970-01-01
      • 2014-04-29
      • 1970-01-01
      • 2015-02-02
      • 2017-11-24
      • 1970-01-01
      • 2022-11-12
      • 1970-01-01
      相关资源
      最近更新 更多