-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.html
527 lines (403 loc) · 29.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Angular Unit Testing</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- Optional theme -->
<link href='http://fonts.googleapis.com/css?family=Lato:400,700,400italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/zenburn.min.css">
<link rel="stylesheet" href="core.css">
<link rel="stylesheet" href="ui-changes.css">
<link rel="icon" href="favicon.ico?v=1"/>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body ng-app="Quickstart" data-spy="scroll" data-target="#table-of-contents" id="top">
<div class="col-sm-12 no-padding-h">
<nav id="table-of-contents" class="affix">
<ul class="nav">
<li><a href="#sample-project">Where can I see the actual tests?</a></li>
<li><a href="#unit-testing">How does Karma differ from Protractor?</a></li>
<li><a href="#installing-karma">How do I install Karma?</a></li>
<li><a href="#configuring-karma">How do does Karma know which files to include?</a></li>
<li><a href="#basic-jasmine">How is a basic spec organized?</a></li>
<li><a href="#including-module">How do I inject a module in a spec?</a></li>
<li><a href="#testing-controller">How do I instantiate a controller in a spec?</a></li>
<li><a href="#including-service">How do I inject a service in a spec?</a></li>
<li><a href="#testing-template">How do I test if an element is in the DOM?</a></li>
<li><a href="#testing-route">How do I test route changes?</a></li>
<li><a href="#testing-directive">How do I set up a spec for a directive?</a></li>
<li><a href="#mocking">How/Why do I mock a service call in a controller spec?</a></li>
<li><a href="#spying-methods">How do I determine if one method successfully calls another method?</a></li>
<li><a href="#spying-methods">How do I determine what arguments were included when I call a method?</a></li>
<li><a href="#testing-promise">How do I handle async operations in a spec?</a></li>
<li><a href="#debugging">How do I troubleshoot problems with my specs?</a></li>
<li><a href="#best-practices">How do I know I am formatting my specs in the most efficient manner?</a></li>
<li><a href="#resources">Resources</a></li>
</ul>
</nav>
</div>
<div class="container-fluid" id="top">
<div class="row">
<div class="col-sm-12">
<div class="main-content">
<img class="pull-right" src="images/testing-quickstart.png" alt="Testing Quickstart" width="200"/>
<h1>Angular Unit Testing Quick Start</h1>
<h3 class="section-heading" id="sample-project">Introduction</h3>
<p class="section-question">Why are you doing this?</p>
<p>Angular was written from the ground up to be testable and yet there are scores of Angular developers who are not writing enough (if any) tests for their application. Why is this? I believe that it is because that while testing Angular is easy,
actually getting to that first step is hard. I remember the feeling of despair I felt the first time I was tasked with writing tests for a project I was on. Where do I start? How do I get this Karma thing to actually run? Find my files? How
do I instantiate my controller? What if it has a service dependency? Aaaaaaaaargh!</p>
<p>I have since covered a lot of ground over the last couple years and I found that once you understand a few basic rules of engagement that testing in Angular is actually pretty straight forward and formulaic.</p>
<p>I wanted to try to illustrate some of these basic patterns in an easy to read, approachable way so that developers can get to that first test without losing their mind</p>
<p>Please use this material as a bridge to making tests a natural part of your development process; and if you find something amiss, do not hesitate to create a pull request on the
<a href="https://github.com/simpulton/angular-testing-quick-start-guide">repo</a>. Nothing would make me happier! Enjoy!</p>
<h3 class="section-heading" id="sample-project">The Sample Project</h3>
<p class="section-question">Where can I see the actual tests?</p>
<p>The companion repository for this quick start guide can be found here <a href="https://github.com/simpulton/angular-testing-quick-start">https://github.com/simpulton/angular-testing-quick-start</a></p>
<h3 class="section-heading" id="unit-testing">Unit Testing vs E2E</h3>
<p class="section-question">How does Karma differ from Protractor?</p>
<p>I like to split my tests up into three different categories:</p>
<ol>
<li>
<strong>End-to-End Tests</strong> - These are the tests where you want to mimic an actual user that visits your website. Each test contains a series of simulated user events (ex. go to http://mysite.com/home and then click on the button with ID
'my-button') and expected results (ex. after 200ms a new window should appear that says "Thank You").</li>
<li>
<strong>Integration Tests</strong> - These tests will call directly into your code. For example, you can use an integration test to call an Angular service. Typically each test will focus on one function. The test calls the target function with
a set of parameters and then checks to make sure the results match expected values.</li>
<li>
<strong>Unit Tests</strong> - These are the same as integration tests except you take extra steps to ensure that nothing is executed besides the one function you are testing. For example, when you test a service that uses $http to call a back end
API, an integration test would include the API call. A unit test, however, would use a utility we will discuss later called $httpBackend to replace $http so that the code executed by the test is restricted to just the target function.</li>
</ol>
<p>Protractor is the tool you will use for end-to-end tests while Karma handles integration and unit testing.</p>
<h3 class="section-heading" id="installing-karma">Installing Karma</h3>
<p class="section-question">How do I install Karma?</p>
<pre>
<code class="js">npm install -g karma</code>
</pre>
<h3 class="section-heading" id="configuring-karma">Configuring Karma</h3>
<p class="section-question">How do does Karma know which files to include?</p>
<pre>
<code class="js">karma init karma.conf.js</code>
</pre>
<p>After installing Karma, we need to set up the karma.conf file. The files array in karma.conf contains all the files needed to run a test. This includes:</p>
<ul>
<li>Any angular libraries used by your code</li>
<li>All your custom code</li>
<li>All your test specs</li>
</ul>
<p>Below is an example of a full karma.conf file.</p>
<pre>
<code ng-include="'templates/karma-config.tpl.js'" class="js">
</code>
</pre>
<p>Note that most values in the karma.conf file can be overridden at the command line. For example, if you wanted to run Firefox instead of Chrome you could either change the value in karma.conf or keep the value the same and use this command:</p>
<pre>
<code lang="js">karma start --browsers Firefox</code>
</pre>
<p>I strongly suggest you take an existing karma.conf file like this one and adapt it to meet your needs. As long as you follow the conventions we outline in this guide, the only things you will likely want to change are:</p>
<ul>
<li>files - to include all your custom code, dependencies and test code</li>
<li>reporters - if you want test coverage you will need to include the 'coverage' reporter</li>
<li>autoWatch and singleRun - most of the time you will want autoWatch=true and singleRun=false so that Karma will automatically re-run your tests as you make changes. However, if you are running Karma as part of a script like a git hook or continuous
integration, then you will want to flip these two boolean values so that Karma only runs the tests once.</li>
</ul>
<h3 class="section-heading" id="basic-jasmine">Basic Jasmine Spec Structure</h3>
<p class="section-question">How is a basic spec organized?</p>
<p>
<em>File Structure</em>
</p>
<p>In general, you want to have one test file for each and every non-test code file in your app. You should have a common naming scheme so that your build tools and test runners can pick out test files from non-test files. We are using one of the
most common test file naming schemes: "{filename}.spec.js". So if you have a code file called "app.js", the file that contains all the tests for app.js would be called "app.spec.js". You will often see all test files in a separate directory
from the rest of the code (usually called 'test'), but in the sample code we have put all specs right along side the code they are testing for your convenience.</p>
<p>
<em>Spec Code Structure</em>
</p>
<p>In general, your spec files should follow this structure:</p>
<pre>
<code ng-include="'templates/general-spec.tpl.js'" class="js"></code>
</pre>
<p>Two things to note from this example.</p>
<p>First, you should make liberal use of before, beforeEach, after and afterEach to set up and tear down the appropriate context for tests. Ideally you only have a couple lines of code within each
<strong>it()</strong> function.</p>
<p>The second thing to note is that the first parameter for the
<strong>describe()</strong> and
<strong>it()</strong> functions may be used by the test runner when tests are executed. For example, when this spec is run, some test runners may output:</p>
<pre>
<code>Unit: App App Abstract Route verifies state configuration</code>
</pre>
<p>So, make sure the string values are descriptive.</p>
<h3 class="section-heading" id="including-module">Including a Module</h3>
<p class="section-question">How do I inject a module in a spec?</p>
<p>The first thing your spec should do is define all the Angular modules that are needed for the tests in that spec. This is done using the
<strong>module()</strong> function that comes from the
<strong>angular-mocks</strong> library. For example:
<pre>
<code lang="js">beforeEach(module('myApp'));</code>
</pre>
<p>This code will enable the spec to test the code from the
<strong>myApp</strong> module. It is best practice to use
<strong>beforeEach()</strong> instead of just
<strong>before()</strong> so that each test is essentially running from a blank slate. If you don't do this, the state from a previous test may bleed into another test and affect the results.</p>
<h3 class="section-heading" id="testing-controller">Testing a Controller</h3>
<p class="section-question">How do I instantiate a controller in a spec?</p>
<p>Here is our controller that we want to test:</p>
<pre>
<code ng-include="'templates/controller-spec.tpl.js'" lang="js"></code>
</pre>
<p>The
<strong>angular-mocks</strong> library provides a service called
<strong>$controller</strong> that we can use to help us test our controllers. In the
<strong>beforeEach()</strong> below, we are injecting
<strong>$controller</strong> along with any other dependencies we need to instantiate our controller.</p>
<pre>
<code ng-include="'templates/advanced-controller.tpl.js'" lang="js"></code>
</pre>
<p>Note that we are using the underscore syntax with
<strong>_Messages_</strong> to get a global reference to the
<strong>Messages</strong> service. The underscores are ignored by the injector when the reference name is resolved.</p>
<p><a href="https://docs.angularjs.org/api/ngMock/function/angular.mock.inject" target="_blank">https://docs.angularjs.org/api/ngMock/function/angular.mock.inject</a></p>
<h3 class="section-heading" id="including-service">Including a Service</h3>
<p class="section-question">How do I inject a service in a spec?</p>
<p>Testing an Angular service is a piece of cake. You can use the
<strong>inject()</strong> function from angular-mocks to get a reference to either internal Angular core objects or any of your custom objects in the modules that are defined at the top of the spec. For example:</p>
<pre>
<code ng-include="'templates/include-service.tpl.js'" lang="js"></code>
</pre>
<p>As a best practice, we suggest injecting objects in
<strong>beforeEach()</strong> and saving the object to a local variable. Then in the test we just reference that local variable.</p>
<h3 class="section-heading" id="testing-template">Testing a Template</h3>
<p class="section-question">How do I test if an element is in the DOM?</p>
<p>The most tricky thing to test with Angular is code within templates. That is why you should try to reduce the amount of code in your templates as much as possible. Even if you are really good about this, though, you will always have some template
code that you want to test.</p>
<p>You can split template testing into two categories. The first category includes templates that don't have any controllers, includes or custom directives. Essentially you are just testing logic that uses basic Angular expressions and core Angular
directives. This use case is relatively easy to test. Take the following example:</p>
<pre>
<code ng-include="'templates/testing-template.tpl.html'" lang="html"></code>
</pre>
<p>We want to have access to this HTML file in our tests, but it is generally a bad idea to make an http call within your tests if you can avoid it. Fortunately, there is a nice feature in Karma that allows us to automatically package all of
our HTML template files into an Angular module that we can access easily in our tests. Just add the following to your
<strong>karma.conf.js</strong> file:</p>
<pre>
<code ng-include="'templates/nghtml2js.tpl.js'" lang="js"></code>
</pre>
<p>This will automatically package any file ending in .html within your src/ folder into an Angular module called myAppTemplates. Each template is accessible by using the
<strong>$templateCache</strong> service. You can test this template simply by injecting the
<strong>$compile</strong> service with some test data and then checking the resulting HTML:</p>
<pre>
<code ng-include="'templates/use-nghtml2js.tpl.js'" lang="js"></code>
</pre>
<p>The second category of template testing is unfortunately more complex. We need to deal with dependencies within the template or surrounding the template such as a controller, the UI router, directives, etc. Let's look at one example of a more
complex use case that includes a UI Router state and a controller:</p>
<pre>
<code ng-include="'templates/complex-templates.tpl.js'" lang="js"></code>
</pre>
<p>In order to test the template and associated controller code, we need to instantiate the controller and surrounding context. To that end, we have created a helper function called
<strong>compileRouteTemplateWithController</strong> that does everything we need.</p>
<pre>
<code ng-include="'templates/big-function.tpl.js'" lang="js"></code>
</pre>
<p>We are using this helper function to get all the dependencies we need to run our tests. This includes creating scope, a controller and a render function. Feel free to use this and adapt it to your needs. Also, as an aside, whenever you see
a lot of repetitive code within your tests, make sure you create your own helper functions.</p>
<p>OK, now we have everything in place to test our template.</p>
<pre>
<code ng-include="'templates/helper-code.tpl.js'" lang="js"></code>
</pre>
<p>The key part of this test was the use of the helper function to instantiate the template and all required dependencies:</p>
<pre>
<code ng-include="'templates/instantiate.tpl.js'" lang="js"></code>
</pre>
<h3 class="section-heading" id="testing-route">Testing a Route</h3>
<p class="section-question">How do I test route changes?</p>
<p>Testing a route essentially means testing that we configured the UI router $stateProvider correctly during the config phase. For example, given the following state configuration:</p>
<pre>
<code ng-include="'templates/route.tpl.js'" lang="js"></code>
</pre>
<p>Our basic strategy for testing is to use the
<strong>$state.go()</strong> and
<strong>$state.href()</strong> methods to modify the current state and then check to make sure the route is changed appropriately.</p>
<pre>
<code ng-include="'templates/route-test.tpl.js'" lang="js"></code>
</pre>
<h3 class="section-heading" id="testing-directive">Testing a Directive</h3>
<p class="section-question">How do I set up a spec for a directive?</p>
<p>Similar to how we test a template, we use the $compile service to help us test a directive. The key is to pass in a HTML snippet to
<strong>$compile()</strong> that refers to the target directive. For example, if you had an element directive called 'experiment', you would simply call
<strong>$compile("<experiment></experiment>")</strong>. You can see the full example here:</p>
<pre>
<code ng-include="'templates/directive.tpl.js'" lang="js"></code>
</pre>
And the spec.
<pre>
<code ng-include="'templates/directive-test.tpl.js'" lang="js"></code>
</pre>
<p>Note: depending on what your directive does, you may need to modify the HTML passed into
<strong>$compile</strong>. For example, if the directive expects other attributes on the element or if you are testing a directive with transclusion (in which case you will want to put different snippets of HTML as children to the element that has
the directive).</p>
<h3 class="section-heading" id="mocking">Mocking</h3>
<p class="section-question">How/Why do I mock a service call in a controller spec?</p>
<p>We mentioned at the beginning that you can create both unit tests and integration tests with Karma. When you are writing a unit test, your goal is to test just one thing and either eliminate or mock out all other dependencies. In general,
you can mock any object through the use of the
<strong>$provide</strong> service. You use this service when you define the module you are using in your spec. For example:
<pre>
<code ng-include="'templates/mocking.tpl.js'" lang="js"></code>
</pre>
<p>In this case, we are overriding the SimpleService object. Once we do this, any code that injects SimpleService will get our mock object instead of the actual SimpleService.</p>
<p>There is one special case with mocking where Angular helps you out. Whenever you use
<strong>$http</strong> to make a remote call, Angular has another service behind the scenes called
<strong>$httpBackend</strong> that actually does all the hard work. The angular-mocks library has its own version of
<strong>$httpBackend</strong> with a number of goodies to help us mock out calls to the back end. For example look at this code which makes an
<strong>$http</strong> call:</p>
<pre>
<code ng-include="'templates/$http-backend.tpl.js'" lang="js"></code>
</pre>
<p>If we call
<strong>getExperiments()</strong> in our test, it will make an actual http request to data/experiments.json. We can intercept that call with
<strong>$httpBackend</strong>, however, and define what should be returned instead of making a remote call.</p>
<pre>
<code ng-include="'templates/$http-backend-example.tpl.js'" lang="js"></code>
</pre>
<p>Note that
<strong>$httpBackend.flush()</strong> is needed because normally $http is asynchronous, but we want to execute our test in a synchronous fashion. The call to
<strong>flush()</strong> will ensure that the
<strong>.then()</strong> on the promise returned from $http will be executed immediately.</p>
<h3 class="section-heading" id="spying-methods">Spying on Methods</h3>
<p class="section-question">How do I determine if one method successfully calls another method?
<br> How do I determine what arguments were included when I call a method?</p>
<p>Jasmine uses a spy to determine whether a method has been called and/or what arguments are set into a method call. So, for example:</p>
<pre>
<code ng-include="'templates/spying.tpl.js'" lang="js"></code>
</pre>
<p>A spy only exists within the
<strong>describe()</strong> or
<strong>it()</strong> function where it has been defined.</p>
<h3 class="section-heading bottom-margin" id="advanced-spying">Advanced Spying</h3>
<p>In addition to simply seeing if a spy has been called, we can also define what value the spy should return (using returnValue()) or what fake function the spy should run instead of the target function (using callFake()). For example:</p>
<pre>
<code ng-include="'templates/advanced-spying.tpl.js'" lang="js"></code>
</pre>
And the spec.
<pre>
<code ng-include="'templates/advanced-spying-test.tpl.js'" lang="js"></code>
</pre>
<h3 class="section-heading" id="testing-promise">Testing a Promise</h3>
<p class="section-question">How do I handle async operations in a spec?</p>
<p>By default, each test runs synchronously. So, if you have any asynchronous operation, the test will complete before the operation completes. There are ways of handling specific use cases (for example
<strong>$httpBackend.flush()</strong> as mentioned earlier), but you can also use the Jasmine
<strong>done()</strong> function. For example:</p>
<pre>
<code ng-include="'templates/promise.tpl.js'" lang="js"></code>
</pre>
<p>In this example, the test will not complete until
<strong>done()</strong> is called. If
<strong>done()</strong> contains a parameter, Jasmine treats that as an error and fails the test.</p>
<p>One last note on async operations. You may have noticed in our examples a call to
<strong>$rootScope.$digest()</strong>. This will force the digest cycle to run which is needed whenever we are testing anything athat involves watchers (so, anything with templates).</p>
<h3 class="section-heading" id="debugging">Debugging</h3>
<p class="section-question">How do I troubleshoot problems with my specs?</p>
<p>Spec code is run in the browser just like any other client side code. So, how do you debug your Angular app? That's right, the Chrome/FireFox dev tools. For example, after running Karma with Chrome there should be a Chrome window open on
your machine that contains the output of the test. To debug, simply open up the Chrome dev tools and refresh the page.</p>
<h3 class="section-heading" id="best-practices">Best Practices</h3>
<p class="section-question">How do I know I am formatting my specs in the most efficient manner?</p>
<p>Here is a quick list of best practices. Some of these we touched on earlier.</p>
<ul>
<li>Use
<strong>beforeEach()</strong> to set up the context for your tests.</li>
<li>Make sure the string descriptions you put in
<strong>describe()</strong> and
<strong>it()</strong> make sense as output</li>
<li>Use
<strong>after()</strong> and
<strong>afterEach()</strong> to cleanup your tests if there is any state that may bleed over.</li>
<li>If any one test is over 10 lines of code, you may need to refactor the test</li>
<li>If you find yourself repeating the same code for many tests, refactor the common code into a helper function</li>
</ul>
<h3 class="section-heading" id="resources">Resources</h3>
<p class="section-question"></p>
<p>If you want to do some more digging, here are 6 resources that will get you started.</p>
<ul>
<li>
<a target="_blank" href="https://docs.angularjs.org/guide/unit-testing">Angular Unit Testing Docs</a>
</li>
<li>
<a target="_blank" href="http://karma-runner.github.io/0.13/index.html">Karma Docs</a>
</li>
<li>
<a target="_blank" href="http://jasmine.github.io/2.0/introduction.html">Jasmine Docs</a>
</li>
<li>
<a target="_blank" href="https://www.airpair.com/angularjs/posts/unit-testing-angularjs-applications">Unit testing Angular applications</a>
</li>
<li>
<a target="_blank" href="http://www.sitepoint.com/unit-testing-angularjs-services-controllers-providers/">Unit Testing in Angular: Services, Controllers & Providers</a>
</li>
<li>
<a target="_blank" href="http://www.sitepoint.com/mocking-dependencies-angularjs-tests/">Mocking Dependencies in Angular Tests</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="toTop" style="display: none;">
<a href="#top">
<span class="glyphicon glyphicon-arrow-up"></span>
</a>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.16/angular.min.js"></script>
<script>
// hljs.initHighlightingOnLoad();
/*$('code').each(function(i, block) {
hljs.highlightBlock(block);
});*/
</script>
<script>
var app = angular.module('Quickstart', []);
app.config(function ($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
})
app.directive('code', function ($timeout) {
return {
restrict: 'E',
link: function (scope, element, attrs) {
hljs.highlightBlock(element[0])
if (attrs.lang == 'html') {
element.html(element.find('script').html());
}
}
}
})
</script>
<script>
var innerHeight = $(window).innerHeight();
$(window).scroll(function() {
innerHeight = $(window).innerHeight();
$('#table-of-contents').css('max-height', innerHeight);
if ($(this).scrollTop()) {
$('#toTop:hidden').stop(true, true).fadeIn();
} else {
$('#toTop').stop(true, true).fadeOut();
}
});
$('#table-of-contents').css('max-height', innerHeight);
</script>
</body>
</html>