4 |
5 | Angular Unit Testing with Jasmine and Karma
6 | =====================
7 |
8 | Welcome
9 | ---------------------
10 |
11 | About the Course/Tutorial
12 | ---------------------
13 |
14 | Hi All, I'm **`Dinanath Jayaswal, Senior UI/Web Developer and Adobe Certified Expert Professional`**, I wanna welcome you to `Angular Unit Testing with Jasmine and Karma`. In this course/tutorial, will take you from the basics/ground and gives you a solid foundation to write automated tests for your Angular apps. Whether you're an absolute beginner or have some familiarity with automated testing, this course/tutorial will give you all the necessary building block skills to write automated tests for your Angular apps.
15 |
16 | Let us dive into a topic which lots of developers/technical professionals are struggling and afraid of - `Testing our code`. In this section, we will learn how to write an automated test for Angular Applications.
17 |
18 |
19 | Who is this for?
20 | ---------------------
21 |
22 | This Course/Tutorial is ideal for:
23 | - Freshers and aspiring UI (JavaScript/Angular) developers
24 | - Absolute beginner Angular developers (Front-End developer)
25 | - Experienced Technical developers
26 | - Developers upgrading from AngularJS 1.x to Angular 2 or above
27 | - Full Stack Developers
28 | - Technical/Team Leads
29 | - Architects, Technical Project Managers, QAs
30 |
31 | This course/Tutorial is for anyone and everyone, Almost everyone! Fresher/Newcomer as well as experienced UI/frontend/Web Developers who are interested in boost skills and further career in Angular world - by learning new latest dynamic tools/utilities which helps to Test Angular application code to become a hi-tech developer.
32 |
33 | Why learn Angular Unit Testing with Jasmine & Karma
34 | ---------------------
35 | - Writing Unit/Integration Test cases and testing code is an art, it helps to produce a product with fewer bugs and better quality
36 | - Tests are the best way to prevent software defects
37 | - In the long run for large applications, manual testing ends up with extreme pain and time-consuming. With automated testing, you spend less time fixing bugs and testing code
38 | - Automated testing is a practice that has been adopted by various organizations and a lot of successful software development teams so Unit Testing becomes a popular skill to learn, know and use
39 |
40 | Course/Tutorial achievement
41 | ---------------------
42 |
43 | Course/Tutorial Goal
44 | ---------------------
45 |
46 | After completing/attending this Course/Tutorial, participants should be able to:
47 | 1. Write Unit and Integration test cases for Angular application using Jasmine
48 | 2. Write clean and maintainable tests for your Angular apps
49 | 2. Feel comfortable writing Angular tests for testing Functions, Logics, Events, multiple types of Components, Attributes-Directives, Dependencies, Routers- Navigation, and services
50 | 3. Know and get familiar with Angular testing best practices
51 |
52 | Prerequisites for current course / What you need to know
53 | ---------------------
54 | The primary focus for this tutorial is testing Angular Applications and code so it is must to know Angular (version 2 and above) and TypeScript. It is advisable to view course/tutorial on Angular - [Angular step by step](https://github.com/dinanathsj29/angular7-step-by-step) and Typescript [Typescript tutorial for all](https://github.com/dinanathsj29/typescript-tutorial) before dive deeper with Angular testing.
55 |
56 | Topics included/covered
57 | =====================
58 |
59 | 1. [Introduction to Automated testing](#1-introduction-to-automated-testing)
60 | - 1.1. [Common questions in mind of developers](#11-common-questions-in-mind-of-developers)
61 | - 1.2. [Developers thoughts](#12-developers-thoughts)
62 | - 1.3. [What is automated testing?](#13-what-is-automated-testing)
63 | - 1.4. [Is it a replacement for manual testing?](#14-is-it-a-replacement-for-manual-testing)
64 | - 1.5. [Codebase to develope](#15-codebase-to-develope)
65 | - 1.6. [Why Test?](#16-why-test)
66 | - 1.7. [Benefits/Advantages of Automated Testing](#17-benefits-advantages-of-automated-testing)
67 | - 1.8. [Do I need Automated testing?](#18-do-i-need-automated-testing)
68 | - 1.9. [First code or write the test? TDD BDD](#19-first-code-or-write-the-test-tdd-bdd)
69 | - 1.10. [What to test?](#110-what-to-test)
70 |
71 | 2. [Different types of tests](#2-different-types-of-tests)
72 | - 2.1. [Unit Test](#21-unit-test)
73 | - 2.2. [Integration Test](#22-integration-test)
74 | - 2.3. [End-to-End or End-2-End or E2E Test or Functional Testing](#23-end-to-end-test)
75 | - 2.4. [The testing pyramid](#24-the-testing-pyramid)
76 |
77 | 3. [The Angular Testing Tools-Toolchain](#3-the-angular-testing-tools-toolchain)
78 | - 3.1. [Testing Tool categories](#31-testing-tool-categories)
79 | - 3.2. [Testing Tools](#32-testing-tools)
80 |
81 | 4. [Setup Angular test](#4-setup-angular-test)
82 | - 4.1. [Installing tools-utilities](#41-installing-tools-utilities)
83 | - 4.2. [Core package-dependencies for testing](#42-core-package-dependencies-for-testing)
84 | - 4.3. [Core test setting-configuration files](#43-core-test-setting-configuration-files)
85 |
86 | 5. [Fundamentals of Unit Testing](#5-fundamentals-of-unit-testing)
87 | - 5.1. [Clean coding principles-best practices](#51-clean-coding-principles-best-practices)
88 | - 5.2. [Creating a spec test file](#52-creating-a-spec-test-file)
89 | - 5.3. [How to write unit tests](#53-how-to-write-unit-tests)
90 | - 5.4. [Widely used Angular Unit Testing functions](#54-widely-used-angular-unit-testing-functions)
91 |
92 | 6. [Starting with Unit Testing](#6-starting-with-unit-testing)
93 | - 6.1. [Unit Testing-Functions](#61-unit-testing-functions)
94 | - 6.2. [Unit Testing-Parameterized Functions](#62-unit-testing-parameterized-functions)
95 | - 6.3. [Running a specific test case](#63-running-a-specific-test-case)
96 | - 6.4. [Unit Testing-Strings](#64-unit-testing-strings)
97 | - 6.5. [Unit Testing-Arrays](#65-unit-testing-arrays)
98 | - 6.6. [Set Up and Tear Down](#66-set-up-and-tear-down)
99 | - 6.7. [Unit Testing-Forms](#67-unit-testing-forms)
100 | - 6.8. [Unit Testing-Event Emitters](#68-unit-testing-event-emitters)
101 | - 6.9. [Unit Testing Limitations](#69-unit-testing-limitations)
102 |
103 | 7. [Code coverage](#7-code-coverage)
104 |
105 | 8. [Working with Integration Testing](#8-working-with-integration-testing)
106 | - 8.1. [Integration Test-Setup](#81-integration-test-setup)
107 | - 8.2. [Integration Test-Generating setup code](#82-integration-test-generating-setup-code)
108 | - 8.3. [ATB Angular TestBed](#83-atb-angular-testbed)
109 | - 8.4. [Integration Test-Property binding](#84-integration-test-property-binding)
110 | - 8.5. [Integration Test-Event binding](#85-integration-test-event-binding)
111 | - 8.6. [fixture detectChanges](#86-fixture-detectchanges)
112 | - 8.7. [Integration Test-Providing dependencies](#87-integration-test-providing-dependencies)
113 | - 8.8. [Testing OnInit ngOnInit](#88-testing-onInit-ngOnInit)
114 | - 8.9. [Why do we use NO ERRORS SCHEMA](#89-why-do-we-use-no-errors-schema)
115 | - 8.10. [Why do we use NO_CUSTOM_SCHEMA](#810-why-do-we-use-no-custom-schema)
116 |
117 | 9. [Angular Testing Resources](#9-angular-testing-resources)
118 |
119 | 1 Introduction to Automated testing
120 | =====================
121 |
122 | 1.1. Common questions in mind of developers
123 | ---------------------
124 |
125 | - What is automated testing?
126 | - Is it a replacement for manual testing?
127 | - Do I need Automated testing?
128 | - Do I write Test first (TDD - Test Driven Development) or application code first?
129 | - What to test?
130 |
131 | 1.2. Developers thoughts
132 | ---------------------
133 |
134 | `Testing our code is an important and integral part of any project` but the majority of developer/technical professionals doesn't follow it, because:
135 | - Testing looks complex
136 | - Its time consuming
137 | - Developers are not clear about Testing
138 | - Don't know how to work with Testing
139 | - No clear idea/picture what to test
140 |
141 | 1.3. What is automated testing?
142 | ---------------------
143 |
144 | > **Automated testing**
145 | - Testing is the process of checking the code/functionality manually or in an automated fashion
146 | - Automated testing is `process/practice of writing code to test our code`, then run tests in an automated fashion
147 | - Automated testing is performed by writing test cases/scripts
148 | - `Manual Testing` is performed by a human carefully executing the test steps
149 | - `Automation Testing` means using an automation tool to execute your test case suite
150 |
151 | 1.4. Is it a replacement for manual testing
152 | ---------------------
153 | 1.4. Development and Testing Life cycle
154 | ---------------------
155 |
156 | Both Manual Testing & Automated Testing have their advantages and disadvantages:
157 | - For `smaller applications`, Manual Testing is beneficial at the same time
158 | - `Large enterprise applications` Automated Testing plays an important role
159 | - Some project/software application (in which requirements changes frequently, R & D Projects) Manual Testing is the best option
160 | - Also in some project/software application combination of both Manual Testing & Automated Testing works and fit fine (`complex things checked manually and dynamic things can be automated tested`)
161 |
162 | ### Manual Testing Process Life cycle
163 | 1. **Code** - We Develop some code/features
164 | 2. **Results** - We have some expected results in mind
165 | 3. **Test** - We Test/check applicaton
166 | - If all looks good/works fine - `success confirmation` - develope other next piece code/feature
167 | - If any error/not happy with code - `Failure` - Modify/Fix and test again
168 |
169 | ### Automated Testing Process Life cycle
170 | 1. **Code** - We Develop some code/features
171 | 2. **Results** - We have some expected results in mind
172 | 3. **Test** - We can Automate and Simply Tests
173 | - We can test some part manually
174 | - At the same time write test cases/automate some task to avoid manual and time-consuming interaction
175 | - `Automate testing helps to get breaking changes/last-minute code shocking changes at the initial level itself`
176 |
177 | Whenever we develop any application we need to test it. Sometimes the test is performed manually by developer/QA team member or at a time we prefer writing an Automated Unit Test.
178 |
179 | `Test-Driven Development is a single powerful tool to prevent bugs, defects from within our application`. By putting some efforts on Testing we get better quality software with fewer bugs which is more maintainable in the long term.
180 |
181 | ### Manual testing process/steps
182 | 1. Launch application in the browser
183 | 2. Login to application
184 | 3. Go to the target page
185 | 4. Follow proper steps and do some clicks here there to test & check, code or functionality developed
186 | 5. Test/check positive and negative both scenarios for particular functionality/function
187 |
188 | `All the way manual testing is pretty time consuming, to follow all the steps/cycle discussed above, we may need a couple of minutes.`
189 |
190 | - Manual Testing of all workflows, all fields, all negative scenarios is time and money consuming
191 | - It is difficult to test for multi-lingual sites manually
192 | - Manual Testing can become boring and hence error-prone.
193 |
194 | ### Automated testing process/steps
195 | `We can write code, directly call the function with different positive and negative input values, and test functionality/function in a fraction of the moment.`
196 |
197 | - Automation increases the speed of test execution
198 | - Automation helps increase Test Coverage
199 | - Automation does not require human intervention. You can run automated test unattended (overnight)
200 |
201 | 1.5. Codebase to develope
202 | ---------------------
203 |
204 | With Automated testing, we have to `write Production Code as well as Unit Test Code`, so it `takes significantly more time` as compared to normal development time.
205 |
206 |
207 |
208 |
209 | Image - Codebase to develop (Production + Test Code)
210 |
211 |
212 |
213 | ### Production/Development Cost
214 |
215 | Its fact that implementing the feature with unit test/testing will take more time than development without unit test/testing.
216 |
217 |
218 |
219 |
220 | Image - Production development cost
221 |
222 |
223 |
224 | ### Manual Testing Cost VS Automated Testing Cost
225 |
226 | #### Manual Testing Cost
227 | - In any application at the initial development level, Manual Testing takes less time
228 | - As the application grows with more and more features, functionality and complexity, time is taken by Manual Testing increases exponentially-significantly
229 | - In the longer run, many new team members are not aware of exact functionality and requirements to test as an actual old developer who developed the features are no more working with the company
230 |
231 | #### Automated Testing Cost
232 | - At the initial development level, Automated Testing takes more time
233 | - In longer time over the years as and when the application grows with features and complexity, Automated Testing time decreases and it is far lesser than Manual Testing
234 | - Now a days many companies avoid manual testing and automate everything and prefer test automation
235 |
236 |
242 |
243 | 1.6. Why Test
244 | ---------------------
245 |
246 | Testing is important and done to:
247 | - Get an error if code break
248 | - Avoid last-minute shocking/breaking code changes
249 | - Tests are the best way to prevent software defects
250 | - Avoid any invalid/bad/unwanted code
251 | - Think about possible issues and bugs in code/application
252 | - Integrate into build workflow (If all test cases succeed than merge code and deployed automatically)
253 | - Save time in the longer run
254 | - Break up complex code dependencies and make our code easier
255 | - Improve code/better code quality
256 |
257 | 1.7. Benefits-Advantages of Automated Testing
258 | ---------------------
259 |
260 | - `It helps to catch defects/bugs before releasing your application/product/software`
261 | - With Automated Testing, we produce software with fewer bugs and of better quality and more reliable
262 | - Tests prevent software defects
263 | - It will help you become a better developer
264 | - It will enforce you to write better and more reliable code
265 | - Helps in regression testing (Testing complete application in chunks, make sure old functionalities are working fine)
266 | - Reveals mistakes in Design/Development (If some features are difficult/complex to write test cases - simplify functionality and logic)
267 | - In the longer run, Automated Unit Testing acts as documentation fo application functionality
268 |
269 | 1.8. Do I need Automated testing
270 | ---------------------
271 | 1.8. Real-time testing scenarios
272 | ---------------------
273 | 1.8. What world think about testing
274 | ---------------------
275 |
276 | ### Be Linguistics and Pragmatic:
277 | - Automated testing has lots of advantages-benefits but it is not good-fit for each project and every team
278 | - `Needed disciplined code and programmer` in team else we need to spend more time and money to fix broken code which may result in loss
279 | - In the Real world, we have constrained for TIME and MONEY - our job is to build + deliver real working software by solving problems and deliver values to the world
280 | - `Depends on the Project Budget, Development Time and Resources we can decide to go for Automated Testing or not`
281 |
282 | ### Automated Testing may not good for:
283 | - A startup who have limited budget and time
284 | - Startup companies who are not sure about product future
285 | - Companies who develop research-based/experimental products (R & D projects)
286 | - Software/application in which requirements changes frequently
287 |
288 | 1.9. First code or write the test TDD BDD
289 | ---------------------
290 | 1.9. Do I write Test first (TDD - Test Driven Development) or application code first?
291 | ---------------------
292 |
293 | - **TDD (Test Driven Development)**
294 | - Sometimes, we write tests before we even start developing which is called TDD (Tests are written before the code)
295 | - We mostly follow BDD (Behavior Driven Development) since we are using the Jasmine framework
296 |
297 | - **Behavior Driven Development**
298 | - Behavior Driven testing is an extension of TDD
299 | - Like TDD in BDD also we can write tests first and then add application code, **The major difference that we get to see here are:**
300 | - `Tests are written in plain descriptive English type grammar`
301 | - Tests are explained as a behavior of an application and are more user-focused
302 | - Using examples to clarify requirements
303 |
304 | This difference brings in the need to have a language which can define, in an understandable format.
305 |
306 | Its all depends on TIME, MONEY and need/requirements - usually, developers and companies first prefer to do application development then go for testing ie. BDD (Behavior Driven Development).
307 |
308 |
309 | 1.10. What to test
310 | ---------------------
311 | 1.10. Which Test Cases to Automate?
312 | ---------------------
313 |
314 | **Test cases to be automated can be selected using the following criterion to increase the automation ROI:**
315 |
316 | - High Risk - Business Critical test cases
317 | - Test cases that are repeatedly executed
318 | - Test Cases that are very tedious or difficult to perform manually
319 | - Time-consuming test Cases
320 |
321 | We can write Angular tests cases for testing Functions, Logics, Events, multiple types of Components, Attributes-Directives, Dependencies, Routers- Navigation, and services.
322 |
323 | While writing test we must think/test all execution scenarios like `if and else condition, positive, negative outputs, pass and fail cases, true or false switch case` etc.
324 |
325 | **The following category of test cases are not suitable for automation:**
326 |
327 | - Test Cases that are newly designed and not executed manually at least once
328 | - Test Cases for which the requirements are frequently changing
329 | - Test cases which are executed on an ad-hoc (emergency or when needed) basis
330 |
331 |
332 | 2 Different types of tests
333 | =====================
334 |
335 | There are different ways/types to test our application code. In Angular context, there are following types of test: `isolated and shallow unit testing (without any custom tags), integration tests between components and UI/E2E tests, which can be functional and visual regression testing`. In general, we have 3 types of tests as given below:
336 | 1. Unit Test
337 | 2. Integration Test
338 | 3. End-to-end Test (Functional Testing)
339 |
340 | Let's go through each testing type in detail and write the right tests for ensuring the application/testing work as expected.
341 |
342 | 2.1. Unit Test
343 | ---------------------
344 |
345 | - **`Testing a function in isolation (testing one function, test individual components of the system)`**
346 | - This is sometimes also called `Isolated testing`, It’s the practice of `testing small isolated pieces of code`
347 | - Test an individual component `in isolation, without external resources` (e.g. file system, server, database, API endpoints, etc.)
348 | - In Angular terms/context `testing only component class` file without any template/view, with fake services and fake routers
349 | - **Coverage** - Small Unit/chunk of code to test
350 | - **Complexity** - Easier to write
351 | - **Time/Duration** - Super Fast, takes less time
352 | - **Frequency** - Write more/as much as you can (Hundreds)
353 | - **Funtionality Testing Confidence** - Does not test the functionality of the application in detail, not give us much confidence about functionality
354 |
355 | > **Note**:
356 | - To perform unit testing for application code, we need to `develop a separate program which executes each unit of the software independently`, providing proper input data from the source and then checking the output result against the expected results
357 | - Usually, a unit testing program is written with the same programming language in which the actual program/code-logic is developed; e.g. if we develop a program in C#/Java/JavaScript, then we need to develop its related unit testing program in C#/Java/JavaScript respectively
358 |
359 |
360 |
366 |
367 | 2.2. Integration Test
368 | ---------------------
369 |
370 | - **`If any Unit testing depends on external resources like databases, networks, and APIs, then it is not a unit test, it's an Integration Test`**
371 | - Testing a Component with Template interaction, dependencies (testing a function that calls and depends on another function)
372 | - In Angular terms/context `testing component along with template (component + template)`, with fake services and fake routers
373 | - **Coverage** - Test a component `with external resources` (e.g. file system, server, database, API endpoints etc.)
374 | - **Complexity** - Little complex as we need to deal with dependency injection
375 | - **Time/Duration** - Little time consuming
376 | - **Frequency** - Write a good couple of (Tens)
377 | - **Funtionality Testing Confidence** - Give us much confidence about functionality
378 |
379 |
385 |
386 | 2.3. End to End Test
387 | ---------------------
388 | 2.3. End-to-End or End-2-End or E2E Test or Functional Testing
389 | ---------------------
390 |
391 | - **`Test an entire application as a whole including function, user interaction, service API calls and complete functionality`**
392 | - This is defined as the testing of the complete functionality of an application
393 | - End-to-End or Functional Testing simply means interacting with your application as it’s running in a browser just like a user would interact with it in real life, i.e. via clicks on a page, filling up data, etc.
394 | - `Testing and checking application from launching in browser till individual functionality, Full flow (validating a DOM after a click)`
395 | - **Coverage** - Test whole app functionality, get more confidence about functionality
396 | - **Complexity** - Complex
397 | - **Time/Duration** - Pretty time consuming, Tests are very slow
398 | - **Frequency** - Write a few (1,2 or so)
399 | - **Funtionality Testing Confidence** - Very fragile (can get broken easily) if any changes in template or component
400 |
401 | 2.4. The testing pyramid
402 | ---------------------
403 |
404 | The testing thumb-rule/testing pyramid says that: `75-80 % of the tests should be unit tests, 15-20 % is integration tests and 5 % is End-2-End UI tests`, overall depends on companies to companies, requirements to requirements.
405 |
406 | > **Note**: Write more Unit and Integration Test, few/less End-to-End tests only for key functionalities
407 |
408 |
409 | 3 The Angular Testing Tools-Toolchain
410 | =====================
411 |
412 | 3.1. Testing Tool categories
413 | ---------------------
414 |
415 | Angular testing toolchain consist of various tools of different types/categories, which can perform unit testing on Angular Framework. Some of the tools categories mentioned below:
416 |
417 | - **Assertion Library**:
418 | - Define test cases, write testing logic, conditions
419 | - Examples/Tools: Jasmine, Chai
420 | - **Test Runner**:
421 | - Execute our tests and summarize results
422 | - Examples/Tools: Karma, Mocha
423 | - **End-to-End testing tools**:
424 | - Perform complete Application test
425 | - Examples/Tools: Protractor
426 | - **Headless Browser**:
427 | - Simultes browser interaction, execute tests in GUI-less browser
428 | - Examples/Tools: Headless chrome, Puppeteer, PhantomJS
429 |
430 | 3.2. Testing Tools
431 | ---------------------
432 |
433 | We can test our Angular applications from scratch by writing and executing pure javascript functions. Creating instances of the relevant classes, calling functions and checking the actual versus expected result.
434 |
435 | But as testing is such a common activity with javascript there are several testing libraries/frameworks available to use which reduce the amount of time it takes to write tests.
436 |
437 | Here is the list of important tools used for Angular testing:
438 |
439 | 1. Jasmine
440 | 2. Karma
441 | 3. Protractor
442 | 4. PhantomJS
443 | 5. Istanbul
444 | 6. Chai
445 | 7. Sinon
446 | 8. Mocha
447 | 9. Angular Testing Utilities
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 | ### 3.2.1. Jasmine
456 |
457 | - **`Jasmine is an open-source Behavior Driven Development (BDD) framework for testing JavaScript code, BDD is an important feature of Test Driven Development (TDD)`**
458 | - Jasmine is the most popular JavaScript testing framework in the Angular community - core framework to write a unit test
459 | - Angular is built-in with Jasmine and Karma so it's pretty easy to get started with testing
460 | - Jasmine provides bunch of functions to write test, e.g. `describe()`, `it()` etc.
461 | - Dependency free and does not require a DOM (Document Object Model)
462 | - Website URL: https://jasmine.github.io/
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 | ### 3.2.2. Karma
471 | - **`A test runner tool for running and executing unit test while developing an Angular app`**
472 | - Karma is a direct product of the AngularJS team and default test runner for applications created with the Angular CLI
473 | - Shows the `outcome of all test` run whether to pass or fail
474 | - Karma allows us to `generate various reports on the results`
475 | - Increases developer productivity by showing/giving live results of tests
476 | - Karma is a tool which let's use `Chrome, Firefox or provides headless browsers` and run Jasmine tests inside of them
477 | - Website URL: https://karma-runner.github.io/latest/index.html
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 | ### 3.2.3. Protractor
486 | - **`Protractor is an End-to-End/End-2-End (E2E) behavior-driven testing framework for Angular`**
487 | - It helps QA or Testers to write and run End-to-End/End-2-End (E2E) to test complete application flow
488 | - It Explores the app as users experience it
489 | - Website URL: https://www.protractortest.org/#/
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 | ### 3.2.4. PhantomJS
498 | - **`PhantomJS is a headless WebKit scriptable browser with a JavaScript API`**
499 | - It has fast and native support for various web standards like DOM handling, CSS selector, JSON, Canvas, and SVG
500 | - PhantomJS - Scriptable Headless Browser, in simple terms we can say - PhantomJS is a web browser `without a graphical user interface`
501 | - PhantomJS can be used to take screenshots of websites, those screenshots can be rendered in different formats also
502 | - As we can use PhantomJS to load and manipulate a web page, it is perfect for carrying out page automation. This helps developers run a bunch of tests without ever having to open a web browser
503 | - **`PhantomJS development is suspended until further notice, PhantomJS is a discontinued headless browser used for automating web page interaction`**
504 | - Website URL: https://phantomjs.org/
505 |
506 | ### 3.2.5. Istanbul
507 | - **`Angular uses Istanbul and Karma for built-in testing`**
508 | - `Istanbul is a Karma reporter` that uses the latest Istanbul 1.x APIs (with full source map support) to report coverage
509 | - Website URL:
510 | - https://www.npmjs.com/package/istanbul,
511 | - https://www.npmjs.com/package/karma-coverage-istanbul-reporter
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 | ### 3.2.6. Sinon
520 | - **`Standalone test spies, stubs and mocks for JavaScript (fake service/HTTP-API calls)`**
521 | - It works with any unit testing framework and has no external dependencies
522 | - **Installation command**: `npm install sinon`
523 | - Jasmine already consists of `spies, Mock`, just a thought from some community that Sinon.JS is better!
524 | - Website URL: https://sinonjs.org/
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 | ### 3.2.7. Chai
533 | - **`Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework`**
534 | - `Chai is an assertion library with some tasty syntax sugar` that can be paired with any other testing framework
535 | - Jasmine already uses a TDD style, so developers using Chai for its BDD interfaces, mainly through the use of `should` and `expect`
536 | - **Installation command**: `npm install chai`
537 | - Website URL:
538 | - https://www.chaijs.com/
539 | - https://angular-2-training-book.rangle.io/testing/using-chai
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 | ### 3.2.8. Mocha
548 | - **`A test runner tool for running and executing unit test while developing an Angular app`**
549 | - Mocha is a testing framework that provides functions that are executed according to in a specific order, and that logs their results to the terminal window
550 | - Mocha makes synchronous and asynchronous testing simple and fun, also runs test serially, allowing for flexible and accurate reporting
551 | - **Installation command**: `npm install mocha`
552 | - Website URL:
553 | - https://mochajs.org/
554 | - https://github.com/mochajs/mocha
555 |
556 | ### 3.2.9. Angular Testing Utilities
557 | - Help us to create a test environment for the complete/whole application code
558 | - Used to cover/test interactions and functionality as a whole
559 | - Angular **`TestBed`** utility / Angular Test Bed (ATB):
560 | - The first and most important inbuilt testing utility which creates an angular testing module
561 | - Used to test interaction between - component and its template or with different component
562 | - **Package/Import statement** - `import { TestBed } from '@angular/core/testing';`
563 |
564 | In the current course/tutorial will mainly deal with `Jasmine (to write tests) & Karma (to run the test and get results/code coverage reports) with Angular Testbed (ATB - to cover interactions and functionality)`.
565 |
566 | 4 Setup Angular test
567 | =====================
568 |
569 | 4.1. Installing tools-utilities
570 | ---------------------
571 |
572 | To create Angular application we need `Node/NPM/Angular CLI` to be installed on the machine, if not then go through following steps and install required tools:
573 |
574 | 1. Install Node (https://nodejs.org/en)
575 | 2. Install Angular CLI (https://cli.angular.io/) command: `npm install -g @angular/cli` OR `npm i -g @angular/cli`
576 | 3. Create a new Angular project with Angular CLI command: `ng new project/appName` OR `ng new angular-unit-test-demo`
577 | 4. Run Angular App by using Angular CLI command: `ng serve`
578 | 5. To run the test cases/test scripts command: `ng test`
579 | - `ng test` command read all the spec/test files from an application with `.spec` extensions and execute them in serial order
580 | - `Karma` launches a headless browser window with port `9876` OR address `http://localhost:9876/?id=96650121` and shows test results and statistics (total test cases run, test pass/fail, etc.)
581 |
582 | > **Note**:
583 | - We don’t have to set up anything special to start on unit testing, thanks to `Angular CLI - an Angular Command Line Interface/Utility`
584 | - Angular CLI creates all the set up with packages and dependencies (Jasmine and karma) with `.spec test file` for us
585 | - Any system which has `Node/NPM/Angular CLI` installed, can simply create an Angular App with the command: `ng new appName` and then
586 | - run `ng test` command to start running default tests/test script present in the application in the form of `.spec` files
587 |
588 | > **Note**: For detailed description of Node/NPM/Angular/Angular CLI Setup, please refer the following links:
589 | - https://github.com/dinanathsj29/angularcli-angualr-cli#02-Getting-Started-with-Angular-CLI
590 | - https://github.com/dinanathsj29/angular7-step-by-step#02-getting-started
591 |
592 |
607 |
608 |
609 | Image - Executing ng test command
610 |
611 |
612 |
613 |
614 |
615 |
616 | Image - Running Angular Test - ng test output
617 |
618 |
619 |
620 | 4.2. Core package-dependencies for testing
621 | ---------------------
622 |
623 | See the image below which lists all the dependencies installed for testing purposes. Let’s go through the more important ones:
624 |
625 |
631 |
632 | - **jasmine-core**:
633 | - **`Jasmine is the framework we are going to use to create our tests (.spec files consists of Jasmine logic)`**
634 | - It has a bunch of functionalities to allow us the write different kinds of tests
635 | - **karma**:
636 | - **`Karma is a task runner tool for our tests`**
637 | - It uses a configuration file to set the startup file, the reporters, the testing framework, the test output browser
638 | - **protractor**:
639 | - **`End to End test writing framework`**
640 | - The rest of the dependencies are mainly reporters for our tests, different tools to use karma and Jasmine and browser launchers
641 |
642 | 4.3. Core test setting-configuration files
643 | ---------------------
644 |
645 | Here are some of the core test settings/configuration files
646 |
647 | - **karma.conf.js**:
648 | - The unit test runner configuration file
649 | - **protractor.conf.js**:
650 | - Protractor end-to-end test framework configuration file
651 | - **test.ts**:
652 | - The main entry point for unit tests and loads all the `.spec` and framework files
653 | - The angular-cli configuration of karma uses the file `test.ts` as the entry point of the tests for the application
654 | - This file is required by karma.conf.js and loads recursively all the .spec and framework files
655 |
656 |
657 | 5 Fundamentals of Unit Testing
658 | =====================
659 |
660 | 5.1. Clean coding principles-best practices
661 | ---------------------
662 |
663 | - Need to `follow clean coding practices` for writing code of development as well as test cases
664 | - Small functions/methods (10 lines of code or less)
665 | - Proper naming conventions for variables and functions/methods (Follow clear and consistent naming conventions for your unit tests)
666 | - Single responsibility principle (one function should do/perform one task only)
667 | - Unit Test cases should be independent (In case of any enhancements or change in requirements, unit test cases should not be affected)
668 | - Test only one code at a time
669 | - While writing test we must think/test all execution scenarios like `if and else condition, positive, negative outputs, pass and fail cases, true or false switch case` etc.
670 | - In case of a change in code in any module, ensure there is a corresponding unit Test Case for the module, and the module passes the tests before changing the implementation
671 | - Bugs identified during unit testing must be fixed before proceeding to the next phase in SDLC (Software Development Life Cycle)
672 | - Adopt a `test as you code` approach, The more code you write without testing, the more paths you have to check for errors
673 |
674 | 5.2. Creating a spec test file
675 | ---------------------
676 |
677 | 1. Create a new Test file which should have `.spec.ts` extension
678 | - Every class/component file should have its corresponding Unit Test case file with `.spec.ts` extension
679 | - `(e.g.: component = header.component.ts, unit testing/spec file = header.component.spec.ts)`
680 | 2. Angular development team recommends putting/keeping unit test scripts alongside the files they are testing and using a `.spec` filename extension to mark it as a testing script (it's a Jasmine convention)
681 | - `header.component.ts, header.component.spec.ts` - should present under one folder
682 | 3. Inside `.spec` test file write Unit Test cases as per logic/functionality mentioned and/or as per specific needs-requirements in the component class file
683 | 4. To run the test cases/test scripts, use Angular CLI command: `ng test`
684 |
685 | 5.3. How to write unit tests
686 | ---------------------
687 |
688 | ### 5.3.1. Unit Test Syntax
689 |
690 | ```typescript
691 | // 1. describe - define test suite, Create a group of specs (often called a suite)
692 |
693 | describe('Textual description of the group', Function for Jasmine to invoke that will define inner suites specs () => {
694 |
695 | // 2. it - define an individual unit test case
696 |
697 | it('expectation from current test case', () => {
698 |
699 | // 3. expect - Create an expectation/assertion for a spec, expect().matcherFunction();
700 |
701 | expect(expectation).toBe(expected);
702 |
703 | })
704 |
705 | })
706 | ```
707 |
708 |
709 |
710 | ### 5.3.2. Unit Test Code
711 |
712 | ```typescript
713 | // 1. describe - define test suite, Create a group of specs (often called a suite)
714 |
715 | describe('HeaderComponent', () => {
716 |
717 | // 2. it - define an individual unit test case
718 |
719 | it('should have header title', () => {
720 |
721 | // 3. expect - Create an expectation for a spec/assertion, expect().matcherFunction();
722 |
723 | let title = 'Welcome to Angular Testing';
724 |
725 | expect(title).toEqual('Welcome to Angular Testing');
726 |
727 | })
728 |
729 | })
730 | ```
731 |
732 |
733 |
734 | ### 5.3.3. Simple function to test with jasmine
735 |
736 | > **Syntax & Example**: `function.ts:`
737 |
738 | ```typescript
739 | function sayHello() {
740 |
741 | return 'Hello World!!!';
742 |
743 | }
744 | ```
745 |
746 | > **Syntax & Example**: `Jasmine test .spec.ts:`
747 |
748 | ```typescript
749 | describe('Say Hello', () => {
750 |
751 | it('should says Hello World', () => {
752 |
753 | expect(sayHello())
754 |
755 | .toEqual('Hello World!!!');
756 |
757 | });
758 |
759 | });
760 | ```
761 |
762 | 5.4. Widely used Angular Unit Testing functions
763 | ---------------------
764 | 5.4. Widely used Angular Unit Testing functions / Structure of Unit Test Case:
765 | ---------------------
766 | 1. describe()
767 | 2. it()
768 | 3. expect()
769 | 4. Various Matcher functions
770 |
771 | ### 5.4.1. describe()
772 | - **`describe() function block define a test suite (the group of related tests)`**
773 | - The `describe(string, function)` function defines what we call a `Test Suite`, a collection of individual `Test Specs`
774 | - Usually, with describe block we define/describe - the name of the current component to test
775 | - e.g.
776 |
777 | ```typescript
778 | describe('test-suite-name / component-name', () => {
779 |
780 | })
781 |
782 | OR
783 |
784 | describe('LoginComponent', () => {
785 |
786 | })
787 | ```
788 |
789 | ### 5.4.2. it()
790 | - **`it() block define a individual spec or test`**
791 | - The `it(string, function)` function defines an individual `Test Spec`, this contains one or more `Test Expectations`
792 | - The `it` block must have proper readable and meaningful statement as a Test Spec/description
793 | - With in `describe()`, we can `have one or more it() functions` - (group of related test/sepc)
794 | - Inside `it()` block `define test/code behavior` - expectation/assertion
795 | - e.g.
796 |
797 | ```typescript
798 | it('test-spec-name', () => {
799 |
800 | })
801 |
802 | OR
803 |
804 | it('should have/show submit button', () => {
805 |
806 | })
807 | ```
808 |
809 | ### 5.4.3. expect()
810 | - **`expect() function block is Jasmine API for checking expectation/assertion`**
811 | - The `expect(actual)` expression is what we call an Expectation
812 | - Takes actual value as the parameter
813 | - Chained with a Matcher function
814 | - In conjunction with a `Matcher Function,` it describes an expected piece of behavior in the application
815 | - e.g.
816 |
817 | ```typescript
818 | expect(something).matcherFunction(value expected)
819 |
820 | OR
821 |
822 | expect(var-name).toBe(value);
823 | expect(var-name).toContain(value);
824 | expect(var-name).toEqual(value);
825 | expect(var-name).toBeNull(value);
826 | expect(var-name).toBeTruthy(value);
827 | expect(var-name).toBeFalsy(value);
828 | ```
829 |
830 | ### 5.4.4. Various Matcher functions() - Built-in matchers
831 | - **`The matcher(expected) expression is what we call a Matcher`**
832 | - It does a boolean comparison with the `expected` value passed in VS. the `actual` value passed to the `expect` function if they are false the spec fails
833 | - It is responsible for reporting to Jasmine if the expectation is true or false, Jasmine will then pass or fail the spec/test
834 | - **Jasmine comes with a rich set of pre-built matchers like:**
835 |
836 | ```typescript
837 | expect(array).toContain(member);
838 | expect(fn).toThrow(string);
839 | expect(fn).toThrowError(string);
840 | expect(instance).toBe(instance);
841 | expect(mixed).toBeDefined();
842 | expect(mixed).toBeFalsy();
843 | expect(mixed).toBeNull();
844 | expect(mixed).toBeTruthy();
845 | expect(mixed).toBeUndefined();
846 | expect(mixed).toEqual(mixed);
847 | expect(mixed).toMatch(pattern);
848 | expect(number).toBeCloseTo(number, decimalPlaces);
849 | expect(number).toBeGreaterThan(number);
850 | expect(number).toBeLessThan(number);
851 | expect(number).toBeNaN();
852 | expect(spy).toHaveBeenCalled();
853 | expect(spy).toHaveBeenCalledTimes(number);
854 | expect(spy).toHaveBeenCalledWith(...arguments);
855 | ```
856 |
857 | 6 Starting with Unit Testing
858 | =====================
859 |
860 | Till now we know and learned that **Unit testing is nothing but `testing only component class` file without any template/view or external dependencies, with fake services and fake routers. so its time to learn basics-fundamentals to advanced level of unit testing**
861 |
862 | **As and when we are running the test, it should run in an isolated mode - as its only test exist in the .spec.ts file**
863 |
864 | 1. **Comment/Remove old test cases (app.component.spec.ts)** - To avoid any confusion/conflicts with pre-existing tests, please comment/remove all the test cases (3 tests) available in `app.component.spec.ts` file.
865 |
866 | 6.1. Unit Testing-Functions
867 | ---------------------
868 |
869 | ### 6.1.1. Creating the first component to test
870 |
871 | 1. Create a new folder and first component file - `app/01-unit-test/01-fundamentals-functions/01-counter.ts`
872 |
873 | > **Syntax & Example**: `01-fundamentals-functions/01-counter.ts`
874 |
875 | ```typescript
876 | export class CounterComponent {
877 |
878 | public counter: number = 0;
879 |
880 | // increment
881 | public increaseCounter(): number {
882 |
883 | this.counter++;
884 |
885 | return this.counter;
886 |
887 | }
888 |
889 | // decrement
890 | public decreaseCounter(): number {
891 |
892 | this.counter--;
893 |
894 | return this.counter;
895 |
896 | }
897 |
898 | } // class CounterComponent
899 | ```
900 |
901 |
907 |
908 |
909 | ### 6.1.2. Creating the first test script
910 |
911 | 1. Create a .spec/test file - `01-counter.spec.ts` and write test case for following scenarios:
912 | - if `increaseCounter` function called than `curCounterValue` value will be greater than zero (positive)
913 |
914 | > **Syntax & Example**: `01-fundamentals-functions/01-counter.spec.ts`
915 |
916 | ```typescript
917 | // import component to test
918 | import { CounterComponent } from "./01-counter";
919 |
920 | // 1. describe - define test suite, Create a group of specs (often called a suite)
921 | describe('CounterComponent', ()=> {
922 |
923 | // 2. it - define an individual unit test case
924 | it ('should check incremented value is greater than zero', ()=> {
925 |
926 | // dependency injection
927 | let counterComponent: CounterComponent = new CounterComponent();
928 |
929 | const curCounterValue = counterComponent.increaseCounter();
930 |
931 | // 3. expect - Create an expectation/assertion for a spec
932 | expect(curCounterValue).toBeGreaterThan(0);
933 |
934 | })
935 |
936 | }) // describe
937 | ```
938 |
939 |
940 |
941 |
942 | Image - Unit Testing - counter .spec test file
943 |
944 |
945 |
946 | ### 6.1.3. Running/Executing the first test script
947 |
948 | 1. Run the test cases/test scripts, by using Angular CLI command: `ng test`
949 |
950 |
951 |
952 |
953 | Image - Unit Testing - Running test
954 |
955 |
964 |
965 | ### 6.1.4. Write and add other test cases in .spec file
966 |
967 | 1. Write another test case for the negative scenario as:
968 | - in case of `decreaseCounter` function executed curCounterValue value will be less than zero (negative)
969 |
970 | ```typescript
971 | it ('should check decremented value is less than zero', ()=> {
972 |
973 | let counterComponent: CounterComponent = new CounterComponent();
974 |
975 | const curCounterValue = counterComponent.decreaseCounter();
976 |
977 | expect(curCounterValue).toBeLessThan(0);
978 |
979 | })
980 | ```
981 |
982 |
983 |
984 | > **Syntax & Example**: final `01-fundamentals-functions/01-counter.spec.ts`
985 |
986 | ```typescript
987 | // import component to test
988 | import { CounterComponent } from "./01-counter";
989 |
990 | // 1. describe - define test suite, Create a group of specs (often called a suite)
991 | describe('CounterComponent', ()=> {
992 |
993 | // 2. it - define an individual unit test case
994 | it ('should check incremented value is greater than zero', ()=> {
995 |
996 | // dependency injection
997 | let counterComponent: CounterComponent = new CounterComponent();
998 |
999 | const curCounterValue = counterComponent.increaseCounter();
1000 |
1001 | // 3. expect - Create an expectation/assertion for a spec
1002 | expect(curCounterValue).toBeGreaterThan(0);
1003 |
1004 | })
1005 |
1006 | it ('should check decremented value is less than zero', ()=> {
1007 |
1008 | let counterComponent: CounterComponent = new CounterComponent();
1009 |
1010 | const curCounterValue = counterComponent.decreaseCounter();
1011 |
1012 | expect(curCounterValue).toBeLessThan(0);
1013 |
1014 | })
1015 |
1016 | }) // describe
1017 | ```
1018 |
1019 |
1020 |
1021 |
1022 | Image - Unit Testing - Running all tests
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 | Image - Unit Testing - Running all test - Browser Karma output
1031 |
1032 |
1033 |
1034 |
1035 | 6.2. Unit Testing-Parameterized Functions
1036 | ---------------------
1037 |
1038 | ### 6.2.1. Simple calculator with parameterized function
1039 |
1040 | > **Syntax & Example**: `02-parameterized-functions/01-parameter-counter.ts`
1041 |
1042 | ```typescript
1043 | export function counterParameter(num): number {
1044 |
1045 | if (num < 0) {
1046 |
1047 | return 0
1048 |
1049 | } else {
1050 |
1051 | return num + 1;
1052 | }
1053 |
1054 | }
1055 | ```
1056 |
1057 |
1058 |
1059 | > **Syntax & Example**: `02-parameterized-functions/01-parameter-counter.spec.ts`
1060 |
1061 | ```typescript
1062 | // import function/component to test
1063 | import { counterParameter } from "./01-parameter-counter";
1064 |
1065 | // 1. describe - define test suite, Create a group of specs (often called a suite)
1066 | describe('counterParameter', ()=> {
1067 |
1068 | // 2. it - define an individual unit test case
1069 | it ('should return zero 0 if input is negative', ()=> {
1070 |
1071 | const counterResult = counterParameter(-1);
1072 |
1073 | // 3. expect - Create an expectation/assertion for a spec
1074 | expect(counterResult).toBe(0);
1075 | expect(counterResult).toBeLessThanOrEqual(0);
1076 |
1077 | })
1078 |
1079 | it ('should increment if input is positive', ()=> {
1080 |
1081 | const counterResult = counterParameter(1);
1082 |
1083 | expect(counterResult).toBe(2);
1084 |
1085 | })
1086 |
1087 | }) // describe
1088 | ```
1089 |
1090 | ### 6.2.2. Dimension calculator with parameterized function
1091 |
1092 | > **Syntax & Example**: `02-parameterized-functions/02-parameter-dimension-calculator.ts`
1093 |
1094 | ```typescript
1095 | export class DimensionCalculator {
1096 |
1097 | public getArea(length: number, width: number): number {
1098 |
1099 | let area = length * width;
1100 |
1101 | return area;
1102 |
1103 | }
1104 |
1105 | }
1106 | ```
1107 |
1108 |
1109 |
1110 | > **Syntax & Example**: `02-parameterized-functions/02-parameter-dimension-calculator.ts`
1111 |
1112 | ```typescript
1113 | // import function/component to test
1114 | import { DimensionCalculator } from "./02-parameter-dimension-calculator";
1115 |
1116 | // 1. describe - define test suite, Create a group of specs (often called a suite)
1117 | describe('DimensionCalculator', () => {
1118 |
1119 | // 2. it - define an individual unit test case
1120 | it('should return area equal or greater than 100', () => {
1121 |
1122 | // dependency injection
1123 | let dimensionComponent: DimensionCalculator = new DimensionCalculator();
1124 |
1125 | const areaResult = dimensionComponent.getArea(10, 10);
1126 |
1127 | // 3. expect - Create an expectation/assertion for a spec
1128 | expect(areaResult).toBeGreaterThanOrEqual(100);
1129 |
1130 | })
1131 |
1132 | }) // describe
1133 | ```
1134 |
1135 | 6.3. Running a specific test case
1136 | ---------------------
1137 | 6.3. Ignore/prevent unwanted test case to run
1138 | ---------------------
1139 | 6.3. Disabled and focused tests
1140 | ---------------------
1141 |
1142 | - The `.spec.ts` test file may contain multiple test cases/test scripts, as in current application `01-counter.spec.ts` file has a total 2 test cases. Let's see, learn and deal with required or unwanted test cases:
1143 |
1144 | ### 6.3.1. Focused tests / Run a Specific test
1145 |
1146 | - To run a specific test from a bunch of tests cases, one can simply put/use/insert `f` before `it() function block`
1147 |
1148 | ```typescript
1149 |
1150 | fit ('should check incremented value is greater than zero ', ()=> { })
1151 |
1152 | ```
1153 |
1154 | - Developer can also focus on specific test suits by pre-pending `f` with `describe()`:
1155 |
1156 | ```typescript
1157 | fdescribe('Say Hello', () => {
1158 |
1159 | fit('should says Hello World', () => {
1160 |
1161 | expect(sayHello())
1162 |
1163 | .toEqual('Hello World!!!');
1164 |
1165 | });
1166 |
1167 | });
1168 | ```
1169 |
1170 |
1171 |
1172 |
1173 | Image - Unit Testing - Running specific test
1174 |
1175 |
1176 |
1177 |
1178 |
1179 |
1180 |
1181 | Image - Unit Testing - Running specific test - Browser Karma output
1182 |
1183 |
1184 |
1185 | ### 6.3.2. Disable tests / Ignore test
1186 |
1187 | - To disable test put/use/insert `x` before `it() function block`, it will prevent running that particular specs/test scripts
1188 | - In the below scenario, 2nd test case with `x` will be ignored/disabled
1189 |
1190 | ```typescript
1191 |
1192 | it ('should check incremented value is greater than zero ', ()=> { })
1193 |
1194 |
1195 | xit ('should check decremented value is less than zero ', ()=> { })
1196 |
1197 | ```
1198 |
1199 | - The developer can easily disable test suit or tests without commenting them out but by just pre-pending `x to the describe` or `it functions`:
1200 |
1201 | ```typescript
1202 | xdescribe('Say Hello', () => {
1203 |
1204 | xit('should says Hello World', () => {
1205 |
1206 | expect(sayHello())
1207 |
1208 | .toEqual('Hello World!!!');
1209 |
1210 | });
1211 |
1212 | });
1213 | ```
1214 |
1215 | > **Note**: We can use `f` and `x` even with `describe() block` to run specific test suit or to ignore unwanted test suit
1216 |
1217 |
1218 |
1219 |
1220 | Image - Unit Testing - Ignore specific test
1221 |
1222 |
1223 |
1224 |
1225 |
1226 |
1227 |
1228 | Image - Unit Testing - Ignore specific test - Browser Karma output
1229 |
1230 |
1231 |
1232 |
1233 | 6.4. Unit Testing-Strings
1234 | ---------------------
1235 |
1236 | > **Note: What to test?**
1237 | - Just check availability `.toContain()` of particuler text/string
1238 | - With Strings and Arrays dont write very specific/fragile unit test case (with .`toBe()` matcher function) - if specific string not availble then it may break easily
1239 | - instead, its advisable to use `.toContain()` matcher function - to check availability of particuler text/string
1240 |
1241 | > **Syntax & Example**: `04-strings/01-string-greetings.ts`
1242 |
1243 | ```typescript
1244 | export function greetingsTo(personName: string) {
1245 |
1246 | return 'Welcome ' + personName;
1247 | // return 'Hello ' + personName;
1248 |
1249 | }
1250 | ```
1251 |
1252 |
1253 |
1254 | > **Syntax & Example**: `04-strings/01-string-greetings.spec.ts`
1255 |
1256 | ```typescript
1257 | // import function/component to test
1258 | import { greetingsTo } from "./01-greetings";
1259 |
1260 | // 1. describe - define test suite, Create a group of specs (often called a suite)
1261 | describe('GreetingString', () => {
1262 |
1263 | // 2. it - define an individual unit test case
1264 | it('should include person name in the greeting message', () => {
1265 |
1266 | // 3. expect - Create an expectation/assertion for a spec
1267 | expect(greetingsTo('Dinanath')).toContain('Welcome Dinanath');
1268 | // expect(greetingsTo('Dinanath')).toContain('Hello Dinanath');
1269 |
1270 | })
1271 |
1272 | }) // describe
1273 | ```
1274 |
1275 | 6.5. Unit Testing-Arrays
1276 | ---------------------
1277 |
1278 | > **Note: What to test?**
1279 | - While testing an array we must need to assert/test/check that array must include-contains particular item/string/value, irrespective of its exact position in an array
1280 |
1281 | > **Syntax & Example**: `05-arrays/01-array-country.ts`
1282 |
1283 | ```typescript
1284 | export function getCountry() {
1285 |
1286 | return ['India', 'Russia', 'Japan', 'israel', 'France'];
1287 |
1288 | }
1289 | ```
1290 |
1291 |
1292 |
1293 | > **Syntax & Example**: `05-arrays/01-array-country.spec.ts`
1294 |
1295 | ```typescript
1296 | // import function/component to test
1297 | import { getCountry } from "./01-array-country";
1298 |
1299 | // 1. describe - define test suite, Create a group of specs (often called a suite)
1300 | describe('ArrayGetCountry', () => {
1301 |
1302 | // 2. it - define an individual unit test case
1303 | it('should return supported country in array', () => {
1304 |
1305 | // 3. expect - Create an expectation/assertion for a spec
1306 | expect(getCountry()).toContain('India');
1307 | expect(getCountry()).toContain('Russia');
1308 | })
1309 |
1310 | it('should return supported country in array', () => {
1311 |
1312 | const countryResult = getCountry();
1313 | expect(countryResult).toContain('India');
1314 | expect(countryResult).toContain('Israel');
1315 |
1316 | })
1317 |
1318 | }) // describe
1319 | ```
1320 |
1321 | 6.6. Set Up and Tear Down
1322 | ---------------------
1323 | 6.6. Triple-A - AAA - 3A - Arrang, Act and Assert pattern/structure
1324 | ---------------------
1325 |
1326 | ### 6.6.1. SetUp and TearDown
1327 |
1328 | - **Set Up**:
1329 | - Sometimes to test a feature we need to perform some setup, perhaps it’s creating some test objects, components initialization, dependency injection, etc.
1330 | - Code written in `beforeEach()` function is known as `Set Up`
1331 |
1332 | - **Tear Down**:
1333 | - Also, we may need to perform some cleanup activities after we have finished testing, like reset object/variable value, perhaps we need to delete some files from the hard drive, etc.
1334 | - Code written in `afterEach()` function is known as `Tear Down`
1335 |
1336 | Jasmine has a few functions we can use to make the activities named setup and teardown easier:
1337 |
1338 | 1. **beforeAll()**:
1339 | - This function is called once, before all the specs in `describe` test suite is run
1340 |
1341 | 2. **afterAll()**:
1342 | - This function is called once `after all the specs in a test suite are finished`
1343 |
1344 | 3. **beforeEach()**:
1345 | - Jasmine calls this function before each and every test - `it` function
1346 | - This function is called before each test specification, `it` function, has been run
1347 | - Its advisable to put `common things/initialize` variables/object inside `beforeEach()` function
1348 | - `beforeEach` runs before each test and is used for the `setup` part of a test
1349 |
1350 | 4. **afterEach()**:
1351 | - Jasmine calls this function after every test - `it` function
1352 | - This function is called after each test specification has been run
1353 | - Runs after each test and is used for the `teardown` part of a test
1354 |
1355 | > **Syntax & Example**: `06-setup-and-teardown/01-setup-teardown-beforeall-afterall.ts`
1356 |
1357 | ```typescript
1358 |
1359 | export function sayHello() {
1360 |
1361 | return 'Hello World!!!';
1362 |
1363 | }
1364 |
1365 | ```
1366 |
1367 | > **Syntax & Example**: `06-setup-and-teardown/06-setup-and-teardown/01-setup-teardown-beforeall-afterall.spec.ts`
1368 |
1369 | ```typescript
1370 | // import component to test
1371 | import { sayHello } from "./02-setup-teardown-beforeall-afterall";
1372 |
1373 | // 1. describe - define test suite, Create a group of specs (often called a suite)
1374 | describe('Say Hello', () => {
1375 |
1376 | let expectedResult = '';
1377 |
1378 | // setup - initialize objects and variables
1379 | beforeEach(() => {
1380 | expectedResult = 'Hello World!!!';
1381 | console.log('setup beforeEach', expectedResult);
1382 | })
1383 |
1384 | // teardown - reset object/variable value
1385 | afterEach(() => {
1386 | expectedResult = '';
1387 | console.log('teardown afterEach', expectedResult);
1388 | })
1389 |
1390 | // 2. it - define an individual unit test case
1391 | it('should says Hello World', () => {
1392 |
1393 | // 3. expect - Create an expectation/assertion for a spec
1394 | expect(sayHello())
1395 |
1396 | .toEqual(expectedResult);
1397 |
1398 | })
1399 |
1400 | }) // describe
1401 | ```
1402 |
1403 | ### 6.6.2. Tripple A - AAA - 3A - Arrang, Act and Assert pattern/structure
1404 |
1405 | The `AAA (Arrange, Act, Assert) pattern/structure` is a common way of writing unit tests for a method under test. It suggests that you should divide your test method into three sections: `arrange, act and assert`. It also makes the test more clean and readable.
1406 |
1407 | - **Arrang**:
1408 | - Initialize system under test
1409 | - The `Arrange` section of a unit test method `initializes objects` and `sets the value` of the data that is passed to the method under test
1410 | - ```let component = new ComponentToCheck();```
1411 |
1412 | - **Act**:
1413 | - Calling a method/function which perform some activity
1414 | - ```component.methodFunction();```
1415 |
1416 | - **Assert**:
1417 | - The fact to check/test
1418 | - The `Assert section verifies` that the action of the method under test behaves as expected
1419 |
1420 | ```typescript
1421 |
1422 | expect(var-name).toBe(value);
1423 | expect(var-name).toContain(value);
1424 | expect(var-name).toEqual(value);
1425 | expect(var-name).toBeNull(value);
1426 | expect(var-name).toBeTruthy(value);
1427 | expect(var-name).toBeFalsy(value);
1428 |
1429 | ```
1430 |
1431 |
1432 |
1433 | > **Syntax & Example**: `06-setup-and-teardown/02-counter.ts`
1434 |
1435 | ```typescript
1436 | export class CounterComponent {
1437 |
1438 | public counter: number = 0;
1439 |
1440 | // increment
1441 | public increaseCounter(): number {
1442 |
1443 | this.counter++;
1444 |
1445 | return this.counter;
1446 |
1447 | }
1448 |
1449 | // decrement
1450 | public decreaseCounter(): number {
1451 |
1452 | this.counter--;
1453 |
1454 | return this.counter;
1455 |
1456 | }
1457 |
1458 | } // class CounterComponent
1459 | ```
1460 |
1461 |
1462 |
1463 | > **Syntax & Example**: `06-setup-and-teardown/0201-basic-simple-counter.spec.ts`
1464 |
1465 | ```typescript
1466 | import { CounterComponent } from "./01-counter";
1467 |
1468 | describe('BasicSimplefCounterComponent', () => {
1469 |
1470 | it('should check incremented value is greater than zero', () => {
1471 |
1472 | let counterComponent: CounterComponent = new CounterComponent();
1473 |
1474 | const curCounterValue = counterComponent.increaseCounter();
1475 |
1476 | expect(curCounterValue).toBeGreaterThan(0);
1477 |
1478 | })
1479 |
1480 | it('should check decremented value is less than zero', () => {
1481 |
1482 | let counterComponent: CounterComponent = new CounterComponent();
1483 |
1484 | const curCounterValue = counterComponent.decreaseCounter();
1485 |
1486 | expect(curCounterValue).toBeLessThan(0);
1487 |
1488 | })
1489 |
1490 | })
1491 | ```
1492 |
1493 |
1494 |
1495 | > **Syntax & Example**: `06-setup-and-teardown/0202-aaa-arrange-act-assert-counter.spec.ts`
1496 |
1497 | ```typescript
1498 | import { CounterComponent } from "./01-counter";
1499 |
1500 | describe('ArrangeActAssertCounterComponent', () => {
1501 |
1502 | it('should check incremented value is greater than zero', () => {
1503 |
1504 | // Arrange - dependency injection
1505 | let counterComponent: CounterComponent = new CounterComponent();
1506 |
1507 | // Act - call a method/function
1508 | const curCounterValue = counterComponent.increaseCounter();
1509 |
1510 | // Assert - 3. expect - Create an expectation/assertion for a spec
1511 | expect(curCounterValue).toBeGreaterThan(0);
1512 |
1513 | })
1514 |
1515 | it('should check decremented value is less than zero', () => {
1516 |
1517 | // Arrange - dependency injection
1518 | let counterComponent: CounterComponent = new CounterComponent();
1519 |
1520 | // Act - call a method/function
1521 | const curCounterValue = counterComponent.decreaseCounter();
1522 |
1523 | // Assert - 3. expect - Create an expectation/assertion for a spec
1524 | expect(curCounterValue).toBeLessThan(0);
1525 |
1526 | })
1527 |
1528 | })
1529 | ```
1530 |
1531 |
1532 |
1533 | > **Syntax & Example**: `06-setup-and-teardown/0203-setup-teardown-counter.spec.ts`
1534 |
1535 | > **Note**: To follow Setup and TearDown methodology we can remove the common/repetitive code from `it() block` and put in the body of test suit ie. `inside describe() block`
1536 |
1537 | ```typescript
1538 | import { CounterComponent } from "./01-counter";
1539 |
1540 | describe('SetupTearDownCounterComponent', () => {
1541 |
1542 | // Arrange - dependency injection
1543 | let counterComponent: CounterComponent;
1544 |
1545 | // setup - initialize objects and variables
1546 | beforeEach(() => {
1547 |
1548 | counterComponent = new CounterComponent();
1549 |
1550 | })
1551 |
1552 | it('should check incremented value is greater than zero', () => {
1553 |
1554 | // Act - call a method/function
1555 | const curCounterValue = counterComponent.increaseCounter();
1556 |
1557 | // Assert - 3. expect - Create an expectation/assertion for a spec
1558 | expect(curCounterValue).toBeGreaterThan(0);
1559 |
1560 | })
1561 |
1562 | it('should check decremented value is less than zero', () => {
1563 |
1564 | // Act - call a method/function
1565 | const curCounterValue = counterComponent.decreaseCounter();
1566 |
1567 | // Assert - 3. expect - Create an expectation/assertion for a spec
1568 | expect(curCounterValue).toBeLessThan(0);
1569 |
1570 | })
1571 |
1572 | })
1573 | ```
1574 |
1575 | 6.7. Unit Testing-Forms
1576 | ---------------------
1577 |
1578 | > **Note: What to test?**
1579 | - At the time of `LoginFormComponent initialization`, it must have `FormGroup` with three controls `name`, `password` and `email`
1580 | - Insure `Validataors` for controls should be present/available/used
1581 |
1582 | > **Syntax & Example**: `07-forms/01-loginform.component.ts`
1583 |
1584 | ```typescript
1585 | import { FormBuilder, FormGroup, Validator, Validators } from "@angular/forms";
1586 |
1587 | export class LoginFormComponent {
1588 |
1589 | loginForm: FormGroup;
1590 |
1591 | constructor(loginFB: FormBuilder) {
1592 |
1593 | this.loginForm = loginFB.group({
1594 |
1595 | name: ['', Validators.required],
1596 | password: ['', Validators.minLength(8)],
1597 | email: ['', Validators.email]
1598 |
1599 | })
1600 |
1601 | }
1602 |
1603 | }
1604 | ```
1605 |
1606 |
1607 |
1608 | > **Syntax & Example**: `07-forms/01-loginform.component.spec.ts`
1609 |
1610 | ```typescript
1611 | import { LoginFormComponent } from "./01-loginform.component";
1612 |
1613 | import { FormBuilder } from "@angular/forms";
1614 |
1615 | describe('LoginFormComponent', () => {
1616 |
1617 | let loginFormComponent: LoginFormComponent;
1618 |
1619 | beforeEach(() => {
1620 |
1621 | loginFormComponent = new LoginFormComponent(new FormBuilder);
1622 |
1623 | })
1624 |
1625 | it('should create a form with 3 controls', () => {
1626 |
1627 | expect(loginFormComponent.loginForm.contains('name')).toBe(true);
1628 | expect(loginFormComponent.loginForm.contains('password')).toBeTruthy();
1629 | expect(loginFormComponent.loginForm.contains('email')).toBeTruthy();
1630 |
1631 | })
1632 |
1633 | it('should make the name control required', () => {
1634 |
1635 | let nameControl = loginFormComponent.loginForm.get('name');
1636 |
1637 | nameControl.setValue('');
1638 |
1639 | expect(nameControl.valid).toBeFalsy();
1640 |
1641 | })
1642 |
1643 | it('should use password with minimum 8 characters', () => {
1644 |
1645 | let passwordControl = loginFormComponent.loginForm.get('password');
1646 |
1647 | passwordControl.setValue('12345678')
1648 |
1649 | expect(passwordControl.valid).toBeTruthy();
1650 |
1651 | })
1652 |
1653 | it('should validate the email input type', () => {
1654 |
1655 | let emailControl = loginFormComponent.loginForm.get('email');
1656 |
1657 | emailControl.setValue('dinanathj@gmail.com')
1658 |
1659 | expect(emailControl.valid).toBeTruthy();
1660 |
1661 | })
1662 |
1663 | })
1664 | ```
1665 |
1666 | 6.8. Unit Testing-Event Emitters
1667 | ---------------------
1668 |
1669 | > **Note: What to test?**
1670 | - `EventEmitters are observables, so subscribe to them and test/check the emitted event/value`
1671 |
1672 | > **Syntax & Example**: `08-event-emitter/01-event-emitter-count.component.ts`
1673 |
1674 | ```typescript
1675 | import { EventEmitter } from "@angular/core";
1676 |
1677 | export class EventCounterComponent {
1678 |
1679 | totalCount = 0;
1680 |
1681 | counterChanged = new EventEmitter();
1682 |
1683 | incrementCounter() {
1684 |
1685 | this.totalCount++;
1686 | this.counterChanged.emit(this.totalCount);
1687 |
1688 | }
1689 |
1690 | }
1691 | ```
1692 |
1693 |
1694 |
1695 | > **Syntax & Example**: `08-event-emitter/01-event-emitter-count.component.spec.ts`
1696 |
1697 | ```typescript
1698 | import { EventCounterComponent } from "./01-event-emitter-count.component";
1699 |
1700 | describe('EventCounterComponent', () => {
1701 |
1702 | let eventCounterComponent: EventCounterComponent;
1703 |
1704 | beforeEach(() => {
1705 |
1706 | eventCounterComponent = new EventCounterComponent();
1707 |
1708 | })
1709 |
1710 | it('should raise counterChanged event when incrementCounter fired', () => {
1711 |
1712 | let totalCounter = 0;
1713 | // let totalCounter = null;
1714 |
1715 | eventCounterComponent.counterChanged.subscribe(_totalCount => {
1716 |
1717 | totalCounter = _totalCount;
1718 |
1719 | eventCounterComponent.incrementCounter();
1720 |
1721 | expect(totalCounter).toBe(1);
1722 | // expect(totalCounter).not.toBeNull();
1723 |
1724 | })
1725 |
1726 | })
1727 |
1728 | })
1729 | ```
1730 |
1731 | 6.9. Unit Testing Limitations
1732 | ---------------------
1733 | There are some limitations with unit tests:
1734 | - `Routers` (Not able to cover with Unit Test. we need to load component in Angular environment so need to follow Integration testing)
1735 | - `Template interpolation and binding` (With a Unit test, not sure properties bound properly in the template )
1736 | - `Event Handlers` (click event or so)
1737 | - Unit testing `can't be expected to catch every error` in a program
1738 | - It is `not possible to evaluate all execution paths` even in the most trivial/small programs
1739 | - Unit testing focuses on a unit of code, hence it `can't catch integration errors` or broad system-level errors
1740 |
1741 | 7 Code coverage
1742 | =====================
1743 |
1744 | - As and when we write the test for our application we must need to know and understand how much code has been covered under test cases
1745 | - `Code coverage` represents how much `percent of code is covered with unit tests`
1746 | - With the Angular CLI, we can run unit tests as well as create code coverage reports - Code coverage reports allow us to see any parts of our code base that may not be properly tested by our unit tests
1747 | - `karma.conf.js` consists of a key `coverageIstanbulReporter` for code coverage related settings:
1748 |
1749 | > **If your team decides on a set minimum amount to be unit tested you can enforce this minimum with the Angular CLI:**
1750 |
1751 | - The `thresholds` property will enforce a minimum of `80%` code coverage when the unit tests are run in the project
1752 |
1753 |
1754 | ```typescript
1755 |
1756 | coverageIstanbulReporter: {
1757 | dir: require('path').join(__dirname, '../coverage'),
1758 | reports: ['html', 'lcovonly'],
1759 | fixWebpackSourcePaths: true
1760 | },
1761 |
1762 | coverageIstanbulReporter: {
1763 | reports: [ 'html', 'lcovonly' ],
1764 | fixWebpackSourcePaths: true,
1765 | thresholds: {
1766 | statements: 80,
1767 | lines: 80,
1768 | branches: 80,
1769 | functions: 80
1770 | }
1771 | }
1772 |
1773 | ```
1774 |
1775 | - If you want to `create code-coverage reports every time you test`, you can set the following option in the CLI configuration file, `angular.json`: This will produce code coverage results whenever tests are run for the project
1776 |
1777 | ```typescript
1778 | "test": {
1779 | "options": {
1780 | "codeCoverage": true
1781 | }
1782 | }
1783 |
1784 | ```
1785 |
1786 | To find out exact code coverage percentage / To generate a coverage report run the following command in the root of your project:
1787 | - `ng test --codeCoverage` OR
1788 | - ng test --code-coverage
1789 |
1790 | Generate the code-coverage report at the same time close Karma test window (don't watch unit test cases):
1791 | - ng test --no-watch --code-coverage
1792 | - ng test --watch=false --code-coverage
1793 |
1794 | > **Output:**
1795 | - Angular CLI generates the coverage report in a separate folder called `coverage` at the root
1796 | - Every folder in the `coverage/src/app` has his index.html, we can load that in the browser to see the actual report for that particular folder or module
1797 | - `coverage/index.html`: To check the final report on code coverage of every individual component or page/files or folders
1798 | - `coverage/src/index.html`: Shows report of `polyfills.ts` and `test.ts`
1799 |
1800 |
1844 |
1845 |
1846 |
1847 | > **Note**:
1848 | - To verify code coverage report percentage, one can `comment-uncomment` some code from `.spec` files and view the report
1849 | - In code coverage report, `lines marked in GREEN are covered in test` and lines `highlighted in RED are not covered` in the test (no test written for such lines)
1850 |
1851 | 8 Working with Integration Testing
1852 | =====================
1853 |
1854 | 8.1. Integration Test-Setup
1855 | ---------------------
1856 |
1857 | In a simple isolated unit test, we can create a new component as `new ComponentName`. But in case of integration test, we need to ask Angular to create an instance of the component with `TestBed` utility. `TestBed` class provides various utility methods to deal with test cases.
1858 |
1859 | > **Syntax & Example**: Basic setup to write integration tests - `name.component.spec.ts`
1860 |
1861 | ```typescript
1862 | import { TestBed, ComponentFixture } from '@angular/core/testing';
1863 |
1864 | describe('test-suite-group-name', () => {
1865 |
1866 | let component: ComponentName;
1867 | let fixture: ComponentFixture;
1868 |
1869 | beforeEach( () => {
1870 |
1871 | // create a dynamic module and put component inside dynamic module
1872 | TestBed.configureTestingModule({
1873 |
1874 | imports: [ Dependency ModuleName, ],
1875 | providers: [ Dependency ServicesName ],
1876 | declarations: [ Current ComponentName, Dependency ComponentName ]
1877 |
1878 | });
1879 |
1880 | fixture = TestBed.createComponent(ComponentName);
1881 | component = fixture.componentInstance;
1882 | fixture.detectChanges();
1883 |
1884 | })
1885 |
1886 | })
1887 | ```
1888 |
1889 | 8.2. Integration Test-Generating setup code
1890 | ---------------------
1891 | 8.2. Integration Test-Generating setup code with Angular CLI
1892 | ---------------------
1893 |
1894 | Creating an integration .spec test file every time manually is pretty time consuming also there are chances of an error. It is advisable to `use Angular CLI to generate components/services/directives/routings, etc.` as Angular CLI generates basic setup code respective to component/test/.spec files.
1895 |
1896 | Angular CLI command to generate component:
1897 | - `ng generate component component-name` OR
1898 | - ng g c component-name
1899 |
1900 | (which generates 4 files: `.ts, .html, .css, .spec file` with some basic setup/scaffolding code)
1901 |
1902 | > **Syntax & Example**: Default code in `app.component.spec.ts`
1903 |
1904 | ```typescript
1905 | import { TestBed, async } from '@angular/core/testing';
1906 | import { AppComponent } from './app.component';
1907 |
1908 | describe('AppComponent', () => {
1909 | beforeEach(async(() => {
1910 | TestBed.configureTestingModule({
1911 | declarations: [
1912 | AppComponent
1913 | ],
1914 | }).compileComponents();
1915 | }));
1916 |
1917 | it('should create the app', async(() => {
1918 | const fixture = TestBed.createComponent(AppComponent);
1919 | const app = fixture.debugElement.componentInstance;
1920 | expect(app).toBeTruthy();
1921 | }));
1922 |
1923 | it(`should have as title 'app'`, async(() => {
1924 | const fixture = TestBed.createComponent(AppComponent);
1925 | const app = fixture.debugElement.componentInstance;
1926 | // expect(app.title).toEqual('app');
1927 | expect(app.title).toEqual('angular-unit-test-demo!');
1928 | }));
1929 |
1930 | it('should render title in a h1 tag', async(() => {
1931 | const fixture = TestBed.createComponent(AppComponent);
1932 | fixture.detectChanges();
1933 | const compiled = fixture.debugElement.nativeElement;
1934 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to angular-unit-test-demo!');
1935 | }));
1936 |
1937 | });
1938 | ```
1939 |
1940 | 8.3. ATB Angular TestBed
1941 | ---------------------
1942 |
1943 | ### 8.3.1. What is ATB Angular TestBed?
1944 |
1945 | - `TestBed` is the `primary API for writing unit tests` for Angular applications and libraries
1946 | - `TestBed` is the basic building block of the angular testing module also the main utility available for Angular-specific testing
1947 | - `TestBed` class provides various utility methods to deal with test cases
1948 | - `Configures and initializes environment for unit testing` and provides methods for creating components and services in unit tests
1949 | - The Angular Test Bed (ATB) is a `higher level Angular Only testing framework` that allows us to easily test behaviors that depend on the Angular Framework
1950 | - Angular TestBed provides slightly easier way/methods/utilities to create components, handle injection, test asynchronous behavior and interact with our application
1951 | - With the help of various utilities of as mentioned above, it `makes the writing test cases with Jasmine easier`
1952 | - `TestBed.configureTestingModule()` this is where we configure the spec file takes a similar configuration and emulates as `@NgModule`. So, It creates a dynamic testing module and always put this configuration in the `beforeEach()` which runs before every test method
1953 | - Test suite's/test file's `beforeEach()` block consists of `TestBed.configureTestingModule()` which give it an object with similar values as a regular `NgModule` for `declarations`, `providers` and `imports`. We can then chain a call to `compileComponents` to tell Angular to compile the declared components
1954 | - We can create a component fixture with `TestBed.createComponent()`, Fixtures have access to a `debugElement`, which will give you access to the internals of the component fixture
1955 |
1956 | ### 8.3.2. When to Use Angular Test Bed?
1957 |
1958 | We need to use the Angular Test Bed process to perform unit testing of the following things:
1959 |
1960 | - Test Bed allows us to test the interaction of a component or directive with its templates
1961 | - debugElement, nativeElement, triggerEventHandler, classes
1962 | - It also allows us to easily test change the detection mechanism of the Angular
1963 | - fixture.detectChanges();
1964 | - It also allows us to test the Dependency Injection process
1965 | - `providers: [ Dependency ServicesName ],`
1966 | - It allows us to run tests using NgModule configuration, which we use in our application:
1967 |
1968 | ```typescript
1969 |
1970 | TestBed.configureTestingModule({
1971 |
1972 | imports: [ Dependency ModuleName, ],
1973 | providers: [ Dependency ServicesName ],
1974 | declarations: [ Current ComponentName, Dependency ComponentName ]
1975 |
1976 | });
1977 |
1978 | ```
1979 | - It allows us to test user interactions including clicks and input field operation
1980 | - triggerEventHandler
1981 |
1982 | ### 8.3.3. Component fixture
1983 |
1984 | We can create a component fixture with `TestBed.createComponent()`, Fixtures have access to a `debugElement`, which will give you access to the internals of the component fixture
1985 |
1986 | Component fixture class is a wrapper around component with this we can:
1987 | - get an instance of the component,
1988 | - get DOM elements via nativeElement or debugElement properties,
1989 | - we can also run change detection manually, and
1990 | - we can also get one or more injected dependencies in this component
1991 |
1992 |
1993 | 8.4. Integration Test-Property binding
1994 | ---------------------
1995 |
1996 | > **Note: What to test?**
1997 | - All types of bindings: `property binding, class binding, style binding, event binding`
1998 | - Property binding: `{{ totalCount }}` or interpolation or some value-class property binding render accurately
1999 | - Class binding: some classes like `[class.highlighted]` conditionally applied correctly
2000 | - Component object: `Component object initialized`/created properly
2001 | - Event binding: Methods like `(click)="upCount()"` invoked flawlessly
2002 |
2003 | > **Syntax & Example**: `02-integration-test/01-property-binding/counter-property-binding.component.html`
2004 |
2005 | ```typescript
2006 |
2007 |
2022 |
2023 | ```
2024 |
2025 |
2026 |
2027 | > **Syntax & Example**: `02-integration-test/01-property-binding/counter-property-binding.component.ts`
2028 |
2029 | ```typescript
2030 |
2031 | import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
2032 |
2033 | @Component({
2034 | selector: 'app-counter-property-binding',
2035 | templateUrl: './counter-property-binding.component.html',
2036 | styleUrls: ['./counter-property-binding.component.css']
2037 | })
2038 |
2039 | export class CounterPropertyBindingComponent implements OnInit {
2040 |
2041 | constructor() { }
2042 |
2043 | ngOnInit() {
2044 | }
2045 |
2046 | @Input() othersCount = 0;
2047 | @Input() myCount = 0;
2048 |
2049 | @Output() count = new EventEmitter();
2050 |
2051 | upCount() {
2052 | if (this.myCount == 1)
2053 | return;
2054 |
2055 | this.myCount++;
2056 |
2057 | this.count.emit({ myCount: this.myCount });
2058 | }
2059 |
2060 | downCount() {
2061 | if (this.myCount == -1)
2062 | return;
2063 |
2064 | this.myCount--;
2065 |
2066 | this.count.emit({ myCount: this.myCount });
2067 | }
2068 |
2069 | get totalCounts(): number {
2070 | return this.othersCount + this.myCount;
2071 | }
2072 |
2073 | }
2074 |
2075 | ```
2076 |
2077 |
2078 |
2079 | > **Syntax & Example**: `02-integration-test/01-property-binding/counter-property-binding.component.spec.ts`
2080 |
2081 | ```typescript
2082 |
2083 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2084 | import { By } from "@angular/platform-browser";
2085 |
2086 | import { CounterPropertyBindingComponent } from './counter-property-binding.component';
2087 |
2088 | describe('CounterPropertyBindingComponent', () => {
2089 | let component: CounterPropertyBindingComponent;
2090 | let fixture: ComponentFixture;
2091 |
2092 | beforeEach(async(() => {
2093 | TestBed.configureTestingModule({
2094 | declarations: [CounterPropertyBindingComponent]
2095 | })
2096 | .compileComponents();
2097 | }));
2098 |
2099 | beforeEach(() => {
2100 | fixture = TestBed.createComponent(CounterPropertyBindingComponent);
2101 | component = fixture.componentInstance;
2102 | fixture.detectChanges();
2103 | });
2104 |
2105 | it('should create CounterPropertyBindingComponent', () => {
2106 | expect(component).toBeTruthy();
2107 | });
2108 |
2109 | /* binding property - interpolation */
2110 | it('should bind-show-render totalCount', () => {
2111 | component.othersCount = 10
2112 | component.myCount = 5;
2113 | fixture.detectChanges();
2114 |
2115 | let totalCountTextElement = fixture.debugElement.queryAll(By.css('span'));
2116 | let totalCountTextNativeElement: HTMLElement = totalCountTextElement[1].nativeElement;
2117 |
2118 | expect(totalCountTextNativeElement.getAttribute('class')).toBe('totalCountText');
2119 | // expect(totalCountTextNativeElement.innerText).toContain(15);
2120 |
2121 | });
2122 |
2123 | /* binding style/class */
2124 | it('should highlight the upCount button if totalCounts is 1', () => {
2125 | component.myCount = 1;
2126 | fixture.detectChanges();
2127 |
2128 | let upCountButtonElement = fixture.debugElement.query(By.css('.icon-menu-up.count-button'));
2129 |
2130 | expect(upCountButtonElement.classes['highlighted']).toBeTruthy();
2131 |
2132 | });
2133 |
2134 | /* binding event */
2135 | it('should increase totalCounts by 1 when upCount button clicked', () => {
2136 | let upCountButtonElement = fixture.debugElement.query(By.css('.icon-menu-up.count-button'));
2137 |
2138 | upCountButtonElement.triggerEventHandler('click', null);
2139 |
2140 | // component.upCount();
2141 |
2142 | expect(component.totalCounts).toEqual(1);
2143 |
2144 | });
2145 |
2146 | });
2147 |
2148 | ```
2149 |
2150 | 8.5. Integration Test-Event binding
2151 | ---------------------
2152 |
2153 | > **Syntax & Example**: `event-binding.component.spec.ts`
2154 |
2155 | ```typescript
2156 |
2157 | /* binding event */
2158 | it('should increase totalCounts by 1 when upCount button clicked', () => {
2159 | let upCountButtonElement = fixture.debugElement.query(By.css('.icon-menu-up.count-button'));
2160 |
2161 | upCountButtonElement.triggerEventHandler('click', null);
2162 |
2163 | // component.upCount();
2164 |
2165 | expect(component.totalCounts).toEqual(1);
2166 |
2167 | });
2168 |
2169 | ```
2170 |
2171 | 8.6. fixture detectChanges
2172 | ---------------------
2173 | 8.6. fixture.detectChanges()
2174 | ---------------------
2175 | - In Angular application whenever we make any changes in DOM element, Angular runs its `change Detection` algorithm automatically
2176 | - **Note**: In a testing environment, Angular does not run the `change Detection` algorithm automatically so we need to explicitly/manually call it by using `fixture.detectChanges();`
2177 | - In a testing environment, Angular doesn't automatically bind the component's properties with the template elements.
2178 | - You have to explicitly call `fixture.detectChanges()` every time you want to `bind a component property with the template`
2179 | - `fixture.detectChanges()` is called to `update the DOM with the new values`
2180 | - We use `fixture.detectChanges` to instruct Angular to `run change detection` before doing our assertions with Jasmine’s `expect`
2181 | - By using the `ATB = Angular TestBed` and `fixtures` we can inspect the components view through `fixture.debugElement` and also trigger a change detection run by calling `fixture.detectChanges()`
2182 | - When we create a component on the TestBed, Angular does not automatically initiate change detection which means that our `template will not be rendered with its bindings evaluated`
2183 | - This simply means that `we need to manually trigger change detection` thankfully our handy `component fixture` makes this easy
2184 | - Whenever we want to trigger change detection, we just need to call `fixture.detectChanges` either at the bottom of our `beforeEach` block or in every test cases
2185 |
2186 | > **Syntax & Example**: `fixture.detectChanges()`
2187 |
2188 | ```typescript
2189 |
2190 | it('should highlight the upCount button if totalCounts is 1', () => {
2191 | component.myCount = 1;
2192 | fixture.detectChanges();
2193 |
2194 | let upCountButtonElement = fixture.debugElement.query(By.css('count-button'));
2195 |
2196 | expect(upCountButtonElement.classes['highlighted']).toBeTruthy();
2197 |
2198 | });
2199 |
2200 | it('should have a title Welcome to Angular Testing', () => {
2201 | component.title = 'Welcome to Angular Testing';
2202 |
2203 | fixture.detectChanges();
2204 |
2205 | expect(element.textContent).toContain(component.title);
2206 |
2207 | })
2208 |
2209 | ```
2210 |
2211 | 8.7. Integration Test-Providing dependencies
2212 | ---------------------
2213 |
2214 | - In case of Unit test, we use to provide dependencies used in constructor as `loginFormComponent = new LoginFormComponent(new FormBuilder);`
2215 | - But for the Integration test, we have to use a different approach as `providers`, the same as we used in module.ts/class files
2216 | - Any external services used at Component level must be added under .spec/test `providers` (in some cases we need to mention Module level dependencies/services also like HTTP or HttpModule)
2217 |
2218 | > **Syntax & Example**: `Providers in Integration test:`
2219 |
2220 | ```typescript
2221 |
2222 | import { Dependency ServicesName } from './path';
2223 |
2224 | TestBed.configureTestingModule({
2225 | imports: [ Dependency ModuleName, HttpModule ],
2226 | providers: [ Dependency ServicesName, DataService ],
2227 | declarations: [ Current ComponentName, Dependency ComponentName, EmployeeComponents ]
2228 | });
2229 |
2230 | ```
2231 |
2232 | > **Note**: If dependencies are not provided properly than we get `Error: No provider for service!`. In the case of component, dependencies can be added at either Module level or Component level.
2233 |
2234 |
2235 | 8.8. Testing OnInit ngOnInit
2236 | ---------------------
2237 | 8.8. Getting dependencies
2238 | ---------------------
2239 |
2240 | - In Angular application, `ngOnInit` method is called by Angular automatically at the time of component initialization
2241 | - If `implements OnInit` or `export class ComponentName implements OnInit` statement is used than only `ngOnInit()` method executes automatically else `ngOnInit()` is normal method present in class
2242 | - When performing testing we need to call `component lifecycle hooks ourselves`, like `ngOnInit()` by ourself as `component.ngOnInit()`, Angular won’t do this for us in the test environment
2243 |
2244 |
2245 |
2246 | If Module level dependencies used in `module.ts` as: `providers: []` than write test case as `it('should load todos from the server', () => { let loginService = TestBed.get(LoginService)})`
2247 |
2248 | > **Syntax & Example**: `module level service dependencies inserted under providers arrays`
2249 |
2250 | ```typescript
2251 | @NgModule({
2252 | imports: [
2253 | CommonModule
2254 | ],
2255 | providers: [
2256 | LoginService,
2257 | AuthenticationService,
2258 | ]
2259 | declarations: [ LoginComponent ]
2260 | })
2261 |
2262 | ```
2263 |
2264 | To get dependencies used at component level write test case as `it('should load todos from the component', () => { let loginService = fixture.debugElement.injector.get(LoginService)})`
2265 |
2266 | ```typescript
2267 | @Component({
2268 | selector: 'login-component',
2269 | templateUrl: './login.component.html',
2270 | styleUrls: ['./login.component.scss'],
2271 | providers: [LoginService, AuthenticationService]
2272 |
2273 | })
2274 | ```
2275 |
2276 | 8.9. Why do we use NO ERRORS SCHEMA
2277 | ---------------------
2278 | 8.9. Why do we use NO_ERRORS_SCHEMA
2279 | ---------------------
2280 |
2281 | ### 8.9.1. What is NO_ERRORS_SCHEMA
2282 |
2283 | Defines a schema that allows any property on any element, so Angular Test ignores any custom elements, attributes in HTML file while testing.
2284 |
2285 | https://medium.com/bb-tutorials-and-thoughts/angular-a-comprehensive-guide-to-unit-testing-with-angular-and-best-practices-e1f9ef752e4e
2286 |
2287 | Let’s run the npm test and we would see a bunch of errors because of nesting components. since the app component has other components inside such as header, footer, and add-item.component, etc.. We have to declare those in the app.component.spec.ts file `TestBed.configureTestingModule()` blocks `declarations` array
2288 |
2289 | Another way is to use `NO_ERRORS_SCHEMA` which tell angular `“Angular, please ignore all the unrecognized tags while testing app.component”`
2290 |
2291 | > **Syntax & Example**: `schemas: [ NO_ERRORS_SCHEMA ]`
2292 |
2293 | ```typescript
2294 | import { NO_ERRORS_SCHEMA } from '@angular/core';
2295 |
2296 | beforeEach(async(() => {
2297 |
2298 | TestBed.configureTestingModule({
2299 |
2300 | declarations: [ ComponentName ],
2301 |
2302 | schemas: [ NO_ERRORS_SCHEMA ]
2303 |
2304 | }).compileComponents();
2305 |
2306 | }));
2307 |
2308 | ```
2309 |
2310 | ### 8.9.2. Why you shouldn’t use NO_ERRORS_SCHEMA in Angular Unit Tests
2311 |
2312 | `NO_ERRORS_SCHEMA` simply telling the TestBed to ignore any template errors.
2313 | So, while testing when it hits `` tag, you don’t have to import `HeaderComponent` into your TestBed in your spec file. Angular will just treat that tag like any old div and continue on its way. In the above example, you don’t need to import any of the child components as well as custom components of ParentComponent.
2314 |
2315 | However, there’s a big gotcha! and thing to understand for everyone is that: it also will `ignore unknown attributes; both property bindings and event handlers`. Here is an example:
2316 |
2317 | ```typescript
2318 |
2319 |
2320 |
2321 | ```
2322 |
2323 | Now let us discuss the problem - The bindings in FooterComponent are to `[checking]` and (customClicked) not `click`. But the `unit tests will still compile! They’ll even run!`.
2324 |
2325 | `ng build --prod` will catch the property binding problem, `[checking]`, but will not catch the misnamed (customClicked) handler. The only way to find that one is in integration testing! so overpowering `NO_ERRORS_SCHEMA` could be causing damage.
2326 |
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/1-angualr-jasmine-karma-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/1-angualr-jasmine-karma-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/1-karma-jasmine-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/1-karma-jasmine-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/1.5.1-codebase-to-develop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/1.5.1-codebase-to-develop.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/1.5.2-production-development-cost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/1.5.2-production-development-cost.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/1.5.3-manual-automated-testing-cost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/1.5.3-manual-automated-testing-cost.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/2.1.1-unit-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/2.1.1-unit-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/2.1.2-integration-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/2.1.2-integration-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.1-jasmine-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.1-jasmine-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.2-karma-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.2-karma-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.3-protractor-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.3-protractor-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.4-phantomjs-logo-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.4-phantomjs-logo-2.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.6-sinon-logo-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.6-sinon-logo-1.jpg
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.7-chai-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.7-chai-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/3.2.8-mocha-logo-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/3.2.8-mocha-logo-1.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/4.1.1-app-folder-structure-ng-serve-command.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/4.1.1-app-folder-structure-ng-serve-command.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/4.1.2-ng-serve-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/4.1.2-ng-serve-output.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/4.1.3-ng-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/4.1.3-ng-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/4.1.4-ng-test-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/4.1.4-ng-test-output.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/4.2.1-package-dependencies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/4.2.1-package-dependencies.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1a-function-counter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1a-function-counter.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1b-unit-test-function-counter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1b-unit-test-function-counter.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1c-ng-test-function-counter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1c-ng-test-function-counter.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1d-ng-test-output-function-counter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1d-ng-test-output-function-counter.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1e-ng-test-function-all-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1e-ng-test-function-all-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.1.1f-ng-test-output-function-all-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.1.1f-ng-test-output-function-all-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.3.1a-run-specific-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.3.1a-run-specific-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.3.1b-run-specific-test-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.3.1b-run-specific-test-output.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.3.1c-ignore-specific-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.3.1c-ignore-specific-test.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/6.3.1d-ignore-specific-test-output.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/6.3.1d-ignore-specific-test-output.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/7.1.1-code-coverage-folder-structure-explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/7.1.1-code-coverage-folder-structure-explorer.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/7.1.2-code-coverage-folder-structure-vs-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/7.1.2-code-coverage-folder-structure-vs-code.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/7.1.3-code-coverage-index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/7.1.3-code-coverage-index.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/7.1.4-code-coverage-individual-component.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/7.1.4-code-coverage-individual-component.png
--------------------------------------------------------------------------------
/_images-angular-unit-testing-jasmine-karma/7.1.5-code-coverage-red-green-whats-covered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dinanathsj29/angular-unit-testing-jasmine-karma-tutorial/dd57ad6a01a4be186c9a588a86ae661516a20c0d/_images-angular-unit-testing-jasmine-karma/7.1.5-code-coverage-red-green-whats-covered.png
--------------------------------------------------------------------------------