UNPKG

ng-describe

Version:

Convenient BDD specs for Angular

271 lines (230 loc) 7.22 kB
# API {%= 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/). ## Primary options **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 [Inject valid constants into Angular](http://glebbahmutov.com/blog/inject-valid-constants-into-angular/) blog post and examples below. ## Secondary options **verbose** - flag to print debug messages during execution **only** - flag to run this set of tests and skip the rest. Equivalent to [ddescribe or describe.only](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(); }); } ```