UNPKG

9.39 kBMarkdownView Raw
1# API
2
3{%= name %} provides a single function `ngDescribe` that takes an options object.
4
5```js
6ngDescribe({
7 // your options
8});
9```
10
11You do not have to specify every option, there are reasonable defaults. We also tried to make
12the API [user-friendly](http://glebbahmutov.com/blog/user-friendly-api/).
13
14`ngDescribe` returns itself, so you can chain multiple sets of specs easily
15
16```js
17ngDescribe({
18 name: 'first suite'
19 ...
20})({
21 name: 'second suite'
22 ...
23});
24```
25
26## Primary options
27
28**name** - a string name for the spec, similar to BDD `describe(name, ...)`
29
30**modules** - list of modules to inject
31
32```js
33angular.module('A', []);
34angular.module('B', []);
35ngDescribe({
36 name: 'modules example',
37 modules: ['A', 'B']
38});
39```
40
41If you have a single module to inject, you can just use a string name without Array notation
42
43```js
44ngDescribe({
45 name: 'single module',
46 modules: 'A'
47});
48```
49
50**inject** - list of dependencies to inject into unit tests. A single dependency can be just a string
51without Array notation. All dependencies will be exposed as properties of the `deps` argument to the
52tests callback
53
54```js
55angular.module('A', []).value('foo', 42);
56ngDescribe({
57 name: 'inject example',
58 modules: 'A',
59 inject: ['foo', '$timeout'],
60 tests: function (deps) {
61 it('has foo', function () {
62 expect(deps.foo).toEqual(42);
63 });
64 it('has timeout service', function () {
65 expect(typeof deps.$timeout).toEqual('function');
66 });
67 }
68});
69```
70
71**tests** - callback function that contains actual specs. Think of this as equivalent to `describe` with
72all necessary Angular dependencies taken care of.
73
74```js
75ngDescribe({
76 inject: ['$q', '$rootScope'],
77 tests: function (deps) {
78 it('injects $q', function () {
79 expect(typeof deps.$q).toEqual('function');
80 });
81 it('can be resolved', function () {
82 deps.$q.when(42).then(function (value) {
83 expect(value).toEqual(42);
84 });
85 // move promises along
86 deps.$rootScope.$digest();
87 });
88 }
89});
90```
91
92**Dependencies injection shortcut**
93
94You can list the dependencies to be injected directly in the test callback.
95
96```js
97angular.module('shortcut', [])
98 .constant('foo', 'bar');
99ngDescribe({
100 module: 'shortcut',
101 tests: function (foo) {
102 it('has constant', function () {
103 console.assert(foo === 'bar');
104 });
105 }
106});
107```
108
109You can inject multiple providers, including built-in services. If the test callback argument
110is named `deps` or `dependencies` it will be assumed that you do NOT use the shortcut.
111
112**mocks** - top level mocks to be substituted into the tests.
113The mocks override *any* injected dependencies among modules.
114
115```js
116ngDescribe({
117 mocks: {
118 // each module to mock by name
119 moduleName1: {
120 // each dependency from moduleName1 to mock
121 dependencyName1: mockValue1,
122 dependencyName2: mockValue2
123 // the rest of moduleName1 is unchanged
124 },
125 moduleName2: {
126 // dependencies to mock in moduleName2
127 }
128 }
129});
130```
131
132For more information see examples below.
133
134**controllers** - list of controllers by name that should be injected. Each controller
135is created with a new `$rootScope` instance.
136
137**NOTE: For each created controller, its SCOPE instance will be in the dependencies object.**
138
139```js
140angular.module('D', [])
141 .controller('dController', function ($scope) {
142 $scope.foo = 'foo';
143 });
144ngDescribe({
145 modules: 'D',
146 controllers: 'dController',
147 tests: function (deps) {
148 it('is a scope for controller', function () {
149 expect(typeof deps.dController).toEqual('object');
150 // deps.dController is the $scope object injected into dController
151 expect(deps.dController.foo).toEqual('foo');
152 });
153 }
154});
155```
156
157**element** - HTML fragment string for testing custom directives and DOM updates.
158
159```js
160ngDescribe({
161 element: '<my-foo bar="baz"></my-foo>'
162});
163```
164
165The compiled `angular.element` will be injected into the dependencies object under `element` property.
166See examples below for more information. The compilation will create a new scope object too.
167
168**parentScope** - when creating HTML fragment, copies properties from this object into the
169scope. The returned dependencies object will have `deps.parentScope` that is the new scope.
170
171```js
172// myFoo directive uses isolate scope for example
173ngDescribe({
174 element: '<my-foo bar="baz"></my-foo>',
175 parentScope: {
176 baz: 42
177 },
178 tests: function (deps) {
179 it('baz -> bar', function () {
180 deps.parentScope.baz = 100;
181 deps.$rootScope.$apply();
182 expect(deps.element.isolateScope().bar).toEqual(100);
183 });
184 }
185});
186```
187
188See "2 way binding" example below.
189
190**configs** - object with modules that have provider that can be used to inject
191run time settings.
192See *Update 1* in
193[Inject valid constants into Angular](http://glebbahmutov.com/blog/inject-valid-constants-into-angular/)
194blog post and examples below.
195
196## Secondary options
197
198**verbose** - flag to print debug messages during execution
199
200**only** - flag to run this set of tests and skip the rest. Equivalent to
201[ddescribe or describe.only](http://glebbahmutov.com/blog/focus-on-karma-test/).
202
203```js
204ngDescribe({
205 name: 'run this module only',
206 only: true
207});
208```
209
210**skip** - flag to skip this group of specs. Equivalent to `xdescribe` or `describe.skip`.
211Could be a string message explaining the reason for skipping the spec.
212
213**exposeApi** - expose low-level ngDescribe methods
214
215The `tests` callback will get the second argument, which is an object with the following methods
216
217 {
218 setupElement: function (elementHtml),
219 setupControllers: function (controllerNames)
220 }
221
222You can use `setupElement` to control when to create the element.
223For example, instead of creating element right away, expose element factory so that you can create
224an element *after* running a `beforeEach` block. Useful for setting up mock backend before creating
225an element.
226
227```js
228ngDescribe({
229 exposeApi: true,
230 inject: '$httpBackend',
231 // no element option
232 tests: function (deps, describeApi) {
233 beforeEach(function () {
234 deps.$httpBackend
235 .expectGET('/api/foo/bar').respond(500);
236 });
237 beforeEach(function () {
238 // now create an element ourselves
239 describeApi.setupElement('<study-flags />');
240 });
241 it('created an element', function () {
242 la(check.has(deps.element));
243 });
244 });
245});
246```
247
248See the spec in [test/expose-spec.js](test/expose-spec.js)
249
250Or you can use `setupControllers` to create controller objects AFTER setting up your spies.
251
252```js
253angular.module('BroadcastController', [])
254 .controller('broadcastController', function broadcastController($rootScope) {
255 $rootScope.$broadcast('foo');
256 });
257```
258
259We need to listen for the `foo` broadcast inside a unit test before creating the controller.
260If we let `ngDescribe` create the "broadcastController" it will be too late. Instead we
261can tell the `ngDescribe` to expose the low-level api and then we create the controllers when
262we are ready
263
264```js
265ngDescribe({
266 name: 'spy on controller init',
267 modules: 'BroadcastController',
268 inject: '$rootScope',
269 exposeApi: true,
270 tests: function (deps, describeApi) {
271 it('can catch the broadcast in controller init', function (done) {
272 var heardFoo;
273 deps.$rootScope.$on('foo', function () {
274 heardFoo = true;
275 done();
276 });
277 describeApi.setupControllers('broadcastController');
278 });
279 }
280});
281```
282
283See the spec in [test/controller-init-spec.js](test/controller-init-spec.js)
284
285**http** - shortcut for specifying mock HTTP responses,
286built on top of [$httpBackend](https://docs.angularjs.org/api/ngMock/service/$httpBackend).
287Each GET request will be mapped to `$httpBackend.whenGET` for example. You can provide
288data, response code + data pair or custom function to return something using custom logic.
289If you use `http` property, then the injected dependencies will have `http` object that
290you can flush (it is really `$httpBackend` object).
291
292```js
293ngDescribe({
294 inject: '$http', // for making test calls
295 http: {
296 get: {
297 '/my/url': 42, // status 200, data 42
298 '/my/other/url': [202, 42], // status 202, data 42,
299 '/my/smart/url': function (method, url, data, headers) {
300 return [500, 'something is wrong'];
301 } // status 500, data "something is wrong"
302 },
303 post: {
304 // same format as GET
305 }
306 },
307 tests: function (deps) {
308 it('responds', function (done) {
309 deps.$http.get('/my/other/url')
310 .then(function (response) {
311 // expect
312 // response.status = 202
313 // response.data = 42
314 done();
315 });
316 deps.http.flush();
317 });
318 }
319});
320```
321All standard methods should be supported (`get`, `head`, `post`, `put`, `delete`, `jsonp` and `patch`).
322
323Each of the methods can return a function that returns an configuration object, see [mock http](#mock-http).
324
325**step** - shortcut for running the digest cycle and mock http flush
326
327```js
328tests: function (deps) {
329 it('runs the digest cycle', function (done) {
330 $q.when(42).finally(done);
331 deps.step();
332 // same as deps.$rootScope.$digest();
333 });
334}
335```
336
337Also flushes the mock http backend
338
339```js
340http: {}
341tests: function (deps) {
342 it('returns expected result', function (done) {
343 deps.$http.get(...)
344 .then(...)
345 .finally(done);
346 deps.step();
347 // same as deps.http.flush();
348 });
349}
350```