├── README.md └── _images-angular-unit-testing-jasmine-karma ├── 1-angualr-jasmine-karma-logo-1.png ├── 1-karma-jasmine-logo-1.png ├── 1.5.1-codebase-to-develop.png ├── 1.5.2-production-development-cost.png ├── 1.5.3-manual-automated-testing-cost.png ├── 2.1.1-unit-test.png ├── 2.1.2-integration-test.png ├── 3.2.1-jasmine-logo-1.png ├── 3.2.2-karma-logo-1.png ├── 3.2.3-protractor-logo-1.png ├── 3.2.4-phantomjs-logo-2.png ├── 3.2.6-sinon-logo-1.jpg ├── 3.2.7-chai-logo-1.png ├── 3.2.8-mocha-logo-1.png ├── 4.1.1-app-folder-structure-ng-serve-command.png ├── 4.1.2-ng-serve-output.png ├── 4.1.3-ng-test.png ├── 4.1.4-ng-test-output.png ├── 4.2.1-package-dependencies.png ├── 6.1.1a-function-counter.png ├── 6.1.1b-unit-test-function-counter.png ├── 6.1.1c-ng-test-function-counter.png ├── 6.1.1d-ng-test-output-function-counter.png ├── 6.1.1e-ng-test-function-all-test.png ├── 6.1.1f-ng-test-output-function-all-test.png ├── 6.3.1a-run-specific-test.png ├── 6.3.1b-run-specific-test-output.png ├── 6.3.1c-ignore-specific-test.png ├── 6.3.1d-ignore-specific-test-output.png ├── 7.1.1-code-coverage-folder-structure-explorer.png ├── 7.1.2-code-coverage-folder-structure-vs-code.png ├── 7.1.3-code-coverage-index.png ├── 7.1.4-code-coverage-individual-component.png └── 7.1.5-code-coverage-red-green-whats-covered.png /README.md: -------------------------------------------------------------------------------- 1 |

2 | Angular Jasmine Karma Logo 3 |

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 |     Codebase to develop 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 |     Production development cost 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 |

237 |

238 |     Manual vs Automated testing cost 239 |
    Image - Manual vs Automated testing cost
240 |
241 |

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 |

361 |

362 |     Unit Testing 363 |
    Image - Unit Testing
364 |
365 |

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 |

380 |

381 |     Integration Testing 382 |
    Image - Integration Testing
383 |
384 |

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 | Jasmine - Assertion Library - Write Unit Test 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 | Karma - A test runner 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 | Protractor - Write End-to-End test 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 | Phantomjs - Headless GUI-less Browser 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 | Sinonjs - Standalone test spies, stubs and mocks 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 | Chai - BDD/TDD Assertion Library - Write Unit Test 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 | Mocha - A test runner 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 |

593 |

594 |     Angular App Folder Structure - ng serve 595 |
    Image - Angular App Folder Structure - ng serve
596 |
597 |

598 | 599 |

600 |

601 |     Running Angular App - ng serve output 602 |
    Image - Running Angular App - ng serve output
603 |
604 |

605 | 606 |

607 |

608 |     Executing ng test command 609 |
    Image - Executing ng test command
610 |
611 |

612 | 613 |

614 |

615 |     Running Angular Test - ng test output 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 |

626 |

627 |     Testing packages-dependencies 628 |
    Image - Testing packages-dependencies
629 |
630 |

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 |

902 |

903 |     Unit Testing file/folder - counter component 904 |
    Image - Unit Testing file/folder - counter component
905 |
906 |

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 |     Unit Testing - counter .spec test file 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 |     Unit Testing - Running test 953 |
    Image - Unit Testing - Running test
954 |
955 |

956 | 957 | 958 |

959 |

960 |     Unit Testing - Running test - Browser Karma output 961 |
    Image - Unit Testing - Running test - Browser Karma output
962 |
963 |

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 |     Unit Testing - Running all tests 1022 |
    Image - Unit Testing - Running all tests
1023 |
1024 |

1025 | 1026 | 1027 |

1028 |

1029 |     Unit Testing - Running all test - Browser Karma output 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 |     Unit Testing - Running specific test 1173 |
    Image - Unit Testing - Running specific test
1174 |
1175 |

1176 | 1177 | 1178 |

1179 |

1180 |     Unit Testing - Running specific test - Browser Karma output 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 |     Unit Testing - Ignore specific test 1220 |
    Image - Unit Testing - Ignore specific test
1221 |
1222 |

1223 | 1224 | 1225 |

1226 |

1227 |     Unit Testing - Ignore specific test - Browser Karma output 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 |

1801 |

1802 |     code coverage - folder structure 1803 |
    Image - code coverage - folder structure
1804 |
1805 |

1806 | 1807 |
1808 | 1809 |

1810 |

1811 |     code coverage - folder structure - vs code 1812 |
    Image - code coverage - folder structure - vs code
1813 |
1814 |

1815 | 1816 |
1817 | 1818 | If you load the `coverage/index.html` from this folder in the browser, we can see the full report: 1819 | 1820 |

1821 |

1822 |     code coverage - index - full report 1823 |
    Image - code coverage - index - full report
1824 |
1825 |

1826 | 1827 |
1828 | 1829 |

1830 |

1831 |     code coverage - individual component 1832 |
    Image - code coverage - individual component
1833 |
1834 |

1835 | 1836 |
1837 | 1838 |

1839 |

1840 |     code coverage - Red Gren Highlight - Whats covered 1841 |
    Image - code coverage - Red Gren Highlight - Whats covered
1842 |
1843 |

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 |
2008 | 2009 | 2010 | Up Count 2011 | 2012 | 2013 | 2014 | Total: 2015 | {{ totalCounts }} 2016 | 2017 | 2018 | Down Count 2019 | 2020 | 2021 |
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 --------------------------------------------------------------------------------