Key Points
link
directive is responsible for core logic implementations, such as DOM operations and event handling, and should be thoroughly tested using AngularJS's testing utility. $templateCache
during testing. Unit testing is an integral part of software development and helps reduce code errors. Testing is one of several tasks to improve code quality. AngularJS is created with testability in mind, so any code written on top of the framework can be easily tested. In my last post on testing, I covered unit test controllers, services, and providers. This article continues to discuss instruction testing. Directives are different from other components because they are not used as objects in JavaScript code, but in HTML templates of applications. We write instructions to perform DOM operations and we cannot ignore them in unit tests because they play an important role. Furthermore, they directly affect the availability of the application. I suggest you check out previous articles about mocking dependencies in AngularJS testing, as we will use some of the techniques from that article in this article. If you want to try out the code developed in this tutorial, you can check out the GitHub repository I set up for you.
Instruction Test
directives are the most important and complex components in AngularJS. Directive testing is tricky because they are not called like functions. In an application, directives are applied declaratively on HTML templates. When templates are compiled and the user interacts with instructions, their actions are executed. When performing unit tests, we need to automate user operations and manually compile HTML to test the functionality of the directive.
Set the object of the test command
Just like testing any language or using any logical snippet in any framework, we need to get a reference to the required object before starting the test directive. The key object to be created here is an element containing the directive to be tested. We need to compile an HTML fragment with specified directives in order for the directive to take effect. For example, consider the following directive:
angular.module('sampleDirectives', []).directive('firstDirective', function() { return function(scope, elem){ elem.append('This span is appended from directive.'); }; });
directive will start and the compile and link functions will be executed. We can manually compile any HTML template using the $compile
service. The following beforeEach
block compiles the above instructions:
angular.module('sampleDirectives', []).directive('firstDirective', function() { return function(scope, elem){ elem.append('This span is appended from directive.'); }; });
After compilation, the life cycle of the instruction will start. After the next digest cycle, the directive object will be in the same state as it appears on the page. If the directive depends on any service to implement its functionality, the services must be impersonated before compiling the directives so that calls to any service method can be checked in the test. We will see an example in the next section.
Test link function
link
Functions are the most commonly used properties in directive definition objects (DDOs). It contains most of the core logic of the instruction. This logic includes simple DOM operations, listening for publish/subscribe events, monitoring changes in objects or attributes, calling services, handling UI events, and more. We will try to cover most of these scenarios.
DOM operation
Let's start with the case of the directive defined in the previous section. This directive adds a span element to the contents of the element that applies the directive. It can be tested by looking for span inside the directive. The following test case asserts this behavior:
var compile, scope, directiveElem; beforeEach(function(){ module('sampleDirectives'); inject(function($compile, $rootScope){ compile = $compile; scope = $rootScope.$new(); }); directiveElem = getCompiledElement(); }); function getCompiledElement(){ var element = angular.element('<div first-directive=""></div>'); var compiledElement = compile(element)(scope); scope.$digest(); return compiledElement; }
Observer
Since instructions act on the current state of the scope, they should have observers to update the instructions when the state of the scope changes. The observer's unit test must manipulate the data and force the observer to run by calling $digest
, and the status of the instruction must be checked after the digest cycle. The following code is a slightly modified version of the above directive. It uses fields on scope to bind text inside span:
it('should have span element', function () { var spanElement = directiveElem.find('span'); expect(spanElement).toBeDefined(); expect(spanElement.text()).toEqual('This span is appended from directive.'); });
Test this directive is similar to the first directive; except that it should be verified against data on scope and should be checked for updates. The following test cases verify whether the status of the instruction has changed:
angular.module('sampleDirectives').directive('secondDirective', function(){ return function(scope, elem){ var spanElement = angular.element('' + scope.text + ''); elem.append(spanElement); scope.$watch('text', function(newVal, oldVal){ spanElement.text(newVal); }); }; });
The same technique can also be used for observers on test properties.
(The subsequent content will be simplified and summarized due to space limitations, and the core testing methods and ideas will be retained)
DOM Event You can use jqLite's triggerHandler
to simulate click events and verify the results.
Instruction template testing Preload templates with $templateCache
to simplify testing.
Directive Scope Test Verify property binding and method calls for isolation scopes.
require test Verify directive dependencies, including strict and optional dependencies.
replace test Check whether the instruction element is replaced.
transclude test Verify that the directive handles the translated content correctly.
Summary
As shown in this article, instructions are harder to test than other concepts in AngularJS. At the same time, they cannot be ignored because they control some important parts of the application. AngularJS's testing ecosystem makes it easier for us to test any part of the project. I hope that through this tutorial, you will now be more confident in testing instructions. Please let me know what you think in the comments section. If you want to try out the code developed in this tutorial, you can check out the GitHub repository I set up for you.
(The FAQs part is omitted here due to the length of the article. The core content has been covered above.)
The above is the detailed content of AngularJS Testing Tips: Testing Directives. For more information, please follow other related articles on the PHP Chinese website!