tentacle.js
Version:
Auto mock/inject dependencies for Angular tests
284 lines (224 loc) • 8.64 kB
Markdown
[](https://travis-ci.org/anilanar/tentacle.js)
[](https://coveralls.io/github/anilanar/tentacle.js?branch=master)
[](https://badge.fury.io/js/tentacle.js)
This utility library is unstable and experimental. You don't have to use it for all of your test suites. Give it a try for testing one of your services/controllers/directives!
# tentacle.js
---------------
Auto-mock dependencies for angular.js tests. See integration tests for examples.
Injecting or mocking dependencies is supported for services/factories, controllers and directives.
Filters and providers currently are not supported. However services returned by providers can be tested using tentacle.js.
### Table of Contents
1. [Installation](#1-installation)
2. [First steps](#2-first-steps)
3. [API and examples](#3-api-and-examples)
- [`tentacle.injectAll`](#tentacleinjectAll)
- [`tentacle.service`](#tentacleservice)
- [`tentacle.factory`](#tentaclefactory)
- [`tentacle.controller`](#tentaclecontroller)
- [`tentacle.controller.run`](#tentaclecontrollerrun)
- [`tentacle.directive`](#tentacledirective)
- [`tentacle.directive.run`](#tentacledirectiverun)
- [`tentacle.reset`](#tentaclereset)
4. [Advanced](#4-advanced)
- [How it works](#how-it-works)
- [`tentacle.globalInjects`](#tentacleglobalinjects)
- [`tentacle.mockExceptions`](#tentaclemockexceptions)
### 1. Installation
##### npm:
```
npm install tentacle.js
```
##### bower:
```
bower install tentacle.js
```
### 2. First steps
##### node.js:
```js
var tentacleInit = require('tentacle');
var angular = require('angular');
var globalScope = {}; // you can use global too,
// similar to window object
// in browsers
tentacleInit(global, angular)
// You can use globalScope.tentacle
describe('test', function () {
it('should have tentacle', function () {
expect(globalScope.tentacle).to.be.an.object;
// if you use 'global' object:
// expect(tentacle).to.be.an.object;
});
});
```
##### browsers (karma):
Add [dist/tentacle.js](dist/tentacle.js) to your files list in karma config. `tentacle` object is put into `window` global variable:
```js
describe('test', function () {
it('should have tentacle', function () {
expect(tentacle).to.be.an.object;
});
});
```
### 3. API and examples:
---
#### `tentacle.injectAll`
Injects all dependencies given a module name and a service, factory, controller or directive name.
###### Arguments
| Param | Type | Details
| ---------- | ------- | ----------
| moduleName | string | name of angular module
| name | string | name of service/factory/ctrl/directive
---
#### `tentacle.service`
#### `tentacle.factory`
Mocks all dependencies of an angular service, except those defined in `tentacle.mockExceptions`.
###### Usage
```js
// a simple service
angular.module('myModule').factory('myService', [
'anotherService',
function (anotherService) {
return {
myMethod: function () {
anotherService.anotherMethod();
};
}
}]);
// ----------------
// test
var mocks = tentacle.service('myModule', 'myService');
mocks.anotherService.anotherMethod = function () {
return 'HELLO';
};
expect(myService.myMethod()).to.equal('HELLO');
```
###### Arguments
| Param | Type | Details
| ----------- | ------- | ----------
| moduleName | string | name of angular module
| serviceName | string | name of service
| customMocks | object | _(optional)_ string-value pairs for overriding default mock object. defaults to an empty object
| defaultMock | any | _(optional)_ value to inject for mocked dependencies. provided values are deeply cloned before each injection. defaults to an empty object
###### Returns
`object{string: any}` : string-value pairs of mocked dependency names and their values
---
#### `tentacle.controller`
Mocks all dependencies of an angular controller, except those defined in `tentacle.mockExceptions`.
###### Usage
```js
// a simple controller
angular.module('myModule').controller('myCtrl', [
'$scope',
'anotherService',
function ($scope, anotherService) {
this.myMethod = function () {
anotherService.anotherMethod();
}
$scope.myValue = this.myMethod();
}]);
// ----------------
// test
var mocks = tentacle.controller('myModule', 'myCtrl');
mocks.anotherService.anotherMethod = function () {
return 'HELLO';
};
var ctrl = tentacle.controller.run();
expect(ctrl.myMethod()).to.equal('HELLO');
expect($scope.myValue).to.equal('HELLO');
```
###### Arguments
| Param | Type | Details
| ----------- | ------- | ----------
| moduleName | string | name of angular module
| ctrlName | string | name of controller
| customMocks | object | _(optional)_ string-value pairs for overriding default mock object. defaults to an empty object
| defaultMock | any | _(optional)_ value to inject for mocked dependencies. provided values are deeply cloned before each injection. defaults to an empty object
###### Returns
`object{string: any}` : string-value pairs of mocked dependency names and their values
---
#### `tentacle.controller.run`
Executes the last controller that was initialized using `tentacle.controller`.
###### Returns
`object : instance of controller
---
#### `tentacle.directive`
Mocks all dependencies of an angular controller, except those defined in `tentacle.mockExceptions`.
###### Usage
```js
// a simple directive
angular.module('myModule').directive('myDir', [
'anotherService',
function (anotherService) {
function link ($scope) {
$scope.myValue = anotherService.anotherMethod();
}
return {
restrict: 'EA',
scope: {
'myParam': '='
},
template: '<p>{{myParam}}</p>'
}
}]);
// ----------------
// test
var mocks = tentacle.directive('myModule', 'myDir');
mocks.anotherService.anotherMethod = function () {
return 'HELLO';
};
var elem = tentacle.directive.run('<my-dir my-param="param"></my-dir');
expect(isolateScope.myValue).to.equal('HELLO');
$scope.param = 'tentacle.js';
$scope.$digest();
var isolateScope = elem.isolateScope();
expect(isolateScope.myParam).to.equal('tentacle.js');
```
###### Arguments
| Param | Type | Details
| ----------- | ------- | ----------
| moduleName | string | name of angular module
| dirName | string | name of directive
| customMocks | object | _(optional)_ string-value pairs for overriding default mock object. defaults to an empty object
| defaultMock | any | _(optional)_ value to inject for mocked dependencies. provided values are deeply cloned before each injection. defaults to an empty object
###### Returns
`object{string: any}` : string-value pairs of mocked dependency names and their values
---
#### `tentacle.directive.run`
Executes the last controller that was initialized using `tentacle.controller`.
| Param | Type | Details
| ------- | ------- | ----------
| html | string | html to use for initializing directive. it must have an element that resolves to tested directive at **root**
###### Returns
`object` : an instance of [`angular.element`](https://docs.angularjs.org/api/ng/function/angular.element). the following methods are especially important for testing:
- `scope()`: returns scope
- `isolateScope()`: returns isolate scope if directive is defined to have one
- `controller('directiveName')`: returns controller that was set in directive definition using `controller` property.
---
### 4. Advanced
You can read the following for more advanced information on _tentacle.js_.
#### How it works
When dependencies are injected or mocked using _tentacle.js_, dependencies for given service, controller or directive are searched in `angular._invokeQueue`, a private/undocumented property of _angular_.
Dependencies in `tentacle.globalInjects` are always injected in the global scope while dependencies in `tentacle.mockExceptions` are never mocked.
#### `tentacle.globalInjects`
You can push more dependencies into this array. It is defined as follows:
```js
tentacle.globalInjects = [
'$rootScope',
'$q',
'$httpBackend',
'$templateCache',
'$compile'
];
```
#### `tentacle.mockExceptions`
You can push more dependencies into this array. It is defined as follows:
```js
tentacle.mockExceptions = [
'$http',
'$httpBackend',
'$rootScope',
'$q',
'$scope',
'$filter'
];
```