如何使用 DOM 测试 angularjs 组件

How to test angularjs component with DOM

我正在尝试熟悉测试 AngularJS 应用程序。 虽然测试组件逻辑或多或少是清楚的,但我在 html 模板和模型绑定方面遇到了麻烦,因为我想测试 html 与控制器逻辑的绑定。

测试是运行 by karma 在真实浏览器中,所以测试环境支持DOM。

看起来不可能,不是吗?

describe('sign-up', function () {
        angular.mock.module('myApp');
        angular.mock.inject(function($componentController, $rootScope, $document) {
            let scope = $rootScope.$new();
            let signUp = $componentController('signUp', {$scope: scope});
            console.log(`signup = ${signUp}`);
            for (let [k,v] of signUp) {
                // there is no field signUp.firstName
                // but inside the controller code referencing  
                // this.firstName is working
                console.log(`signup.${k} = ${v}`);
            }
            // jquery cannot find #firstName node
            // $('#firstName').val('dan') gets the same outcome
            $document.find('#firstName').val('dan');
            expect($document.find('#firstName').val()).toBe('dan');
            // without DOM form submission is not possible
        });
    });
});

控制器组件:

angular.
    module('myApp').
    component('signUp', {
        templateUrl: template,
        controller: [
            function () {
                this.form = {};
                var self = this;
}]});

模板:

  <form novalidate name="$ctrl.form" >
    <div class="form-group">
      <input type="text" class="form-control"
             ng-model="$ctrl.firstName"
             required
             name="firstName"
             id="firstName"
             />
    </div>
  </form>

您需要创建并编译元素:

let element = angular.element('<sign-up></sign-up>');
const $compile = $injector.get('$compile');
element = $compile(element)($scope);

controller = element.controller('signUp');

P.S。 $document.find('#firstName') 不会 return 任何东西,因为你不在任何地方添加这个元素。使用 element.find 代替

您可以使用 $compile service to test your component templates ($componentController creates instances of component controllers without creating any markup, even $compile will not attach it to $document, so you have to use angular.element 检查您的模板)。

这是您的组件的一个工作示例:

angular.module('myApp', [])
    .component('signUp', {
        template: '<form novalidate name="$ctrl.form" >\n' +
        '    <div class="form-group">\n' +
        '      <input type="text" class="form-control"\n' +
        '             ng-model="$ctrl.firstName"\n' +
        '             required\n' +
        '             name="firstName"\n' +
        '             id="firstName"\n' +
        '             />\n' +
        '    </div>\n' +
        '  </form>',
        controller: 'SignUpController'
    })
    .controller('SignUpController', [function myComponentController() {
        var ctrl = this;
        ctrl.form = {};
    }]);

/*
TESTS GO HERE
*/

describe('Testing a component controller', function() {

    beforeEach(module('myApp', function ($provide) {

    }));

    beforeEach(inject(function ($injector) {

    }));

    describe('with $compile', function () {
        var element;
        var scope;
        var controller;

        beforeEach(inject(function ($rootScope, $compile) {
            scope = $rootScope.$new();
            element = angular.element('<sign-up></sign-up>');
            element = $compile(element)(scope);
            controller = element.controller('signUp');
            console.log(element);
            scope.$apply();
        }));

        it('should render template', function () {
            expect(element.find('input').val()).toBe('');
            controller.firstName = 'Dan';
            scope.$apply();
            expect(element.find('input').val()).toBe('Dan');
        });
    })
    
});
.as-console-wrapper {
  height:0;
}
<!DOCTYPE html>
<html>

  <head>
    <!-- jasmine -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.js"></script>
    <!-- jasmine's html reporting code and css -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine-html.js"></script>
    <link href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/jasmine.css" rel="stylesheet" />
    
    <script src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.8.0/boot.js"></script>
    <!-- angular itself -->
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
    <!-- angular's testing helpers -->
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-mocks.js"></script>
  </head>

  <body>
    <!-- bootstrap jasmine! -->
  <script>
    var jasmineEnv = jasmine.getEnv();
    
    // Tell it to add an Html Reporter
    // this will add detailed HTML-formatted results
    // for each spec ran.
    jasmineEnv.addReporter(new jasmine.HtmlReporter());
    
    // Execute the tests!
    jasmineEnv.execute();
  </script>
  </body>

</html>