1 | # API
|
2 |
|
3 | {%= name %} provides a single function `ngDescribe` that takes an options object.
|
4 |
|
5 | ```js
|
6 | ngDescribe({
|
7 | // your options
|
8 | });
|
9 | ```
|
10 |
|
11 | You do not have to specify every option, there are reasonable defaults. We also tried to make
|
12 | the 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
|
17 | ngDescribe({
|
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
|
33 | angular.module('A', []);
|
34 | angular.module('B', []);
|
35 | ngDescribe({
|
36 | name: 'modules example',
|
37 | modules: ['A', 'B']
|
38 | });
|
39 | ```
|
40 |
|
41 | If you have a single module to inject, you can just use a string name without Array notation
|
42 |
|
43 | ```js
|
44 | ngDescribe({
|
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
|
51 | without Array notation. All dependencies will be exposed as properties of the `deps` argument to the
|
52 | tests callback
|
53 |
|
54 | ```js
|
55 | angular.module('A', []).value('foo', 42);
|
56 | ngDescribe({
|
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
|
72 | all necessary Angular dependencies taken care of.
|
73 |
|
74 | ```js
|
75 | ngDescribe({
|
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 |
|
94 | You can list the dependencies to be injected directly in the test callback.
|
95 |
|
96 | ```js
|
97 | angular.module('shortcut', [])
|
98 | .constant('foo', 'bar');
|
99 | ngDescribe({
|
100 | module: 'shortcut',
|
101 | tests: function (foo) {
|
102 | it('has constant', function () {
|
103 | console.assert(foo === 'bar');
|
104 | });
|
105 | }
|
106 | });
|
107 | ```
|
108 |
|
109 | You can inject multiple providers, including built-in services. If the test callback argument
|
110 | is 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.
|
113 | The mocks override *any* injected dependencies among modules.
|
114 |
|
115 | ```js
|
116 | ngDescribe({
|
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 |
|
132 | For more information see examples below.
|
133 |
|
134 | **controllers** - list of controllers by name that should be injected. Each controller
|
135 | is 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
|
140 | angular.module('D', [])
|
141 | .controller('dController', function ($scope) {
|
142 | $scope.foo = 'foo';
|
143 | });
|
144 | ngDescribe({
|
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
|
160 | ngDescribe({
|
161 | element: '<my-foo bar="baz"></my-foo>'
|
162 | });
|
163 | ```
|
164 |
|
165 | The compiled `angular.element` will be injected into the dependencies object under `element` property.
|
166 | See 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
|
169 | scope. The returned dependencies object will have `deps.parentScope` that is the new scope.
|
170 |
|
171 | ```js
|
172 | // myFoo directive uses isolate scope for example
|
173 | ngDescribe({
|
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 |
|
188 | See "2 way binding" example below.
|
189 |
|
190 | **configs** - object with modules that have provider that can be used to inject
|
191 | run time settings.
|
192 | See *Update 1* in
|
193 | [Inject valid constants into Angular](http://glebbahmutov.com/blog/inject-valid-constants-into-angular/)
|
194 | blog 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
|
204 | ngDescribe({
|
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`.
|
211 | Could be a string message explaining the reason for skipping the spec.
|
212 |
|
213 | **exposeApi** - expose low-level ngDescribe methods
|
214 |
|
215 | The `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 |
|
222 | You can use `setupElement` to control when to create the element.
|
223 | For example, instead of creating element right away, expose element factory so that you can create
|
224 | an element *after* running a `beforeEach` block. Useful for setting up mock backend before creating
|
225 | an element.
|
226 |
|
227 | ```js
|
228 | ngDescribe({
|
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 |
|
248 | See the spec in [test/expose-spec.js](test/expose-spec.js)
|
249 |
|
250 | Or you can use `setupControllers` to create controller objects AFTER setting up your spies.
|
251 |
|
252 | ```js
|
253 | angular.module('BroadcastController', [])
|
254 | .controller('broadcastController', function broadcastController($rootScope) {
|
255 | $rootScope.$broadcast('foo');
|
256 | });
|
257 | ```
|
258 |
|
259 | We need to listen for the `foo` broadcast inside a unit test before creating the controller.
|
260 | If we let `ngDescribe` create the "broadcastController" it will be too late. Instead we
|
261 | can tell the `ngDescribe` to expose the low-level api and then we create the controllers when
|
262 | we are ready
|
263 |
|
264 | ```js
|
265 | ngDescribe({
|
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 |
|
283 | See the spec in [test/controller-init-spec.js](test/controller-init-spec.js)
|
284 |
|
285 | **http** - shortcut for specifying mock HTTP responses,
|
286 | built on top of [$httpBackend](https://docs.angularjs.org/api/ngMock/service/$httpBackend).
|
287 | Each GET request will be mapped to `$httpBackend.whenGET` for example. You can provide
|
288 | data, response code + data pair or custom function to return something using custom logic.
|
289 | If you use `http` property, then the injected dependencies will have `http` object that
|
290 | you can flush (it is really `$httpBackend` object).
|
291 |
|
292 | ```js
|
293 | ngDescribe({
|
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 | ```
|
321 | All standard methods should be supported (`get`, `head`, `post`, `put`, `delete`, `jsonp` and `patch`).
|
322 |
|
323 | Each 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
|
328 | tests: 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 |
|
337 | Also flushes the mock http backend
|
338 |
|
339 | ```js
|
340 | http: {}
|
341 | tests: 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 | ```
|