I am trying to get familiar with testing an AngularJS application. While testing component logic is clear more or less, I have a trouble with html templates and model binding, because I'd like to test html binding together with controller's logic.
Test is run by karma in a real browser, so testing environment supports DOM.
It looks like it's not possible, doesn't it?
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
});
});
});
Controller component:
angular.
module('myApp').
component('signUp', {
templateUrl: template,
controller: [
function () {
this.form = {};
var self = this;
}]});
Template:
<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>
DOM stands for Document Object Model. AngularJS's directives are used to bind application data to the attributes of HTML DOM elements.
AngularJS is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but if you ignore these guidelines you may end up with an untestable application.
You can use $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
to check your template).
Here is a working example for your component:
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With