AngularJS Unit Testing a Directive
Posted on 2015-03-31
Writing an AngularJS directive is all fun and games until you start fixing bugs. Then regression appear and you look like an idiot.
So I wrote my numeric
directive recently and a few features were added and bugs reported.
I added them and fixed them and obviously, since I had no tests, regressions appeared. So I set out to test my directive!
Here are the basics.
describe("shared.ui.directives.numeric",() => {
var element: ng.IAugmentedJQuery,
scope: tests.shared.ui.directives.INumericTestScope,
timeout: ng.ITimeoutService;
// Load required modules
beforeEach(module("shared"));
beforeEach(module("shared.ui"));
beforeEach(inject(($rootScope: ng.IRootScopeService,
$compile: ng.ICompileService,
$timeout: ng.ITimeoutService) => {
timeout = $timeout;
scope = $rootScope.$new();
// Generate the HTML that we would typically use for this directive
var html = "<input type=\"text\" ng-model=\"Price\" " +
"numeric=\"{ filter: 'currency', decimals: 2 }\" " +
"min=\"MinValue\" max=\"MaxValue\">";
// Set the scope values to sane defaults for testing.
scope.Price = 100;
scope.MinValue = 0;
scope.MaxValue = 250;
// This basically creates the DOM element from the string
// And runs through the full Angular $digest scope.
element = $compile(html)(scope);
// append the element to the body during the test to see behaviour
// while debugging
element.appendTo(document.body);
// This is called multiple times as it forces Angular
// To re-evaluate its cycle
scope.$digest();
}));
afterEach(() => {
// Remove from body after test, obviously.
element.remove();
});
it("should mark as invalid for min and valid when min changes",() => {
scope.MinValue = 10;
scope.$digest();
element
// Enters the value in the input field
.val("0")
// Forces Angular to realize the value has changed
.trigger("input")
// Force the blur event, which does the formatting.
// Not necessary for this specific test, but I added it as an example
.blur();
var hasInvalidValidation = element.hasClass("ng-invalid-min");
expect(hasInvalidValidation).toBe(true);
scope.MinValue = 0;
scope.$digest();
// Since the numeric directive uses $timeout while $watching min and max
// We have to flush it synchronously for it to execute. ngMock
// adds the flush method.
timeout.flush();
hasInvalidValidation = element.hasClass("ng-invalid-min");
expect(hasInvalidValidation).toBe(false);
});
});
Carefully read the comments in the above code for specific tips and tricks on how to test it.
I now have a basic set up to test this directive, I can easily TDD the hell out of it for new features or bug reports!
comments powered by Disqus