AngularTestContext
AngularTestContext provides a simple API that implements core ngMock capabilities needed for unit testing. Based upon your needs, it can replace the need for ngMock, or it can be used in conjunction with ngMock.
This utility was originally created to make it easier to build unit tests for directives using the Page Object design pattern.
Table of Contents
Features
- Compatible with Angular 1.2.x and beyond.
- Can be used in other testing frameworks besides Jasmine and Mocha.
- Compatible with CommonJS, AMD, and non-module build environments.
Installation
To install the package:
npm install angular-test-context
To require the package:
var AngularTestContext = ;
Usage
Creating a Test Context
First, make available any Angular modules needed by your test. In this example,
we want to test myDirective
, so we create a module and add the directive
to the module:
angular ;
Next, create the AngularTestContext instance. AngularTestContext needs to know which Angular modules are used by your test. The names of the Angular modules can be passed in as an array, or as comma separated strings, or both.
var testContext = 'testApp';
Compiling HTML with Scope Variables
To compile the HTML to be tested, call the .compile()
method with the
appropriate HTML and any optional scope variables:
var scope = data: value: 'hello' ;var element = testContext;
The .compile()
method returns the Angular wrapped DOM element, which can
then be inspected during your tests to validate the directive's behavior.
Changing a Scope Value
To change a scope value, modify the value, and then call the .digest()
method:
scopedatavalue = 'goodbye';testContext;
Alternatively, you can access the Angular scope object used to compile the
HTML, using the .scope()
method:
scopedatavalue = 'goodbye';testContextscope;
Injecting A Dependency
To inject a dependency into a function, use the .inject()
method:
testContext;
To inject a dependency into a constructor, use the .instantiate()
method:
{ ...} var controller = testContext;
Page Object Design Pattern
AngularTestContext's GitHub project contains a calculator directive example for writing unit tests using the Page Object design pattern and the AngularTestContext utility.
If you haven't used the Page Object design pattern for writing unit tests, I highly recommend it. It will transform your tests from being unwieldy and fragile, to being robust and easily maintained.
The main benefits are:
- It eliminates fragile tests. If the underlying implementation of your code changes, you modify the Page Object, not your tests.
- Tests are much easier to understand since all implementation details are encapsulated in the Page Object.
- Tests are much easier to write since the DRY (Don't Repeat Yourself) code is encapsulated within the Page Object.
- Since the implementation is encapsulated within the Page Object, tests have the potential to be portable across different frameworks - preserving your investment in tests. Instead of changing your tests for each framework, create a different Page Object for each framework.
Calculator Unit Tests
Here are the unit tests for the calculator directive using the
CalculatorPageObject
.
A couple of points to observe:
- There are no implementation details in the tests. The tests simply execute logical calls against the calculator's Page Object.
- You can't determine from the tests what underlying framework is used to implement the calculator.
Note: Abstracting out the underlying framework in your tests may not always be feasible or desirable, but it's a choice worth considering.
/* * Unit tests for the calculator directive. */'use strict'; //-------------------------------------// Module dependencies and variables//------------------------------------- var Calculator = ; //-------------------------------------// Unit tests//------------------------------------- ;
Calculator Page Object
Here is the source code for the CalculatorPageObject
, which uses the
AngularTestContext utility.
/* * Page Object for the calculator directive. */'use strict'; //-------------------------------------// Module exports//------------------------------------- moduleexports = CalculatorPageObject; //-------------------------------------// Module dependencies and variables//------------------------------------- var AngularTestContext = ;var calculatorDirective = ; // Private model name.var MODEL = '_calculatorPageObject'; //-------------------------------------// Page Object//------------------------------------- /* * @constructor */ { var m = thisMODEL = {}; // Add directive to module. angular ; // Create test context. var testContext = 'testApp'; // Compile and find elements. var element = testContext; var inputs = element; ; var button = element; ; var result = element; ; minput1 = ; minput2 = ; mbutton = button; mresult = result;} var proto = CalculatorPageObjectprototype; /* * Sets the value of the first operand. * * @param {string} value */proto { var m = thisMODEL; minput1;}; /* * Sets the value of the second operand. * * @param {string} value */proto { var m = thisMODEL; minput2;}; /* * Adds the two operands. * * @returns {number} The result. */proto { var m = thisMODEL; mbutton; return ;}; /* * Indicates whether add button is disabled. * * @returns {boolean} */proto { var m = thisMODEL; return mbutton;};