ng-describe
Version:
Convenient BDD specs for Angular
271 lines (230 loc) • 7.22 kB
Markdown
{%= name %} provides a single function `ngDescribe` that takes an options object.
```js
ngDescribe({
// your options
});
```
You do not have to specify every option, there are reasonable defaults. We also tried to make
the API [user-friendly](http://glebbahmutov.com/blog/user-friendly-api/).
**name** - a string name for the spec, similar to BDD `describe(name, ...)`
**modules** - list of modules to inject
```js
angular.module('A', []);
angular.module('B', []);
ngDescribe({
name: 'modules example',
modules: ['A', 'B']
});
```
You if have a single module to inject, you can just use a string name without Array notation
```js
ngDescribe({
name: 'single module',
modules: 'A'
});
```
**inject** - list of dependencies to inject into unit tests. A single dependency can be just a string
without Array notation. All dependencies will be exposed as properties of the `deps` argument to the
tests callback
```js
angular.module('A', []).value('foo', 42);
ngDescribe({
name: 'inject example',
modules: 'A',
inject: ['foo', '$timeout'],
tests: function (deps) {
it('has foo', function () {
expect(deps.foo).toEqual(42);
});
it('has timeout service', function () {
expect(typeof deps.$timeout).toEqual('function');
});
}
});
```
**tests** - callback function that contains actual specs. This of this as `describe` equivalent with
all necessary Angular dependencies taken care of.
```js
ngDescribe({
inject: ['$q', '$rootScope'],
tests: function (deps) {
it('injects $q', function () {
expect(typeof deps.$q).toEqual('function');
});
it('can be resolved', function () {
deps.$q.when(42).then(function (value) {
expect(value).toEqual(42);
});
// move promises along
deps.$rootScope.$digest();
});
}
});
```
**mocks** - top level mocks to be substituted into the tests.
The mocks override *any* injected dependencies among modules.
```js
ngDescribe({
mocks: {
// each module to mock by name
moduleName1: {
// each dependency from moduleName1 to mock
dependencyName1: mockValue1,
dependencyName2: mockValue2
// the rest of moduleName1 is unchanged
},
moduleName2: {
// dependencies to mock in moduleName2
}
}
});
```
For more information see examples below.
**controllers** - list of controllers by name that be injected. Each controller
is created with a new `$rootScope` instance.
**NOTE: For each created controller, its SCOPE instance will be in the dependencies object.**
```js
angular.module('D', [])
.controller('dController', function ($scope) {
$scope.foo = 'foo';
});
ngDescribe({
modules: 'D',
controllers: 'dController',
tests: function (deps) {
it('is a scope for controller', function () {
expect(typeof deps.dController).toEqual('object');
// deps.dController is the $scope object injected into dController
expect(deps.dController.foo).toEqual('foo');
});
}
});
```
**element** - HTML fragment string for testing custom directives and DOM updates.
```js
ngDescribe({
element: '<my-foo bar="baz"></my-foo>'
});
```
The compiled `angular.element` will be injected into dependencies object under `element` property.
See examples below for more information. The compilation will create a new scope object too.
**parentScope** - when creating HTML fragment, copies properties from this object into the
scope. The returned dependencies object will have `deps.parentScope` that is the new scope.
```js
// myFoo directive uses isolate scope for example
ngDescribe({
element: '<my-foo bar="baz"></my-foo>',
parentScope: {
baz: 42
},
tests: function (deps) {
it('baz -> bar', function () {
deps.parentScope.baz = 100;
deps.$rootScope.$apply();
expect(deps.element.isolateScope().bar).toEqual(100);
});
}
});
```
See "2 way binding" example below.
**configs** - object with modules that have provider that can be used to inject
run time settings.
See *Update 1* in
[](http://glebbahmutov.com/blog/inject-valid-constants-into-angular/)
blog post and examples below.
**verbose** - flag to print debug messages during execution
**only** - flag to run this set of tests and skip the rest. Equivalent to
[](http://glebbahmutov.com/blog/focus-on-karma-test/).
```js
ngDescribe({
name: 'run this module only',
only: true
});
```
**skip** - flag to skip this group of specs. Equivalent to `xdescribe` or `describe.skip`.
Could be a string message explaining the reason for skipping the spec.
**exposeApi** - instead of creating element right away, expose element factory so that you can create
an element *after* running a `beforeEach` block. Useful for setting up mock backend before creating
an element.
```js
ngDescribe({
exposeApi: true,
inject: '$httpBackend',
// no element option
tests: function (deps, describeApi) {
beforeEach(function () {
deps.$httpBackend
.expectGET('/api/foo/bar').respond(500);
});
beforeEach(function () {
// now create an element ourselves
describeApi.setupElement('<study-flags />');
});
it('created an element', function () {
la(check.has(deps.element));
});
});
});
```
**http** - shortcut for specifying mock HTTP responses,
built on top of [$httpBackend](https://docs.angularjs.org/api/ngMock/service/$httpBackend).
Each GET request will be mapped to `$httpBackend.whenGET` for example. You can provide
data, response code + data pair or custom function to return something using custom logic.
If you use `http` property, then the injected dependencies will have `http` object that
you can flush (it is really `$httpBackend` object).
```js
ngDescribe({
inject: '$http', // for making test calls
http: {
get: {
'/my/url': 42, // status 200, data 42
'/my/other/url': [202, 42], // status 202, data 42,
'/my/smart/url': function (method, url, data, headers) {
return [500, 'something is wrong'];
} // status 500, data "something is wrong"
},
post: {
// same format as GET
}
},
tests: function (deps) {
it('responds', function (done) {
deps.$http.get('/my/other/url')
.then(function (response) {
// response.status = 202
// response.data = 42
done();
});
http.flush();
});
}
});
```
All standard methods should be supported (`get`, `head`, `post`, `put`, `delete`, `jsonp` and `patch`).
Each of the methods can return a function that returns an configuration object, see [mock http](#mock-http)
**step** - shortcut for running the digest cycle and mock http flush
```js
tests: function (deps) {
it('runs the digest cycle', function (done) {
$q.when(42).finally(done);
deps.step();
// same as deps.$rootScope.$digest();
});
}
```
Also flushes the mock http backend
```js
http: {}
tests: function (deps) {
it('returns expected result', function (done) {
deps.$http.get(...)
.then(...)
.finally(done);
deps.step();
// same as deps.http.flush();
});
}
```