├── LICENSE ├── Mocha-Unit-Testing-Example ├── .gitignore ├── README.md ├── js │ └── className.js ├── package.json ├── test │ ├── arrayTest.js │ └── classNameTest.js └── testrunner.html ├── README.md ├── Section-1 ├── 1.3 │ └── 01-Writing-your-first-unit-test │ │ ├── .DS_Store │ │ ├── after │ │ ├── .gitignore │ │ ├── math.js │ │ └── package.json │ │ └── before │ │ ├── .gitignore │ │ ├── math.js │ │ └── package.json ├── 1.4 │ └── 04-testing-numbers-and-strings │ │ ├── .DS_Store │ │ ├── after │ │ ├── .DS_Store │ │ ├── math.js │ │ ├── package.json │ │ ├── tests │ │ │ ├── math.test.js │ │ │ └── util.test.js │ │ └── util.js │ │ └── before │ │ ├── .DS_Store │ │ ├── math.js │ │ ├── package.json │ │ ├── tests │ │ ├── .DS_Store │ │ └── math.test.js │ │ └── util.js ├── 1.5 │ └── 05-testing-thruthiness │ │ ├── .DS_Store │ │ ├── after │ │ ├── package.json │ │ ├── tests │ │ │ └── util.test.js │ │ └── util.js │ │ └── before │ │ ├── package.json │ │ ├── tests │ │ └── util.test.js │ │ └── util.js ├── 1.6 │ └── 06-testing-arrays-and-objects │ │ ├── after │ │ ├── .DS_Store │ │ ├── package.json │ │ ├── tests │ │ │ └── util.test.js │ │ └── util.js │ │ └── before │ │ ├── package.json │ │ ├── tests │ │ └── util.test.js │ │ └── util.js └── 1.7 │ └── 07-testing-exceptions │ ├── .DS_Store │ ├── after │ ├── package.json │ ├── tests │ │ └── util.test.js │ └── util.js │ └── before │ ├── .DS_Store │ ├── package.json │ ├── tests │ └── util.test.js │ └── util.js ├── Section-2 ├── 2.2 │ ├── BankAccount.js │ ├── package.json │ └── tests │ │ └── BankAcount.test.js └── 2.4 │ ├── Gruntfile.js │ ├── README.md │ ├── features │ └── addition.feature │ ├── gulpfile.js │ ├── package-lock.json │ └── package.json ├── Section-3 ├── 3.1 │ ├── package-lock.json │ ├── package.json │ └── tests │ │ └── assert-demo.test.js ├── 3.2 │ ├── math.js │ ├── package-lock.json │ ├── package.json │ └── tests │ │ ├── assert-demo.test.js │ │ ├── chai.js-demo.test.js │ │ ├── expect-demo.test.js │ │ └── should.js-demo.test.js ├── 3.3 │ ├── math.js │ ├── package-lock.json │ ├── package.json │ └── tests │ │ ├── assert-demo.test.js │ │ ├── chai.js-demo.test.js │ │ ├── expect-demo.test.js │ │ └── should.js-demo.test.js └── 3.4 │ ├── math.js │ ├── package-lock.json │ ├── package.json │ └── tests │ ├── assert-demo.test.js │ ├── chai.js-demo.test.js │ ├── expect-demo.test.js │ └── should.js-demo.test.js ├── Section-4 ├── 4.1 │ ├── package-lock.json │ ├── package.json │ └── spec │ │ ├── math.spec.js │ │ └── support │ │ └── jasmine.json ├── 4.2 │ ├── math.js │ ├── package-lock.json │ ├── package.json │ └── test │ │ ├── db.js │ │ └── test.js ├── 4.3 │ ├── data.txt │ ├── package-lock.json │ ├── package.json │ └── tests │ │ └── math.test.js ├── 4.4 │ ├── package-lock.json │ ├── package.json │ └── tests │ │ └── test.js └── 4.5 │ ├── intern.json │ ├── package-lock.json │ ├── package.json │ └── tests │ └── unit │ └── test.js ├── Section-5 ├── config-overrides.js ├── package.json └── src │ ├── __mocks__ │ └── axios.js │ └── services │ ├── __tests__ │ ├── posts.js │ └── users.js │ ├── posts.js │ └── users.js ├── javascript-unit-testing-with-mocha ├── .gitignore ├── 01-basic-spec │ ├── .gitignore │ ├── package.json │ └── test │ │ └── test.js ├── 02-testing-function │ ├── .gitignore │ ├── controllers │ │ └── login.controller.js │ ├── package.json │ └── test │ │ └── controllers │ │ └── login.controller.spec.js ├── 03-async-callback │ ├── .gitignore │ ├── controllers │ │ └── login.controller.js │ ├── package.json │ └── test │ │ └── controllers │ │ └── login.controller.spec.js ├── 04-hooks │ ├── .gitignore │ ├── controllers │ │ └── login.controller.js │ ├── package.json │ └── test │ │ └── controllers │ │ └── login.controller.spec.js ├── 05-expect-should │ ├── .gitignore │ ├── controllers │ │ └── login.controller.js │ ├── package.json │ └── test │ │ └── controllers │ │ └── login.controller.spec.js ├── 06-promise │ ├── .gitignore │ ├── controllers │ │ └── login.controller.js │ ├── package.json │ └── test │ │ └── controllers │ │ └── login.controller.spec.js ├── 07-chai-assertion │ ├── .gitignore │ ├── package.json │ └── test │ │ └── test.js └── README.md ├── js-unit-test-examples ├── .gitignore ├── LICENSE ├── README.md ├── ava-nyc │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── MathLib │ │ ├── add.test.js │ │ ├── fibonacci.test.js │ │ └── multiply.test.js ├── ava │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── MathLib │ │ ├── add.test.js │ │ ├── fibonacci.test.js │ │ └── multiply.test.js ├── jasmine-chutzpah │ ├── Program.cs │ ├── chutzpah.json │ ├── jasmine-chutzpah.csproj │ ├── jasmine-chutzpah.sln │ ├── spec │ │ └── index.spec.js │ └── src │ │ └── index.js ├── jasmine │ ├── package.json │ ├── spec │ │ ├── index.spec.js │ │ └── support │ │ │ └── jasmine.json │ └── src │ │ └── index.js ├── jest │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── index.test.js ├── mocha-chai-istanbul │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── index.test.js ├── mocha-chai-ts-istanbul │ ├── package.json │ ├── src │ │ └── index.ts │ └── test │ │ └── index.test.ts ├── mocha-chai-ts │ ├── package.json │ ├── src │ │ └── index.ts │ └── test │ │ └── index.test.ts ├── mocha-chai │ ├── package.json │ ├── src │ │ └── index.js │ └── test │ │ └── index.test.js └── tap-nyc │ ├── package.json │ ├── src │ └── index.js │ └── test │ └── MathLib │ ├── add.spec.js │ ├── fibonacci.spec.js │ └── multiply.spec.js └── js-unit-testing-examples ├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── index.js ├── package.json ├── src ├── data │ └── fakeData.js ├── launch.js ├── middleware │ ├── api │ │ └── eventsGetAll.js │ ├── authenticate.js │ ├── dashboard.js │ ├── homepage.js │ ├── login.js │ └── promiseTest.js ├── routes │ └── api.js └── services │ └── events.js └── test ├── examples └── asynchronous.test.js ├── mocha.opts ├── src ├── launch.test.js └── middleware │ ├── api │ └── dataGetAll.test.js │ ├── promiseTest.test.js │ └── services │ └── events.test.js └── support └── base.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started with JavaScript Unit Testing Using Mocha 2 | 3 | Code to accompany the following article: http://www.sitepoint.com/unit-test-javascript-mocha-chai 4 | 5 | To run the code samples: 6 | 7 | - Clone the repo 8 | - Run `npm install` 9 | - Open `testrunner.html` in browser 10 | - Alternatively, uncomment Node specific code and run `mocha` from the command line (this requires Mocha to be installed globally). 11 | 12 | License MIT 13 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/js/className.js: -------------------------------------------------------------------------------- 1 | // Browser version 2 | function addClass(el, newClass) { 3 | if(el.className.indexOf(newClass) !== -1) { 4 | return; 5 | } 6 | 7 | if(el.className !== '') { 8 | //ensure class names are separated by a space 9 | newClass = ' ' + newClass; 10 | } 11 | 12 | el.className += newClass; 13 | } 14 | 15 | // Node Version 16 | // module.exports = { 17 | // addClass: function(el, newClass) { 18 | // if(el.className.indexOf(newClass) !== -1) { 19 | // return; 20 | // } 21 | 22 | // if(el.className !== '') { 23 | // //ensure class names are separated by a space 24 | // newClass = ' ' + newClass; 25 | // } 26 | 27 | // el.className += newClass; 28 | // } 29 | // } 30 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mocha-unit-testing", 3 | "version": "1.0.0", 4 | "description": "Mocha Tests", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "author": "Jani Hartikainen", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "chai": "^3.4.1", 13 | "mocha": "^2.3.4" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/test/arrayTest.js: -------------------------------------------------------------------------------- 1 | // Uncomment if using Node 2 | // var chai = require('chai'); 3 | var assert = chai.assert; 4 | 5 | describe('Array', function() { 6 | it('should start empty', function() { 7 | var arr = []; 8 | 9 | assert.equal(arr.length, 0); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/test/classNameTest.js: -------------------------------------------------------------------------------- 1 | // Uncomment if using Node 2 | // var chai = require('chai'); 3 | var assert = chai.assert; 4 | 5 | // var className = require('../js/className.js'); 6 | // var addClass = className.addClass; 7 | 8 | describe('addClass', function() { 9 | it('should add class into element', function() { 10 | var element = { className: '' }; 11 | 12 | addClass(element, 'test-class'); 13 | 14 | assert.equal(element.className, 'test-class'); 15 | }); 16 | 17 | it('should not add a class which already exists in element', function() { 18 | var element = { className: 'exists' }; 19 | 20 | addClass(element, 'exists'); 21 | 22 | var numClasses = element.className.split(' ').length; 23 | assert.equal(numClasses, 1); 24 | }); 25 | 26 | it('should append new class after existing one', function() { 27 | var element = { className: 'exists' }; 28 | 29 | addClass(element, 'new-class'); 30 | 31 | var classes = element.className.split(' '); 32 | assert.equal(classes[1], 'new-class'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /Mocha-Unit-Testing-Example/testrunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mocha Tests 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Unit Testing 2 | 3 | > *Click ★ if you like the project. Your contributions are heartily ♡ welcome.* 4 | 5 |
6 | 7 | **Unit = Unit of work** 8 | 9 | This could involve **multiple methods and classes** invoked by some public API that can: 10 | 11 | + Return a value or throw an exception 12 | + Change the state of the system 13 | + Make 3rd party calls (API, database, ...) 14 | 15 | A unit test should test the behaviour of a unit of work: for a given input, it expects an end result that can be any of the above. 16 | 17 | **Unit tests are isolated and independent of each other** 18 | 19 | + Any given behaviour should be specified in **one and only one test** 20 | + The execution/order of execution of one test **cannot affect the others** 21 | 22 | The code is designed to support this independence (see "Design principles" below). 23 | 24 | **Unit tests are lightweight tests** 25 | 26 | + Repeatable 27 | + Fast 28 | + Consistent 29 | + Easy to write and read 30 | 31 | **Unit tests are code too** 32 | 33 | They should meet the same level of quality as the code being tested. They can be refactored as well to make them more maintainable and/or readable. 34 | 35 | 36 | 37 | ### Design principles 38 | 39 | The key to good unit testing is to write **testable code**. Applying simple design principles can help, in particular: 40 | 41 | + Use a **good naming** convention and **comment** your code (the "why?" not the "how"), keep in mind that comments are not a substitute for bad naming or bad design 42 | + **DRY**: Don't Repeat Yourself, avoid code duplication 43 | + **Single responsibility**: each object/function must focus on a single task 44 | + Keep a **single level of abstraction** in the same component (for example, do not mix business logic with lower-level technical details in the same method) 45 | + **Minimize dependencies** between components: encapsulate, interchange less information between components 46 | + **Support configurability** rather than hard-coding, this prevents having to replicate the exact same environment when testing (e.g.: markup) 47 | + Apply adequate **design patterns**, especially **dependency injection** that allows separating an object's creation responsibility from business logic 48 | + Avoid global mutable state 49 | 50 |
51 | ↥ back to top 52 |
53 | 54 | ## Guidelines 55 | 56 | The goal of these guidelines is to make your tests: 57 | 58 | + **Readable** 59 | + **Maintainable** 60 | + **Trustworthy** 61 | 62 | These are the 3 pillars of good unit testing. 63 | 64 | All the following examples assume the usage of the [Jasmine](http://jasmine.github.io) framework. 65 | 66 | 67 | ### Whenever possible, use TDD 68 | 69 | TDD is a _design process_, not a testing process. TDD is a robust way of designing software components ("units") interactively so that their behaviour is specified through unit tests. 70 | 71 | How? Why? 72 | 73 | #### Test-first cycle 74 | 75 | 1. Write a simple failing test 76 | 2. Make the test pass by writing the minimum amount of code, don't bother with code quality 77 | 3. Refactor the code by applying design principles/patterns 78 | 79 | #### Consequences of the test-first cycle 80 | 81 | + Writing a test first makes the code design testable de facto 82 | + Writing just the amount of code needed to implement the required functionality makes the resulting codebase minimal, thus more maintainable 83 | + The codebase can be enhanced using refactoring mechanisms, the tests give you confidence that the new code is not modifying the existing functionalities 84 | + Cleaning the code in each cycle makes the codebase more maintainable, it is much cheaper to change the code frequently and in small increments 85 | + Fast feedback for the developers, you know that you don't break anything and that you are evolving the system in a good direction 86 | + Generates confidence to add features, fix bugs, or explore new designs 87 | 88 | Note that code written without a test-first approach is often very hard to test. 89 | 90 |
91 | ↥ back to top 92 |
93 | 94 | ### Structure your tests properly 95 | 96 | Don't hesitate to nest your suites to structure logically your tests in subsets. 97 | 98 | **:(** 99 | 100 | ```js 101 | describe('A set of functionalities', () => { 102 | it('a set of functionalities should do something nice', () => { 103 | }); 104 | 105 | it('a subset of functionalities should do something great', () => { 106 | }); 107 | 108 | it('a subset of functionalities should do something awesome', () => { 109 | }); 110 | 111 | it('another subset of functionalities should also do something great', () => { 112 | }); 113 | }); 114 | ``` 115 | 116 | **:)** 117 | 118 | ```js 119 | describe('A set of functionalities', () => { 120 | it('should do something nice', () => { 121 | }); 122 | 123 | describe('A subset of functionalities', () => { 124 | it('should do something great', () => { 125 | }); 126 | 127 | it('should do something awesome', () => { 128 | }); 129 | }); 130 | 131 | describe('Another subset of functionalities', () => { 132 | it('should also do something great', () => { 133 | }); 134 | }); 135 | }); 136 | ``` 137 | 138 |
139 | ↥ back to top 140 |
141 | 142 | ### Name your tests properly 143 | 144 | Tests names should be concise, explicit, descriptive and in correct English. Read the output of the spec runner and verify that it is understandable! Keep in mind that someone else will read it too. Tests can be the live documentation of the code. 145 | 146 | **:(** 147 | 148 | ```js 149 | describe('MyGallery', () => { 150 | it('init set correct property when called (thumb size, thumbs count)', () => { 151 | }); 152 | 153 | // ... 154 | }); 155 | ``` 156 | 157 | **:)** 158 | 159 | ```js 160 | describe('The Gallery instance', () => { 161 | it('should properly calculate the thumb size when initialized', () => { 162 | }); 163 | 164 | it('should properly calculate the thumbs count when initialized', () => { 165 | }); 166 | 167 | // ... 168 | }); 169 | ``` 170 | 171 | In order to help you write test names properly, you can use the **"unit of work - scenario/context - expected behaviour"** pattern: 172 | 173 | ```js 174 | describe('[unit of work]', () => { 175 | it('should [expected behaviour] when [scenario/context]', () => { 176 | }); 177 | }); 178 | ``` 179 | 180 | Or whenever you have many tests that follow the same scenario or are related to the same context: 181 | 182 | ```js 183 | describe('[unit of work]', () => { 184 | describe('when [scenario/context]', () => { 185 | it('should [expected behaviour]', () => { 186 | }); 187 | }); 188 | }); 189 | ``` 190 | 191 | For example: 192 | 193 | **:) :)** 194 | 195 | ```js 196 | describe('The Gallery instance', () => { 197 | describe('when initialized', () => { 198 | it('should properly calculate the thumb size', () => { 199 | }); 200 | 201 | it('should properly calculate the thumbs count', () => { 202 | }); 203 | }); 204 | 205 | // ... 206 | }); 207 | ``` 208 | 209 |
210 | ↥ back to top 211 |
212 | 213 | ### Don't comment out tests 214 | 215 | Never. Ever. Tests have a reason to be or not. 216 | 217 | Don't comment them out because they are too slow, too complex or produce false negatives. Instead, make them fast, simple and trustworthy. If not, remove them completely. 218 | 219 | 220 | 221 | ### Avoid logic in your tests 222 | 223 | Always use simple statements. Don't use loops and/or conditionals. If you do, you add a possible entry point for bugs in the test itself: 224 | 225 | + Conditionals: you don't know which path the test will take 226 | + Loops: you could be sharing state between tests 227 | 228 | **:(** 229 | 230 | ```js 231 | it('should properly sanitize strings', () => { 232 | let result; 233 | const testValues = { 234 | 'Avion' : 'Avi' + String.fromCharCode(243) + 'n', 235 | 'The-space' : 'The space', 236 | 'Weird-chars-' : 'Weird chars!!', 237 | 'file-name.zip' : 'file name.zip', 238 | 'my-name.zip' : 'my.name.zip' 239 | }; 240 | 241 | for (result in testValues) { 242 | expect(sanitizeString(testValues[result])).toBe(result); 243 | } 244 | }); 245 | ``` 246 | 247 | **:)** 248 | 249 | ```js 250 | it('should properly sanitize strings', () => { 251 | expect(sanitizeString('Avi'+String.fromCharCode(243)+'n')).toBe('Avion'); 252 | expect(sanitizeString('The space')).toBe('The-space'); 253 | expect(sanitizeString('Weird chars!!')).toBe('Weird-chars-'); 254 | expect(sanitizeString('file name.zip')).toBe('file-name.zip'); 255 | expect(sanitizeString('my.name.zip')).toBe('my-name.zip'); 256 | }); 257 | ``` 258 | 259 | Better: write a test for each type of sanitization. It will give a nice output of all possible cases, improving maintainability. 260 | 261 | **:) :)** 262 | 263 | ```js 264 | it('should sanitize a string containing non-ASCII chars', () => { 265 | expect(sanitizeString('Avi'+String.fromCharCode(243)+'n')).toBe('Avion'); 266 | }); 267 | 268 | it('should sanitize a string containing spaces', () => { 269 | expect(sanitizeString('The space')).toBe('The-space'); 270 | }); 271 | 272 | it('should sanitize a string containing exclamation signs', () => { 273 | expect(sanitizeString('Weird chars!!')).toBe('Weird-chars-'); 274 | }); 275 | 276 | it('should sanitize a filename containing spaces', () => { 277 | expect(sanitizeString('file name.zip')).toBe('file-name.zip'); 278 | }); 279 | 280 | it('should sanitize a filename containing more than one dot', () => { 281 | expect(sanitizeString('my.name.zip')).toBe('my-name.zip'); 282 | }); 283 | ``` 284 |
285 | ↥ back to top 286 |
287 | 288 | ### Don't write unnecessary expectations 289 | 290 | Remember, unit tests are a design specification of how a certain *behaviour* should work, not a list of observations of everything the code happens to do. 291 | 292 | **:(** 293 | 294 | ```js 295 | it('should multiply the number passed as parameter and subtract one', () => { 296 | const multiplySpy = spyOn(Calculator, 'multiple').and.callThrough(); 297 | const subtractSpy = spyOn(Calculator, 'subtract').and.callThrough(); 298 | 299 | const result = Calculator.compute(21.5); 300 | 301 | expect(multiplySpy).toHaveBeenCalledWith(21.5, 2); 302 | expect(subtractSpy).toHaveBeenCalledWith(43, 1); 303 | expect(result).toBe(42); 304 | }); 305 | ``` 306 | 307 | **:)** 308 | 309 | ```js 310 | it('should multiply the number passed as parameter and subtract one', () => { 311 | const result = Calculator.compute(21.5); 312 | expect(result).toBe(42); 313 | }); 314 | ``` 315 | 316 | This will improve maintainability. Your test is no longer tied to implementation details. 317 | 318 |
319 | ↥ back to top 320 |
321 | 322 | ### Properly setup the actions that apply to all the tests involved 323 | 324 | **:(** 325 | 326 | ```js 327 | describe('Saving the user profile', () => { 328 | let profileModule; 329 | let notifyUserSpy; 330 | let onCompleteSpy; 331 | 332 | beforeEach(() => { 333 | profileModule = new ProfileModule(); 334 | notifyUserSpy = spyOn(profileModule, 'notifyUser'); 335 | onCompleteSpy = jasmine.createSpy(); 336 | }); 337 | 338 | it('should send the updated profile data to the server', () => { 339 | jasmine.Ajax.install(); 340 | 341 | profileModule.save(); 342 | 343 | const request = jasmine.Ajax.requests.mostRecent(); 344 | 345 | expect(request.url).toBe('/profiles/1'); 346 | expect(request.method).toBe('POST'); 347 | expect(request.data()).toEqual({ username: 'mawrkus' }); 348 | 349 | jasmine.Ajax.uninstall(); 350 | }); 351 | 352 | it('should notify the user', () => { 353 | jasmine.Ajax.install(); 354 | 355 | profileModule.save(); 356 | 357 | expect(notifyUserSpy).toHaveBeenCalled(); 358 | 359 | jasmine.Ajax.uninstall(); 360 | }); 361 | 362 | it('should properly execute the callback passed as parameter', () => { 363 | jasmine.Ajax.install(); 364 | 365 | profileModule.save(onCompleteSpy); 366 | 367 | jasmine.Ajax.uninstall(); 368 | 369 | expect(onCompleteSpy).toHaveBeenCalled(); 370 | }); 371 | }); 372 | ``` 373 | 374 | The setup code should apply to all the tests: 375 | 376 | **:)** 377 | 378 | ```js 379 | describe('Saving the user profile', () => { 380 | let profileModule; 381 | 382 | beforeEach(() => { 383 | jasmine.Ajax.install(); 384 | profileModule = new ProfileModule(); 385 | }); 386 | 387 | afterEach( () => { 388 | jasmine.Ajax.uninstall(); 389 | }); 390 | 391 | it('should send the updated profile data to the server', () => { 392 | profileModule.save(); 393 | 394 | const request = jasmine.Ajax.requests.mostRecent(); 395 | 396 | expect(request.url).toBe('/profiles/1'); 397 | expect(request.method).toBe('POST'); 398 | 399 | }); 400 | 401 | it('should notify the user', () => { 402 | spyOn(profileModule, 'notifyUser'); 403 | 404 | profileModule.save(); 405 | 406 | expect(profileModule.notifyUser).toHaveBeenCalled(); 407 | }); 408 | 409 | it('should properly execute the callback passed as parameter', () => { 410 | const onCompleteSpy = jasmine.createSpy(); 411 | 412 | profileModule.save(onCompleteSpy); 413 | 414 | expect(onCompleteSpy).toHaveBeenCalled(); 415 | }); 416 | }); 417 | ``` 418 | 419 | Consider keeping the setup code minimal to preserve readability and maintainability. 420 | 421 |
422 | ↥ back to top 423 |
424 | 425 | ### Consider using factory functions in the tests 426 | 427 | Factories can: 428 | 429 | + help reduce the setup code, especially if you use dependency injection 430 | + make each test more readable, since the creation is a single function call that can be in the test itself instead of the setup 431 | + provide flexibility when creating new instances (setting an initial state, for example) 432 | 433 | There's a trade-off to find here between applying the DRY principle and readability. 434 | 435 | **:(** 436 | 437 | ```js 438 | describe('User profile module', () => { 439 | let profileModule; 440 | let pubSub; 441 | 442 | beforeEach(() => { 443 | const element = document.getElementById('my-profile'); 444 | pubSub = new PubSub({ sync: true }); 445 | 446 | profileModule = new ProfileModule({ 447 | element, 448 | pubSub, 449 | likes: 0 450 | }); 451 | }); 452 | 453 | it('should publish a topic when a new "like" is given', () => { 454 | spyOn(pubSub, 'notify'); 455 | profileModule.incLikes(); 456 | expect(pubSub.notify).toHaveBeenCalledWith('likes:inc', { count: 1 }); 457 | }); 458 | 459 | it('should retrieve the correct number of likes', () => { 460 | profileModule.incLikes(); 461 | profileModule.incLikes(); 462 | expect(profileModule.getLikes()).toBe(2); 463 | }); 464 | }); 465 | ``` 466 | 467 | **:)** 468 | 469 | ```js 470 | describe('User profile module', () => { 471 | function createProfileModule({ 472 | element = document.getElementById('my-profile'), 473 | likes = 0, 474 | pubSub = new PubSub({ sync: true }) 475 | }) { 476 | return new ProfileModule({ element, likes, pubSub }); 477 | } 478 | 479 | it('should publish a topic when a new "like" is given', () => { 480 | const pubSub = jasmine.createSpyObj('pubSub', ['notify']); 481 | const profileModule = createProfileModule({ pubSub }); 482 | 483 | profileModule.incLikes(); 484 | 485 | expect(pubSub.notify).toHaveBeenCalledWith('likes:inc'); 486 | }); 487 | 488 | it('should retrieve the correct number of likes', () => { 489 | const profileModule = createProfileModule({ likes: 40 }); 490 | 491 | profileModule.incLikes(); 492 | profileModule.incLikes(); 493 | 494 | expect(profileModule.getLikes()).toBe(42); 495 | }); 496 | }); 497 | ``` 498 | 499 | Factories are particularly useful when dealing with the DOM: 500 | 501 | **:(** 502 | 503 | ```js 504 | describe('The search component', () => { 505 | describe('when the search button is clicked', () => { 506 | let container; 507 | let form; 508 | let searchInput; 509 | let submitInput; 510 | 511 | beforeEach(() => { 512 | fixtures.inject(`
513 |
514 | 515 | 516 |
517 |
`); 518 | 519 | container = document.getElementById('container'); 520 | form = container.getElementsByClassName('js-form')[0]; 521 | searchInput = form.querySelector('input[type=search]'); 522 | submitInput = form.querySelector('input[type=submith]'); 523 | }); 524 | 525 | it('should validate the text entered', () => { 526 | const search = new Search({ container }); 527 | spyOn(search, 'validate'); 528 | 529 | search.init(); 530 | 531 | input(searchInput, 'peace'); 532 | click(submitInput); 533 | 534 | expect(search.validate).toHaveBeenCalledWith('peace'); 535 | }); 536 | 537 | // ... 538 | }); 539 | }); 540 | ``` 541 | 542 | **:)** 543 | 544 | ```js 545 | function createHTMLFixture() { 546 | fixtures.inject(`
547 |
548 | 549 | 550 |
551 |
`); 552 | 553 | const container = document.getElementById('container'); 554 | const form = container.getElementsByClassName('js-form')[0]; 555 | const searchInput = form.querySelector('input[type=search]'); 556 | const submitInput = form.querySelector('input[type=submith]'); 557 | 558 | return { 559 | container, 560 | form, 561 | searchInput, 562 | submitInput 563 | }; 564 | } 565 | 566 | describe('The search component', () => { 567 | describe('when the search button is clicked', () => { 568 | it('should validate the text entered', () => { 569 | const { container, form, searchInput, submitInput } = createHTMLFixture(); 570 | const search = new Search({ container }); 571 | spyOn(search, 'validate'); 572 | 573 | search.init(); 574 | 575 | input(searchInput, 'peace'); 576 | click(submitInput); 577 | 578 | expect(search.validate).toHaveBeenCalledWith('peace'); 579 | }); 580 | 581 | // ... 582 | }); 583 | }); 584 | ``` 585 |
586 | ↥ back to top 587 |
588 | 589 | ### Know your testing framework API 590 | 591 | The API documentation of the testing framework/library should be your bedside book! 592 | 593 | Having a good knowledge of the API can help you in reducing the size/complexity of your test code and, in general, help you during development. A simple example: 594 | 595 | **:(** 596 | 597 | ```js 598 | it('should call a method with the proper arguments', () => { 599 | const foo = { 600 | bar: jasmine.createSpy(), 601 | baz: jasmine.createSpy() 602 | }; 603 | 604 | foo.bar('qux'); 605 | 606 | expect(foo.bar).toHaveBeenCalled(); 607 | expect(foo.bar.calls.argsFor(0)).toEqual(['qux']); 608 | }); 609 | 610 | /*it('should do more but not now', () => { 611 | }); 612 | 613 | it('should do much more but not now', () => { 614 | });*/ 615 | ``` 616 | 617 | **:)** 618 | 619 | ```js 620 | fit('should call once a method with the proper arguments', () => { 621 | const foo = jasmine.createSpyObj('foo', ['bar', 'baz']); 622 | 623 | foo.bar('baz'); 624 | 625 | expect(foo.bar).toHaveBeenCalledWith('baz'); 626 | }); 627 | 628 | it('should do something else but not now', () => { 629 | }); 630 | 631 | it('should do something else but not now', () => { 632 | }); 633 | ``` 634 |
635 | ↥ back to top 636 |
637 | 638 | #### Note 639 | 640 | The handy `fit` function used in the example above allows you to execute only one test without having to comment out all the tests below. `fdescribe` does the same for test suites. This could help save a lot of time when developing. 641 | 642 | More information on the [Jasmine website](http://jasmine.github.io). 643 | 644 | 645 | 646 | ### Don't test multiple concerns in the same test 647 | 648 | If a method has several end results, each one should be tested separately. Whenever a bug occurs, it will help you locate the source of the problem. 649 | 650 | **:(** 651 | 652 | ```js 653 | it('should send the profile data to the server and update the profile view properly', () => { 654 | // expect(...)to(...); 655 | // expect(...)to(...); 656 | }); 657 | ``` 658 | 659 | **:)** 660 | 661 | ```js 662 | it('should send the profile data to the server', () => { 663 | // expect(...)to(...); 664 | }); 665 | 666 | it('should update the profile view properly', () => { 667 | // expect(...)to(...); 668 | }); 669 | ``` 670 | 671 | Beware that writing "AND" or "OR" when naming your test smells bad... 672 | 673 |
674 | ↥ back to top 675 |
676 | 677 | ### Cover the general case and the edge cases 678 | 679 | "Strange behaviour" usually happens at the edges... Remember that your tests can be the live documentation of your code. 680 | 681 | **:(** 682 | 683 | ```js 684 | it('should properly calculate a RPN expression', () => { 685 | const result = RPN('5 1 2 + 4 * - 10 /'); 686 | expect(result).toBe(-0.7); 687 | }); 688 | ``` 689 | 690 | **:)** 691 | 692 | ```js 693 | describe('The RPN expression evaluator', () => { 694 | it('should return null when the expression is an empty string', () => { 695 | const result = RPN(''); 696 | expect(result).toBeNull(); 697 | }); 698 | 699 | it('should return the same value when the expression holds a single value', () => { 700 | const result = RPN('42'); 701 | expect(result).toBe(42); 702 | }); 703 | 704 | it('should properly calculate an expression', () => { 705 | const result = RPN('5 1 2 + 4 * - 10 /'); 706 | expect(result).toBe(-0.7); 707 | }); 708 | 709 | it('should throw an error whenever an invalid expression is passed', () => { 710 | const compute = () => RPN('1 + - 1'); 711 | expect(compute).toThrow(); 712 | }); 713 | }); 714 | ``` 715 | 716 |
717 | ↥ back to top 718 |
719 | 720 | ### When applying TDD, always start by writing the simplest failing test 721 | 722 | **:(** 723 | 724 | ```js 725 | it('should suppress all chars that appear multiple times', () => { 726 | expect(keepUniqueChars('Hello Fostonic !!')).toBe('HeFstnic'); 727 | }); 728 | ``` 729 | 730 | **:)** 731 | 732 | ```js 733 | it('should return an empty string when passed an empty string', () => { 734 | expect(keepUniqueChars('')).toBe(''); 735 | }); 736 | ``` 737 | 738 | From there, start building the functionalities incrementally. 739 | 740 | 741 | 742 | ### When applying TDD, always make small steps in each test-first cycle 743 | 744 | Build your tests suite from the simple case to the more complex ones. Keep in mind the incremental design. Deliver software fast, incrementally, and in short iterations. 745 | 746 | **:(** 747 | 748 | ```js 749 | it('should return null when the expression is an empty string', () => { 750 | const result = RPN(''); 751 | expect(result).toBeNull(); 752 | }); 753 | 754 | it('should properly calculate a RPN expression', () => { 755 | const result = RPN('5 1 2 + 4 * - 10 /'); 756 | expect(result).toBe(-0.7); 757 | }); 758 | ``` 759 | 760 | **:)** 761 | 762 | ```js 763 | describe('The RPN expression evaluator', () => { 764 | it('should return null when the expression is an empty string', () => { 765 | const result = RPN(''); 766 | expect(result).toBeNull(); 767 | }); 768 | 769 | it('should return the same value when the expression holds a single value', () => { 770 | const result = RPN('42'); 771 | expect(result).toBe(42); 772 | }); 773 | 774 | describe('Additions-only expressions', () => { 775 | it('should properly calculate a simple addition', () => { 776 | const result = RPN('41 1 +'); 777 | expect(result).toBe(42); 778 | }); 779 | 780 | it('should properly calculate a complex addition', () => { 781 | const result = RPN('2 9 + 15 3 + + 7 6 + +'); 782 | expect(result).toBe(42); 783 | }); 784 | }); 785 | 786 | // ... 787 | 788 | describe('Complex expressions', () => { 789 | it('should properly calculate an expression containing all 4 operators', () => { 790 | const result = RPN('5 1 2 + 4 * - 10 /'); 791 | expect(result).toBe(-0.7); 792 | }); 793 | }); 794 | }); 795 | ``` 796 |
797 | ↥ back to top 798 |
799 | 800 | ### Test the behaviour, not the internal implementation 801 | 802 | **:(** 803 | 804 | ```js 805 | it('should add a user in memory', () => { 806 | userManager.addUser('Dr. Falker', 'Joshua'); 807 | 808 | expect(userManager._users[0].name).toBe('Dr. Falker'); 809 | expect(userManager._users[0].password).toBe('Joshua'); 810 | }); 811 | ``` 812 | 813 | A better approach is to test at the same level of the API: 814 | 815 | **:)** 816 | 817 | ```js 818 | it('should add a user in memory', () => { 819 | userManager.addUser('Dr. Falker', 'Joshua'); 820 | 821 | expect(userManager.loginUser('Dr. Falker', 'Joshua')).toBe(true); 822 | }); 823 | ``` 824 | 825 | Pro: 826 | 827 | + Changing the internal implementation of a class/object will not necessarily force you to refactor the tests 828 | 829 | Con: 830 | 831 | + If a test is failing, we might have to debug to know which part of the code needs to be fixed 832 | 833 | Here, a balance has to be found, unit-testing some key parts can be beneficial. 834 | 835 |
836 | ↥ back to top 837 |
838 | 839 | ### Don't mock everything 840 | 841 | **:(** 842 | 843 | ```js 844 | describe('when the user has already visited the page', () => { 845 | // storage.getItem('page-visited', '1') === '1' 846 | describe('when the survey is not disabled', () => { 847 | // storage.getItem('survey-disabled') === null 848 | it('should display the survey', () => { 849 | const storage = jasmine.createSpyObj('storage', ['setItem', 'getItem']); 850 | storage.getItem.and.returnValue('1'); // ouch. 851 | 852 | const surveyManager = new SurveyManager(storage); 853 | spyOn(surveyManager, 'display'); 854 | 855 | surveyManager.start(); 856 | 857 | expect(surveyManager.display).toHaveBeenCalled(); 858 | }); 859 | }); 860 | 861 | // ... 862 | }); 863 | ``` 864 | 865 | This test fails, because the survey is considered disabled. Let's fix this: 866 | 867 | **:)** 868 | 869 | ```js 870 | describe('when the user has already visited the page', () => { 871 | // storage.getItem('page-visited', '1') === '1' 872 | describe('when the survey is not disabled', () => { 873 | // storage.getItem('survey-disabled') === null 874 | it('should display the survey', () => { 875 | const storage = jasmine.createSpyObj('storage', ['setItem', 'getItem']); 876 | storage.getItem.and.callFake(key => { 877 | switch (key) { 878 | case 'page-visited': 879 | return '1'; 880 | 881 | case 'survey-disabled': 882 | return null; 883 | } 884 | 885 | return null; 886 | }); // ouch. 887 | 888 | const surveyManager = new SurveyManager(storage); 889 | spyOn(surveyManager, 'display'); 890 | 891 | surveyManager.start(); 892 | 893 | expect(surveyManager.display).toHaveBeenCalled(); 894 | }); 895 | }); 896 | 897 | // ... 898 | }); 899 | ``` 900 | 901 | This will work... but needs a lot of code. Let's try a simpler approach: 902 | 903 | **:(** 904 | 905 | ```js 906 | describe('when the user has already visited the page', () => { 907 | // storage.getItem('page-visited', '1') === '1' 908 | describe('when the survey is not disabled', () => { 909 | // storage.getItem('survey-disabled') === null 910 | it('should display the survey', () => { 911 | const storage = window.localStorage; // ouch. 912 | storage.setItem('page-visited', '1'); 913 | 914 | const surveyManager = new SurveyManager(); 915 | spyOn(surveyManager, 'display'); 916 | 917 | surveyManager.start(); 918 | 919 | expect(surveyManager.display).toHaveBeenCalled(); 920 | }); 921 | }); 922 | 923 | // ... 924 | }); 925 | ``` 926 | 927 | We created a permanent storage of data. What happens if we do not properly clean it? 928 | We might affect the other tests. Let's fix this: 929 | 930 | **:) :)** 931 | 932 | ```js 933 | describe('when the user has already visited the page', () => { 934 | // storage.getItem('page-visited', '1') === '1' 935 | describe('when the survey is not disabled', () => { 936 | // storage.getItem('survey-disabled') === null 937 | it('should display the survey', () => { 938 | const storage = new MemoryStorage(); // see https://github.com/tatsuyaoiw/webstorage 939 | storage.setItem('page-visited', '1'); 940 | 941 | const surveyManager = new SurveyManager(storage); 942 | spyOn(surveyManager, 'display'); 943 | 944 | surveyManager.start(); 945 | 946 | expect(surveyManager.display).toHaveBeenCalled(); 947 | }); 948 | }); 949 | }); 950 | ``` 951 | 952 | The `MemoryStorage` used here does not persist data. Nice and easy, with no side effects. 953 | 954 |
955 | ↥ back to top 956 |
957 | 958 | #### Takeaway 959 | 960 | The idea to keep in mind is that *dependencies can still be "real" objects*. Don't mock everything because you can. 961 | In particular, consider using the "real" version of the objects if: 962 | 963 | + it leads to a simple, nice and easy tests setup 964 | + it does not create a shared state between the tests, causing unexpected side effects 965 | + the code being tested does not make AJAX requests, API calls or browser page reloads 966 | + the speed of execution of the tests stays *within the limits you fixed* 967 | 968 | 969 | 970 | ### Create new tests for every defect 971 | 972 | Whenever a bug is found, create a test that replicates the problem **before touching any code**. From there, you can apply TDD as usual to fix it. 973 | 974 | 975 | 976 | ### Don't write unit tests for complex user interactions 977 | 978 | Examples of complex user interactions: 979 | 980 | + Filling a form, drag and dropping some items then submitting the form 981 | + Clicking a tab, clicking an image thumbnail then navigating through a gallery of images previously loaded from a database 982 | + (...) 983 | 984 | These interactions might involve many units of work and should be handled at a higher level by **functional tests**. They will take more time to execute. They could be flaky (false negatives) and they need debugging whenever a failure is reported. 985 | 986 | For functional testing, consider using a test automation framework ([Selenium](http://docs.seleniumhq.org/), ...) or QA manual testing. 987 | 988 |
989 | ↥ back to top 990 |
991 | 992 | ### Test simple user actions 993 | 994 | Example of simple user actions: 995 | 996 | + Clicking on a link that toggles the visibility of a DOM element 997 | + Submitting a form that triggers the form validation 998 | + (...) 999 | 1000 | These actions can be easily tested **by simulating DOM events**, for example: 1001 | 1002 | ```js 1003 | describe('clicking on the "Preview profile" link', () => { 1004 | it('should show the profile preview if it is hidden', () => { 1005 | const previewLink = document.createElement('a'); 1006 | const profileModule = createProfileModule({ previewLink, previewIsVisible: false }); 1007 | 1008 | spyOn(profileModule, 'showPreview'); 1009 | 1010 | click(previewLink); 1011 | 1012 | expect(profileModule.showPreview).toHaveBeenCalled(); 1013 | }); 1014 | 1015 | it('should hide the profile preview if it is displayed', () => { 1016 | const previewLink = document.createElement('a'); 1017 | const profileModule = createProfileModule({ previewLink, previewIsVisible: true }); 1018 | 1019 | spyOn(profileModule, 'hidePreview'); 1020 | 1021 | click(previewLink); 1022 | 1023 | expect(profileModule.hidePreview).toHaveBeenCalled(); 1024 | }); 1025 | }); 1026 | ``` 1027 | 1028 | Note how simple the test is because the UI (DOM) layer does not mix with the business logic layer: 1029 | 1030 | + a "click" event occurs 1031 | + a public method is called 1032 | 1033 | The next step could be to test the business logic implemented in "showPreview()" or "hidePreview()". 1034 | 1035 | ### Libraries 1036 | 1037 | + Jasmine: https://jasmine.github.io/ 1038 | + Jest: https://jestjs.io/ 1039 | + Mocha: https://mochajs.org/ 1040 | + Tape: https://github.com/substack/tape 1041 | 1042 |
1043 | ↥ back to top 1044 |
1045 | -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.3/01-Writing-your-first-unit-test/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/after/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/node,test,macos 2 | 3 | ### macOS ### 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | ### Node ### 32 | # Logs 33 | logs 34 | *.log 35 | npm-debug.log* 36 | yarn-debug.log* 37 | yarn-error.log* 38 | 39 | # Runtime data 40 | pids 41 | *.pid 42 | *.seed 43 | *.pid.lock 44 | 45 | # Directory for instrumented libs generated by jscoverage/JSCover 46 | lib-cov 47 | 48 | # Coverage directory used by tools like istanbul 49 | coverage 50 | 51 | # nyc test coverage 52 | .nyc_output 53 | 54 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 55 | .grunt 56 | 57 | # Bower dependency directory (https://bower.io/) 58 | bower_components 59 | 60 | # node-waf configuration 61 | .lock-wscript 62 | 63 | # Compiled binary addons (https://nodejs.org/api/addons.html) 64 | build/Release 65 | 66 | # Dependency directories 67 | node_modules/ 68 | jspm_packages/ 69 | 70 | # TypeScript v1 declaration files 71 | typings/ 72 | 73 | # Optional npm cache directory 74 | .npm 75 | 76 | # Optional eslint cache 77 | .eslintcache 78 | 79 | # Optional REPL history 80 | .node_repl_history 81 | 82 | # Output of 'npm pack' 83 | *.tgz 84 | 85 | # Yarn Integrity file 86 | .yarn-integrity 87 | 88 | # dotenv environment variables file 89 | .env 90 | 91 | # parcel-bundler cache (https://parceljs.org/) 92 | .cache 93 | 94 | # next.js build output 95 | .next 96 | 97 | # nuxt.js build output 98 | .nuxt 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # Serverless directories 104 | .serverless 105 | 106 | ### Test ### 107 | ### Ignore all files that could be used to test your code and 108 | ### you wouldn't want to push 109 | 110 | # Reference https://en.wikipedia.org/wiki/Metasyntactic_variable 111 | 112 | # Most common 113 | *foo 114 | *bar 115 | *fubar 116 | *foobar 117 | *baz 118 | 119 | # Less common 120 | *qux 121 | *quux 122 | *bongo 123 | *bazola 124 | *ztesch 125 | 126 | # UK, Australia 127 | *wibble 128 | *wobble 129 | *wubble 130 | *flob 131 | *blep 132 | *blah 133 | *boop 134 | *beep 135 | 136 | # Japanese 137 | *hoge 138 | *piyo 139 | *fuga 140 | *hogera 141 | *hogehoge 142 | 143 | # Portugal, Spain 144 | *fulano 145 | *sicrano 146 | *beltrano 147 | *mengano 148 | *perengano 149 | *zutano 150 | 151 | # France, Italy, the Netherlands 152 | *toto 153 | *titi 154 | *tata 155 | *tutu 156 | *pipppo 157 | *pluto 158 | *paperino 159 | *aap 160 | *noot 161 | *mies 162 | 163 | # Other names that would make sense 164 | *tests 165 | *testsdir 166 | *testsfile 167 | *testsfiles 168 | *test 169 | *testdir 170 | *testfile 171 | *testfiles 172 | *testing 173 | *testingdir 174 | *testingfile 175 | *testingfiles 176 | *temp 177 | *tempdir 178 | *tempfile 179 | *tempfiles 180 | *tmp 181 | *tmpdir 182 | *tmpfile 183 | *tmpfiles 184 | *lol 185 | .DS_Store 186 | 187 | # End of https://www.gitignore.io/api/node,test,macos -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/after/math.js: -------------------------------------------------------------------------------- 1 | function sum(a, b){ 2 | return a + b; 3 | } 4 | module.exports = { 5 | sum 6 | } -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/before/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/node,test,macos 2 | 3 | ### macOS ### 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | ### Node ### 32 | # Logs 33 | logs 34 | *.log 35 | npm-debug.log* 36 | yarn-debug.log* 37 | yarn-error.log* 38 | 39 | # Runtime data 40 | pids 41 | *.pid 42 | *.seed 43 | *.pid.lock 44 | 45 | # Directory for instrumented libs generated by jscoverage/JSCover 46 | lib-cov 47 | 48 | # Coverage directory used by tools like istanbul 49 | coverage 50 | 51 | # nyc test coverage 52 | .nyc_output 53 | 54 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 55 | .grunt 56 | 57 | # Bower dependency directory (https://bower.io/) 58 | bower_components 59 | 60 | # node-waf configuration 61 | .lock-wscript 62 | 63 | # Compiled binary addons (https://nodejs.org/api/addons.html) 64 | build/Release 65 | 66 | # Dependency directories 67 | node_modules/ 68 | jspm_packages/ 69 | 70 | # TypeScript v1 declaration files 71 | typings/ 72 | 73 | # Optional npm cache directory 74 | .npm 75 | 76 | # Optional eslint cache 77 | .eslintcache 78 | 79 | # Optional REPL history 80 | .node_repl_history 81 | 82 | # Output of 'npm pack' 83 | *.tgz 84 | 85 | # Yarn Integrity file 86 | .yarn-integrity 87 | 88 | # dotenv environment variables file 89 | .env 90 | 91 | # parcel-bundler cache (https://parceljs.org/) 92 | .cache 93 | 94 | # next.js build output 95 | .next 96 | 97 | # nuxt.js build output 98 | .nuxt 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # Serverless directories 104 | .serverless 105 | 106 | ### Test ### 107 | ### Ignore all files that could be used to test your code and 108 | ### you wouldn't want to push 109 | 110 | # Reference https://en.wikipedia.org/wiki/Metasyntactic_variable 111 | 112 | # Most common 113 | *foo 114 | *bar 115 | *fubar 116 | *foobar 117 | *baz 118 | 119 | # Less common 120 | *qux 121 | *quux 122 | *bongo 123 | *bazola 124 | *ztesch 125 | 126 | # UK, Australia 127 | *wibble 128 | *wobble 129 | *wubble 130 | *flob 131 | *blep 132 | *blah 133 | *boop 134 | *beep 135 | 136 | # Japanese 137 | *hoge 138 | *piyo 139 | *fuga 140 | *hogera 141 | *hogehoge 142 | 143 | # Portugal, Spain 144 | *fulano 145 | *sicrano 146 | *beltrano 147 | *mengano 148 | *perengano 149 | *zutano 150 | 151 | # France, Italy, the Netherlands 152 | *toto 153 | *titi 154 | *tata 155 | *tutu 156 | *pipppo 157 | *pluto 158 | *paperino 159 | *aap 160 | *noot 161 | *mies 162 | 163 | # Other names that would make sense 164 | *tests 165 | *testsdir 166 | *testsfile 167 | *testsfiles 168 | *test 169 | *testdir 170 | *testfile 171 | *testfiles 172 | *testing 173 | *testingdir 174 | *testingfile 175 | *testingfiles 176 | *temp 177 | *tempdir 178 | *tempfile 179 | *tempfiles 180 | *tmp 181 | *tmpdir 182 | *tmpfile 183 | *tmpfiles 184 | *lol 185 | .DS_Store 186 | 187 | # End of https://www.gitignore.io/api/node,test,macos -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/before/math.js: -------------------------------------------------------------------------------- 1 | function sum(a, b){ 2 | return a + b; 3 | } 4 | module.exports = { 5 | sum 6 | } -------------------------------------------------------------------------------- /Section-1/1.3/01-Writing-your-first-unit-test/before/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "directories": { 7 | "test": "tests" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.4/04-testing-numbers-and-strings/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.4/04-testing-numbers-and-strings/after/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/math.js: -------------------------------------------------------------------------------- 1 | function sum(a, b){ 2 | return a + b; 3 | } 4 | module.exports = { 5 | sum 6 | } -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/tests/math.test.js: -------------------------------------------------------------------------------- 1 | const { sum } = require('../math'); 2 | 3 | describe('Sum Feature', () => { 4 | test('should calculate the sum of two numbers', () => { 5 | const results = sum(2,2); 6 | expect(results).toBe(4); 7 | expect(results).toBeGreaterThan(3) 8 | expect(results).toBeGreaterThanOrEqual(3) 9 | expect(results).toBeLessThan(5) 10 | expect(results).toBeLessThanOrEqual(5); 11 | expect(results).toEqual(4) 12 | }); 13 | test('should calculate the sum of two floating point numbers', () => { 14 | const results = sum(0.1 , 0.3); 15 | expect(results).toBeCloseTo(0.4); 16 | }) 17 | }); 18 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const {greet} = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/after/util.js: -------------------------------------------------------------------------------- 1 | function greet(name){ 2 | return `Hello ${name}`; 3 | } 4 | module.exports ={ 5 | greet 6 | } -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.4/04-testing-numbers-and-strings/before/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/math.js: -------------------------------------------------------------------------------- 1 | function sum(a, b){ 2 | return a + b; 3 | } 4 | module.exports = { 5 | sum 6 | } -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/tests/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.4/04-testing-numbers-and-strings/before/tests/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/tests/math.test.js: -------------------------------------------------------------------------------- 1 | const { sum } = require('../math'); 2 | 3 | test('should calculate the sum of two numbers', () => { 4 | 5 | }); 6 | -------------------------------------------------------------------------------- /Section-1/1.4/04-testing-numbers-and-strings/before/util.js: -------------------------------------------------------------------------------- 1 | function greet(name){ 2 | return `Hello ${name}`; 3 | } 4 | module.exports ={ 5 | greet 6 | } -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.5/05-testing-thruthiness/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/after/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { greet, isEven, isOdd } = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }); 10 | }); 11 | 12 | describe('Even', () => { 13 | it('should return true if number is even', () => { 14 | const results = isEven(2); 15 | expect(results).toBeTruthy(); 16 | expect(results).not.toBeFalsy(); 17 | }); 18 | it('should return false if number is not even', () => { 19 | const results = isEven(3); 20 | expect(results).not.toBeTruthy(); 21 | expect(results).toBeFalsy(); 22 | }); 23 | }); 24 | describe('Odd', () => { 25 | it('should return true if number is odd', () => { 26 | const results = isOdd(3); 27 | expect(results).toBeTruthy(); 28 | expect(results).not.toBeFalsy(); 29 | }); 30 | it('should return false if number is not odd', () => { 31 | const results = isOdd(4); 32 | expect(results).not.toBeTruthy(); 33 | expect(results).toBeFalsy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/after/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | module.exports = { 11 | greet, 12 | isEven, 13 | isOdd 14 | }; 15 | -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/before/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/before/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { greet, isEven, isOdd } = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }); 10 | }); 11 | 12 | describe('Even', () => { 13 | it('should return true if number is even', () => { 14 | const results = isEven(2); 15 | expect(results).toBeTruthy(); 16 | expect(results).not.toBeFalsy(); 17 | }); 18 | it('should return false if number is not even', () => { 19 | const results = isEven(3); 20 | expect(results).not.toBeTruthy(); 21 | expect(results).toBeFalsy(); 22 | }); 23 | }); 24 | describe('Odd', () => { 25 | it('should return true if number is odd', () => { 26 | const results = isOdd(3); 27 | expect(results).toBeTruthy(); 28 | expect(results).not.toBeFalsy(); 29 | }); 30 | it('should return false if number is not odd', () => { 31 | const results = isOdd(4); 32 | expect(results).not.toBeTruthy(); 33 | expect(results).toBeFalsy(); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Section-1/1.5/05-testing-thruthiness/before/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | module.exports = { 11 | greet, 12 | isEven, 13 | isOdd 14 | }; 15 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/after/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.6/06-testing-arrays-and-objects/after/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/after/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { greet, isEven, isOdd, getCustomer, getPersons } = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }); 10 | }); 11 | 12 | describe('Even', () => { 13 | it('should return true if number is even', () => { 14 | const results = isEven(2); 15 | expect(results).toBeTruthy(); 16 | expect(results).not.toBeFalsy(); 17 | }); 18 | it('should return false if number is not even', () => { 19 | const results = isEven(3); 20 | expect(results).not.toBeTruthy(); 21 | expect(results).toBeFalsy(); 22 | }); 23 | }); 24 | describe('Odd', () => { 25 | it('should return true if number is odd', () => { 26 | const results = isOdd(3); 27 | expect(results).toBeTruthy(); 28 | expect(results).not.toBeFalsy(); 29 | }); 30 | it('should return false if number is not odd', () => { 31 | const results = isOdd(4); 32 | expect(results).not.toBeTruthy(); 33 | expect(results).toBeFalsy(); 34 | }); 35 | }); 36 | describe('Customer', () => { 37 | it('should find customer by id', () => { 38 | const results = getCustomer(1); 39 | expect(results).toBeDefined(); 40 | expect(results).not.toBeUndefined(); 41 | 42 | expect(results).toEqual({ id: 1, name: 'Jane' }); 43 | expect(results).toHaveProperty('id', 1); 44 | 45 | expect(results).toEqual(expect.objectContaining({ id: 1 })); 46 | }); 47 | }); 48 | describe('Persons', () => { 49 | it('should fetch all the persons', () => { 50 | const results = getPersons(); 51 | expect(results).toHaveLength(4); 52 | expect(results).toContain('Doe'); 53 | 54 | expect(results).toEqual(expect.arrayContaining(['Jane', 'Doe'])); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/after/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | function getCustomer(id) { 11 | return { id, name: 'Jane' }; 12 | } 13 | const persons = ['Jane', 'Doe', 'Sane', 'Mathew']; 14 | function getPersons() { 15 | return persons; 16 | } 17 | module.exports = { 18 | greet, 19 | isEven, 20 | isOdd, 21 | getCustomer, 22 | getPersons 23 | }; 24 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/before/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/before/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { greet, isEven, isOdd, getCustomer, getPersons } = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }); 10 | }); 11 | 12 | describe('Even', () => { 13 | it('should return true if number is even', () => { 14 | const results = isEven(2); 15 | expect(results).toBeTruthy(); 16 | expect(results).not.toBeFalsy(); 17 | }); 18 | it('should return false if number is not even', () => { 19 | const results = isEven(3); 20 | expect(results).not.toBeTruthy(); 21 | expect(results).toBeFalsy(); 22 | }); 23 | }); 24 | describe('Odd', () => { 25 | it('should return true if number is odd', () => { 26 | const results = isOdd(3); 27 | expect(results).toBeTruthy(); 28 | expect(results).not.toBeFalsy(); 29 | }); 30 | it('should return false if number is not odd', () => { 31 | const results = isOdd(4); 32 | expect(results).not.toBeTruthy(); 33 | expect(results).toBeFalsy(); 34 | }); 35 | }); 36 | describe('Customer', () => { 37 | it('should find customer by id', () => { 38 | const results = getCustomer(1); 39 | expect(results).toBeDefined(); 40 | expect(results).not.toBeUndefined(); 41 | 42 | expect(results).toEqual({ id: 1, name: 'Jane' }); 43 | expect(results).toHaveProperty('id', 1); 44 | 45 | expect(results).toEqual(expect.objectContaining({ id: 1 })); 46 | }); 47 | }); 48 | describe('Persons', () => { 49 | it('should fetch all the persons', () => { 50 | const results = getPersons(); 51 | expect(results).toHaveLength(4); 52 | expect(results).toContain('Doe'); 53 | 54 | expect(results).toEqual(expect.arrayContaining(['Jane', 'Doe'])); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /Section-1/1.6/06-testing-arrays-and-objects/before/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | function getCustomer(id) { 11 | return { id, name: 'Jane' }; 12 | } 13 | const persons = ['Jane', 'Doe', 'Sane', 'Mathew']; 14 | function getPersons() { 15 | return persons; 16 | } 17 | module.exports = { 18 | greet, 19 | isEven, 20 | isOdd, 21 | getCustomer, 22 | getPersons 23 | }; 24 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.7/07-testing-exceptions/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/after/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/after/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { 2 | greet, 3 | isEven, 4 | isOdd, 5 | getCustomer, 6 | getPersons, 7 | downloadCV 8 | } = require('../util'); 9 | 10 | describe('Greet Feature', () => { 11 | it('should get the greet message', () => { 12 | const results = greet('Jane'); 13 | expect(results).toBe('Hello Jane'); 14 | expect(results).toMatch('Jane'); 15 | expect(results).toMatch(/Jane/); 16 | }); 17 | }); 18 | 19 | describe('Even', () => { 20 | it('should return true if number is even', () => { 21 | const results = isEven(2); 22 | expect(results).toBeTruthy(); 23 | expect(results).not.toBeFalsy(); 24 | }); 25 | it('should return false if number is not even', () => { 26 | const results = isEven(3); 27 | expect(results).not.toBeTruthy(); 28 | expect(results).toBeFalsy(); 29 | }); 30 | }); 31 | describe('Odd', () => { 32 | it('should return true if number is odd', () => { 33 | const results = isOdd(3); 34 | expect(results).toBeTruthy(); 35 | expect(results).not.toBeFalsy(); 36 | }); 37 | it('should return false if number is not odd', () => { 38 | const results = isOdd(4); 39 | expect(results).not.toBeTruthy(); 40 | expect(results).toBeFalsy(); 41 | }); 42 | }); 43 | describe('Customer', () => { 44 | it('should find customer by id', () => { 45 | const results = getCustomer(1); 46 | expect(results).toBeDefined(); 47 | expect(results).not.toBeUndefined(); 48 | 49 | expect(results).toEqual({ id: 1, name: 'Jane' }); 50 | expect(results).toHaveProperty('id', 1); 51 | 52 | expect(results).toEqual(expect.objectContaining({ id: 1 })); 53 | }); 54 | }); 55 | describe('Persons', () => { 56 | it('should fetch all the persons', () => { 57 | const results = getPersons(); 58 | expect(results).toHaveLength(4); 59 | expect(results).toContain('Doe'); 60 | 61 | expect(results).toEqual(expect.arrayContaining(['Jane', 'Doe'])); 62 | }); 63 | }); 64 | 65 | describe('Download CV', () => { 66 | it('should throw error if user does not provide path', () => { 67 | expect(() => { 68 | downloadCV(); 69 | }).toThrow(); 70 | expect(() => { 71 | downloadCV(); 72 | }).toThrow('invalid URL'); 73 | expect(() => { 74 | downloadCV(null); 75 | }).toThrow(); 76 | }); 77 | it('should get the contents from the CV', () => { 78 | const results = downloadCV('http://localhost:3000/cv/1'); 79 | expect(results).toBe('Content'); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/after/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | function getCustomer(id) { 11 | return { id, name: 'Jane' }; 12 | } 13 | const persons = ['Jane', 'Doe', 'Sane', 'Mathew']; 14 | function getPersons() { 15 | return persons; 16 | } 17 | 18 | function downloadCV(path) { 19 | if (!path) { 20 | throw new Error('invalid URL'); 21 | } 22 | return 'Content'; 23 | } 24 | module.exports = { 25 | greet, 26 | isEven, 27 | isOdd, 28 | getCustomer, 29 | getPersons, 30 | downloadCV 31 | }; 32 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/before/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-1/1.7/07-testing-exceptions/before/.DS_Store -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/before/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/before/tests/util.test.js: -------------------------------------------------------------------------------- 1 | const { greet, isEven, isOdd, getCustomer, getPersons } = require('../util'); 2 | 3 | describe('Greet Feature', () => { 4 | it('should get the greet message', () => { 5 | const results = greet('Jane'); 6 | expect(results).toBe('Hello Jane'); 7 | expect(results).toMatch('Jane'); 8 | expect(results).toMatch(/Jane/); 9 | }); 10 | }); 11 | 12 | describe('Even', () => { 13 | it('should return true if number is even', () => { 14 | const results = isEven(2); 15 | expect(results).toBeTruthy(); 16 | expect(results).not.toBeFalsy(); 17 | }); 18 | it('should return false if number is not even', () => { 19 | const results = isEven(3); 20 | expect(results).not.toBeTruthy(); 21 | expect(results).toBeFalsy(); 22 | }); 23 | }); 24 | describe('Odd', () => { 25 | it('should return true if number is odd', () => { 26 | const results = isOdd(3); 27 | expect(results).toBeTruthy(); 28 | expect(results).not.toBeFalsy(); 29 | }); 30 | it('should return false if number is not odd', () => { 31 | const results = isOdd(4); 32 | expect(results).not.toBeTruthy(); 33 | expect(results).toBeFalsy(); 34 | }); 35 | }); 36 | describe('Customer', () => { 37 | it('should find customer by id', () => { 38 | const results = getCustomer(1); 39 | expect(results).toBeDefined(); 40 | expect(results).not.toBeUndefined(); 41 | 42 | expect(results).toEqual({ id: 1, name: 'Jane' }); 43 | expect(results).toHaveProperty('id', 1); 44 | 45 | expect(results).toEqual(expect.objectContaining({ id: 1 })); 46 | }); 47 | }); 48 | describe('Persons', () => { 49 | it('should fetch all the persons', () => { 50 | const results = getPersons(); 51 | expect(results).toHaveLength(4); 52 | expect(results).toContain('Doe'); 53 | 54 | expect(results).toEqual(expect.arrayContaining(['Jane', 'Doe'])); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /Section-1/1.7/07-testing-exceptions/before/util.js: -------------------------------------------------------------------------------- 1 | function greet(name) { 2 | return `Hello ${name}`; 3 | } 4 | function isEven(n) { 5 | return n % 2 == 0; 6 | } 7 | function isOdd(n) { 8 | return Math.abs(n % 2) == 1; 9 | } 10 | function getCustomer(id) { 11 | return { id, name: 'Jane' }; 12 | } 13 | const persons = ['Jane', 'Doe', 'Sane', 'Mathew']; 14 | function getPersons() { 15 | return persons; 16 | } 17 | 18 | function downloadCV(path) { 19 | if (!path) { 20 | throw new Error('invalid URL'); 21 | } 22 | return 'Content'; 23 | } 24 | module.exports = { 25 | greet, 26 | isEven, 27 | isOdd, 28 | getCustomer, 29 | getPersons, 30 | downloadCV 31 | }; 32 | -------------------------------------------------------------------------------- /Section-2/2.2/BankAccount.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-2/2.2/BankAccount.js -------------------------------------------------------------------------------- /Section-2/2.2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest --watchAll" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-2/2.2/tests/BankAcount.test.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/learning-zone/javascript-unit-testing/2bce97478b1231a70d5ef1a572bf43b7078dfd83/Section-2/2.2/tests/BankAcount.test.js -------------------------------------------------------------------------------- /Section-2/2.4/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // Project configuration. 3 | grunt.initConfig({ 4 | shell: { 5 | simple: { 6 | command: 'cucumber.js simple/features -r simple/steps' 7 | } 8 | } 9 | }); 10 | 11 | // These plugins provide necessary tasks. 12 | grunt.loadNpmTasks('grunt-shell'); 13 | }; 14 | -------------------------------------------------------------------------------- /Section-2/2.4/README.md: -------------------------------------------------------------------------------- 1 | # BDD in JavaScript: Getting Started with Cucumber and Gherkin 2 | 3 | This repository exists as a set of example implementations of Cucumber.js functionality. 4 | Article URL: https://www.sitepoint.com/bdd-in-javascript-cucumber-gherkin 5 | 6 | ## Examples 7 | 8 | This repository has the following set of examples: 9 | 10 | * simple - A very simple example that does nothing special 11 | * background - Identical to the 'simple' example in terms of Javascript, but using a Background for common initialisation 12 | * outline - Identical to the 'simple' example in terms of Javascript, but using a Scenario Outline to generate Scenarios 13 | * datatable - Adaptation of the 'simple' example to use a Data Table to add an arbitrary list of numbers 14 | * hooks - Demonstration of a Before hook for resetting data 15 | * events - Demonstration of event handling for the lifecycle of running tests 16 | * world - Demonstration of the World concept for data sharing 17 | 18 | ## Running examples 19 | 20 | The examples are all set up to run with either npm Scripts, Grunt or Gulp. They can all be run as either: 21 | 22 | * npm run-script 23 | * grunt shell: 24 | * gulp 25 | 26 | ## License 27 | 28 | For example, `npm run-script simple`, `grunt shell:background` or `gulp outline`. 29 | 30 | SitePoint's code archives and code examples are licensed under the MIT license. 31 | 32 | Copyright © 2017 SitePoint 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 35 | 36 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | -------------------------------------------------------------------------------- /Section-2/2.4/features/addition.feature: -------------------------------------------------------------------------------- 1 | Feature: Addition 2 | Scenario: 1 + 2 3 | Given I start with 1 4 | When I add 2 5 | Then I end up with 3 6 | -------------------------------------------------------------------------------- /Section-2/2.4/gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const shell = require('gulp-shell'); 3 | 4 | gulp.task( 5 | 'simple', 6 | shell.task(['cucumber.js simple/features -r simple/steps']) 7 | ); 8 | -------------------------------------------------------------------------------- /Section-2/2.4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bdd", 3 | "version": "1.0.0", 4 | "description": "Behaviour Driven Development in Javascript", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "cucumber.js features -r steps" 8 | }, 9 | "author": "Haider Malik", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chai": "^3.5.0", 13 | "cucumber": "^2.1.0", 14 | "grunt": "^1.0.1", 15 | "grunt-cli": "^1.2.0", 16 | "grunt-shell": "^2.1.0", 17 | "gulp": "^3.9.1", 18 | "gulp-shell": "^0.6.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Section-3/3.1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest --watchAll" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "jest": "^23.6.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-3/3.1/tests/assert-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | describe('Assert library', () => { 3 | it('assert() demo', () => { 4 | assert(100 > 70, 'Expected value is not greater than received value'); 5 | }); 6 | //If two objects, or their child objects, are not equal, an error is thrown and the program is terminated: 7 | it('deepEqual() demo', () => { 8 | let x = { a: { n: 0 } }; 9 | let y = { a: { n: 0 } }; 10 | let z = { a: { n: 0 } }; 11 | assert.deepEqual(x, y); //OK 12 | assert.deepEqual( 13 | x, 14 | z 15 | ); /*AssertionError: { a: { n: 0 } } deepEqual {a: { n: 1 } }*/ 16 | }); 17 | //If two values are not equal, an error is thrown and the program is terminated: 18 | it('equal() demo', () => { 19 | assert.equal(50, 50); //OK 20 | assert.equal(50, '50'); //OK 21 | assert.equal(50, 50); /*AssertionError: 50 == 70 */ 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.2/math.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sum(a, b) { 3 | return a + b; 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /Section-3/3.2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest --watchAll" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "chai": "^4.2.0", 14 | "jest": "^23.6.0" 15 | }, 16 | "dependencies": { 17 | "should": "^13.2.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Section-3/3.2/tests/assert-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | describe('Assert library', () => { 3 | it('assert() demo', () => { 4 | assert(100 > 70, 'Expected value is not greater than received value'); 5 | }); 6 | //If two objects, or their child objects, are not equal, an error is thrown and the program is terminated: 7 | it('deepEqual() demo', () => { 8 | let x = { a: { n: 0 } }; 9 | let y = { a: { n: 0 } }; 10 | let z = { a: { n: 0 } }; 11 | assert.deepEqual(x, y); //OK 12 | assert.deepEqual( 13 | x, 14 | z 15 | ); /*AssertionError: { a: { n: 0 } } deepEqual {a: { n: 1 } }*/ 16 | }); 17 | //If two values are not equal, an error is thrown and the program is terminated: 18 | it('equal() demo', () => { 19 | assert.equal(50, 50); //OK 20 | assert.equal(50, '50'); //OK 21 | assert.equal(50, 50); /*AssertionError: 50 == 70 */ 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.2/tests/chai.js-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const expect = require('chai').expect; 3 | const should = require('chai').should(); //actually call the function 4 | describe('chai assetion library', () => { 5 | it('assert with chai demo', () => { 6 | let foo = 'bar', 7 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 8 | assert.typeOf(foo, 'string'); // without optional message 9 | assert.typeOf(foo, 'string', 'foo is a string'); // with optional message 10 | assert.equal(foo, 'bar', 'foo equal `bar`'); 11 | assert.lengthOf(foo, 3, 'foo`s value has a length of 3'); 12 | assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea'); 13 | }); 14 | it('expect with chai', () => { 15 | const foo = 'bar', 16 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 17 | 18 | expect(foo).to.be.a('string'); 19 | expect(foo).to.equal('bar'); 20 | expect(foo).to.have.lengthOf(3); 21 | expect(beverages) 22 | .to.have.property('tea') 23 | .with.lengthOf(3); 24 | }); 25 | 26 | it('should with chai.js', () => { 27 | const foo = 'bar', 28 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 29 | 30 | foo.should.be.a('string'); 31 | foo.should.equal('bar'); 32 | foo.should.have.lengthOf(3); 33 | beverages.should.have.property('tea').with.lengthOf(3); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Section-3/3.2/tests/expect-demo.test.js: -------------------------------------------------------------------------------- 1 | describe('Expect Assertion library', () => { 2 | it('toBe Demo', () => { 3 | expect(2 + 2).toBe(4); 4 | }); 5 | it('toEqual demo', () => { 6 | const data = { one: 1 }; 7 | data['two'] = 2; 8 | expect(data).toEqual({ one: 1, two: 2 }); 9 | }); 10 | 11 | it('truthiness', () => { 12 | const z = 0; 13 | expect(z).not.toBeNull(); 14 | expect(z).toBeDefined(); 15 | expect(z).not.toBeUndefined(); 16 | expect(z).not.toBeTruthy(); 17 | expect(z).toBeFalsy(); 18 | }); 19 | 20 | it('toContain demo', () => { 21 | const shoppingList = [ 22 | 'diapers', 23 | 'kleenex', 24 | 'trash bags', 25 | 'paper towels', 26 | 'beer' 27 | ]; 28 | expect(shoppingList).toContain('beer'); 29 | }); 30 | 31 | it('toMatch Demo', () => { 32 | expect('Christoph').toMatch(/stop/); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /Section-3/3.2/tests/should.js-demo.test.js: -------------------------------------------------------------------------------- 1 | //docs https://github.com/tj/should.js/ 2 | const { sum } = require('../math'); 3 | const should = require('should'); 4 | describe('Should.js', () => { 5 | it('should return 4 when the input number are 1 and 3', function() { 6 | sum(1, 3).should.be.exactly(4); 7 | sum(1, 3).should.be.exactly(4).and.be.a.Number; 8 | }); 9 | it('startWith demo', () => { 10 | 'foobar'.should.startWith('foo'); 11 | 'foobar'.should.not.startWith('bar'); 12 | }); 13 | it('above and greaterThan demo', () => { 14 | const user = { age: 20 }; 15 | user.age.should.be.above(5); 16 | user.age.should.not.be.above(100); 17 | }); 18 | it('type demo', () => { 19 | const user = {}; 20 | user.should.be.type('object'); 21 | 'test'.should.be.type('string'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.3/math.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sum(a, b) { 3 | return a + b; 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /Section-3/3.3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest --watchAll" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "chai": "^4.2.0", 14 | "jest": "^23.6.0" 15 | }, 16 | "dependencies": { 17 | "should": "^13.2.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Section-3/3.3/tests/assert-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | describe('Assert library', () => { 3 | it('assert() demo', () => { 4 | assert(100 > 70, 'Expected value is not greater than received value'); 5 | }); 6 | //If two objects, or their child objects, are not equal, an error is thrown and the program is terminated: 7 | it('deepEqual() demo', () => { 8 | let x = { a: { n: 0 } }; 9 | let y = { a: { n: 0 } }; 10 | let z = { a: { n: 0 } }; 11 | assert.deepEqual(x, y); //OK 12 | assert.deepEqual( 13 | x, 14 | z 15 | ); /*AssertionError: { a: { n: 0 } } deepEqual {a: { n: 1 } }*/ 16 | }); 17 | //If two values are not equal, an error is thrown and the program is terminated: 18 | it('equal() demo', () => { 19 | assert.equal(50, 50); //OK 20 | assert.equal(50, '50'); //OK 21 | assert.equal(50, 50); /*AssertionError: 50 == 70 */ 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.3/tests/chai.js-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const expect = require('chai').expect; 3 | const should = require('chai').should(); //actually call the function 4 | describe('chai assetion library', () => { 5 | it('assert with chai demo', () => { 6 | let foo = 'bar', 7 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 8 | assert.typeOf(foo, 'string'); // without optional message 9 | assert.typeOf(foo, 'string', 'foo is a string'); // with optional message 10 | assert.equal(foo, 'bar', 'foo equal `bar`'); 11 | assert.lengthOf(foo, 3, 'foo`s value has a length of 3'); 12 | assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea'); 13 | }); 14 | it('expect with chai', () => { 15 | const foo = 'bar', 16 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 17 | 18 | expect(foo).to.be.a('string'); 19 | expect(foo).to.equal('bar'); 20 | expect(foo).to.have.lengthOf(3); 21 | expect(beverages) 22 | .to.have.property('tea') 23 | .with.lengthOf(3); 24 | }); 25 | 26 | it('should with chai.js', () => { 27 | const foo = 'bar', 28 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 29 | 30 | foo.should.be.a('string'); 31 | foo.should.equal('bar'); 32 | foo.should.have.lengthOf(3); 33 | beverages.should.have.property('tea').with.lengthOf(3); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Section-3/3.3/tests/expect-demo.test.js: -------------------------------------------------------------------------------- 1 | describe('Expect Assertion library', () => { 2 | it('toBe Demo', () => { 3 | expect(2 + 2).toBe(4); 4 | }); 5 | it('toEqual demo', () => { 6 | const data = { one: 1 }; 7 | data['two'] = 2; 8 | expect(data).toEqual({ one: 1, two: 2 }); 9 | }); 10 | 11 | it('truthiness', () => { 12 | const z = 0; 13 | expect(z).not.toBeNull(); 14 | expect(z).toBeDefined(); 15 | expect(z).not.toBeUndefined(); 16 | expect(z).not.toBeTruthy(); 17 | expect(z).toBeFalsy(); 18 | }); 19 | 20 | it('toContain demo', () => { 21 | const shoppingList = [ 22 | 'diapers', 23 | 'kleenex', 24 | 'trash bags', 25 | 'paper towels', 26 | 'beer' 27 | ]; 28 | expect(shoppingList).toContain('beer'); 29 | }); 30 | 31 | it('toMatch Demo', () => { 32 | expect('Christoph').toMatch(/stop/); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /Section-3/3.3/tests/should.js-demo.test.js: -------------------------------------------------------------------------------- 1 | //docs https://github.com/tj/should.js/ 2 | const { sum } = require('../math'); 3 | const should = require('should'); 4 | describe('Should.js', () => { 5 | it('should return 4 when the input number are 1 and 3', function() { 6 | sum(1, 3).should.be.exactly(4); 7 | sum(1, 3).should.be.exactly(4).and.be.a.Number; 8 | }); 9 | it('startWith demo', () => { 10 | 'foobar'.should.startWith('foo'); 11 | 'foobar'.should.not.startWith('bar'); 12 | }); 13 | it('above and greaterThan demo', () => { 14 | const user = { age: 20 }; 15 | user.age.should.be.above(5); 16 | user.age.should.not.be.above(100); 17 | }); 18 | it('type demo', () => { 19 | const user = {}; 20 | user.should.be.type('object'); 21 | 'test'.should.be.type('string'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.4/math.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | sum(a, b) { 3 | return a + b; 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /Section-3/3.4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "first-unit-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "test": "jest --watchAll" 8 | }, 9 | "directories": { 10 | "test": "tests" 11 | }, 12 | "devDependencies": { 13 | "chai": "^4.2.0", 14 | "jest": "^23.6.0" 15 | }, 16 | "dependencies": { 17 | "should": "^13.2.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Section-3/3.4/tests/assert-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | describe('Assert library', () => { 3 | it('assert() demo', () => { 4 | assert(100 > 70, 'Expected value is not greater than received value'); 5 | }); 6 | //If two objects, or their child objects, are not equal, an error is thrown and the program is terminated: 7 | it('deepEqual() demo', () => { 8 | let x = { a: { n: 0 } }; 9 | let y = { a: { n: 0 } }; 10 | let z = { a: { n: 0 } }; 11 | assert.deepEqual(x, y); //OK 12 | assert.deepEqual( 13 | x, 14 | z 15 | ); /*AssertionError: { a: { n: 0 } } deepEqual {a: { n: 1 } }*/ 16 | }); 17 | //If two values are not equal, an error is thrown and the program is terminated: 18 | it('equal() demo', () => { 19 | assert.equal(50, 50); //OK 20 | assert.equal(50, '50'); //OK 21 | assert.equal(50, 50); /*AssertionError: 50 == 70 */ 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-3/3.4/tests/chai.js-demo.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const expect = require('chai').expect; 3 | const should = require('chai').should(); //actually call the function 4 | describe('chai assetion library', () => { 5 | it('assert with chai demo', () => { 6 | let foo = 'bar', 7 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 8 | assert.typeOf(foo, 'string'); // without optional message 9 | assert.typeOf(foo, 'string', 'foo is a string'); // with optional message 10 | assert.equal(foo, 'bar', 'foo equal `bar`'); 11 | assert.lengthOf(foo, 3, 'foo`s value has a length of 3'); 12 | assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea'); 13 | }); 14 | it('expect with chai', () => { 15 | const foo = 'bar', 16 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 17 | 18 | expect(foo).to.be.a('string'); 19 | expect(foo).to.equal('bar'); 20 | expect(foo).to.have.lengthOf(3); 21 | expect(beverages) 22 | .to.have.property('tea') 23 | .with.lengthOf(3); 24 | }); 25 | 26 | it('should with chai.js', () => { 27 | const foo = 'bar', 28 | beverages = { tea: ['chai', 'matcha', 'oolong'] }; 29 | 30 | foo.should.be.a('string'); 31 | foo.should.equal('bar'); 32 | foo.should.have.lengthOf(3); 33 | beverages.should.have.property('tea').with.lengthOf(3); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /Section-3/3.4/tests/expect-demo.test.js: -------------------------------------------------------------------------------- 1 | describe('Expect Assertion library', () => { 2 | it('toBe Demo', () => { 3 | expect(2 + 2).toBe(4); 4 | }); 5 | it('toEqual demo', () => { 6 | const data = { one: 1 }; 7 | data['two'] = 2; 8 | expect(data).toEqual({ one: 1, two: 2 }); 9 | }); 10 | 11 | it('truthiness', () => { 12 | const z = 0; 13 | expect(z).not.toBeNull(); 14 | expect(z).toBeDefined(); 15 | expect(z).not.toBeUndefined(); 16 | expect(z).not.toBeTruthy(); 17 | expect(z).toBeFalsy(); 18 | }); 19 | 20 | it('toContain demo', () => { 21 | const shoppingList = [ 22 | 'diapers', 23 | 'kleenex', 24 | 'trash bags', 25 | 'paper towels', 26 | 'beer' 27 | ]; 28 | expect(shoppingList).toContain('beer'); 29 | }); 30 | 31 | it('toMatch Demo', () => { 32 | expect('Christoph').toMatch(/stop/); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /Section-3/3.4/tests/should.js-demo.test.js: -------------------------------------------------------------------------------- 1 | //docs https://github.com/tj/should.js/ 2 | const { sum } = require('../math'); 3 | const should = require('should'); 4 | describe('Should.js', () => { 5 | it('should return 4 when the input number are 1 and 3', function() { 6 | sum(1, 3).should.be.exactly(4); 7 | sum(1, 3).should.be.exactly(4).and.be.a.Number; 8 | }); 9 | it('startWith demo', () => { 10 | 'foobar'.should.startWith('foo'); 11 | 'foobar'.should.not.startWith('bar'); 12 | }); 13 | it('above and greaterThan demo', () => { 14 | const user = { age: 20 }; 15 | user.age.should.be.above(5); 16 | user.age.should.not.be.above(100); 17 | }); 18 | it('type demo', () => { 19 | const user = {}; 20 | user.should.be.type('object'); 21 | 'test'.should.be.type('string'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /Section-4/4.1/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jasmine-demo", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 10 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 11 | "dev": true 12 | }, 13 | "brace-expansion": { 14 | "version": "1.1.11", 15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 16 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 17 | "dev": true, 18 | "requires": { 19 | "balanced-match": "^1.0.0", 20 | "concat-map": "0.0.1" 21 | } 22 | }, 23 | "concat-map": { 24 | "version": "0.0.1", 25 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 26 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 27 | "dev": true 28 | }, 29 | "fs.realpath": { 30 | "version": "1.0.0", 31 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 32 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 33 | "dev": true 34 | }, 35 | "glob": { 36 | "version": "7.1.3", 37 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 38 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 39 | "dev": true, 40 | "requires": { 41 | "fs.realpath": "^1.0.0", 42 | "inflight": "^1.0.4", 43 | "inherits": "2", 44 | "minimatch": "^3.0.4", 45 | "once": "^1.3.0", 46 | "path-is-absolute": "^1.0.0" 47 | } 48 | }, 49 | "inflight": { 50 | "version": "1.0.6", 51 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 52 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 53 | "dev": true, 54 | "requires": { 55 | "once": "^1.3.0", 56 | "wrappy": "1" 57 | } 58 | }, 59 | "inherits": { 60 | "version": "2.0.3", 61 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 62 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 63 | "dev": true 64 | }, 65 | "jasmine": { 66 | "version": "3.3.1", 67 | "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.3.1.tgz", 68 | "integrity": "sha512-/vU3/H7U56XsxIXHwgEuWpCgQ0bRi2iiZeUpx7Nqo8n1TpoDHfZhkPIc7CO8I4pnMzYsi3XaSZEiy8cnTfujng==", 69 | "dev": true, 70 | "requires": { 71 | "glob": "^7.0.6", 72 | "jasmine-core": "~3.3.0" 73 | } 74 | }, 75 | "jasmine-core": { 76 | "version": "3.3.0", 77 | "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.3.0.tgz", 78 | "integrity": "sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA==", 79 | "dev": true 80 | }, 81 | "minimatch": { 82 | "version": "3.0.4", 83 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 84 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 85 | "dev": true, 86 | "requires": { 87 | "brace-expansion": "^1.1.7" 88 | } 89 | }, 90 | "once": { 91 | "version": "1.4.0", 92 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 93 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 94 | "dev": true, 95 | "requires": { 96 | "wrappy": "1" 97 | } 98 | }, 99 | "path-is-absolute": { 100 | "version": "1.0.1", 101 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 102 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 103 | "dev": true 104 | }, 105 | "wrappy": { 106 | "version": "1.0.2", 107 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 108 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 109 | "dev": true 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Section-4/4.1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jasmine-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jasmine" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "jasmine": "^3.3.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-4/4.1/spec/math.spec.js: -------------------------------------------------------------------------------- 1 | describe('A suite', function() { 2 | it('contains spec with an expectation', function() { 3 | expect(true).toBe(true); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /Section-4/4.1/spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ], 9 | "stopSpecOnExpectationFailure": false, 10 | "random": true 11 | } 12 | -------------------------------------------------------------------------------- /Section-4/4.2/math.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | async add(a, b) { 3 | return Promise.resolve(a + b); 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /Section-4/4.2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mocha-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/mocha/bin/mocha" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "chai": "^4.2.0", 14 | "mocha": "^6.0.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Section-4/4.2/test/db.js: -------------------------------------------------------------------------------- 1 | // const expect = require('chai').expect; 2 | // const Sequelize = require('sequelize'); 3 | 4 | // describe('users', () => { 5 | // let database; 6 | // let User; 7 | 8 | // // runs before all tests in this block 9 | // before(async () => { 10 | // database = new Sequelize('postgresql://localhost/app_test', { 11 | // logging: false 12 | // }); 13 | // User = database.define('user', { 14 | // username: Sequelize.STRING, 15 | // birthday: Sequelize.DATE 16 | // }); 17 | // }); 18 | 19 | // // runs before each test in this block 20 | // beforeEach(async () => { 21 | // await User.sync(); 22 | // await User.create({ 23 | // username: 'zaiste', 24 | // birthday: new Date(1988, 1, 21) 25 | // }); 26 | // }); 27 | 28 | // // runs after each test in this block 29 | // afterEach(async () => { 30 | // await User.drop(); 31 | // }); 32 | 33 | // describe('#find()', () => { 34 | // it('should find a user', async () => { 35 | // const user = await User.findOne({ where: { username: 'zaiste' } }); 36 | // expect(user).to.be.a('object'); 37 | // expect(user).to.have.property('username'); 38 | // expect(user).to.have.property('birthday'); 39 | // expect(user.username).to.equal('zaiste'); 40 | // }); 41 | // }); 42 | // }); 43 | -------------------------------------------------------------------------------- /Section-4/4.2/test/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('chai').assert; 2 | const expect = require('chai').expect; 3 | const should = require('chai').should(); 4 | const { add } = require('../math'); 5 | describe('Mocha demo', () => { 6 | it('assert demo', () => { 7 | const numbers = [1, 2, 3, 4, 5]; 8 | assert.isArray(numbers, 'is array of numbers'); 9 | assert.include(numbers, 1, 'array contains 2'); 10 | assert.lengthOf(numbers, 5, 'array contains 5 numbers'); 11 | }); 12 | it('expect style', () => { 13 | const numbers = [1, 2, 3, 4, 5]; 14 | expect(numbers) 15 | .to.be.an('array') 16 | .that.includes(2); 17 | expect(numbers).to.have.lengthOf(5); 18 | }); 19 | it('should style', () => { 20 | const numbers = [1, 2, 3, 4, 5]; 21 | numbers.should.be.an('array').that.includes(2); 22 | numbers.should.have.lengthOf(5); 23 | }); 24 | }); 25 | describe('#add()', () => { 26 | it('2 + 2 is 4', async () => { 27 | const p = await add(2, 2); 28 | expect(p).to.equal(4); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /Section-4/4.3/data.txt: -------------------------------------------------------------------------------- 1 | Hellow orld -------------------------------------------------------------------------------- /Section-4/4.3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ava-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node_modules/.bin/ava tests/**/*.test.js --verbose" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "ava": "^1.3.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-4/4.3/tests/math.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | const fs = require('fs'); 3 | 4 | //Running tests serially 5 | test('foo', t => { 6 | t.pass(); 7 | }); 8 | 9 | test('bar', async t => { 10 | const bar = Promise.resolve('bar'); 11 | t.is(await bar, 'bar'); 12 | }); 13 | 14 | const getValue = () => { 15 | return new Promise(resolve => { 16 | return resolve(true); 17 | }); 18 | }; 19 | test('promises the truth', async t => { 20 | const value = await getValue(); 21 | t.true(value); 22 | }); 23 | 24 | test.cb('data.txt can be read', t => { 25 | // `t.end` automatically checks for error as first argument 26 | fs.readFile('data.txt', t.end); 27 | }); 28 | test.failing('demonstrate some bug', t => { 29 | t.fail(); // Test will count as passed 30 | }); 31 | -------------------------------------------------------------------------------- /Section-4/4.4/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tape-demo", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "balanced-match": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 10 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 11 | "dev": true 12 | }, 13 | "brace-expansion": { 14 | "version": "1.1.11", 15 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 16 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 17 | "dev": true, 18 | "requires": { 19 | "balanced-match": "^1.0.0", 20 | "concat-map": "0.0.1" 21 | } 22 | }, 23 | "concat-map": { 24 | "version": "0.0.1", 25 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 26 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 27 | "dev": true 28 | }, 29 | "deep-equal": { 30 | "version": "1.0.1", 31 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", 32 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", 33 | "dev": true 34 | }, 35 | "define-properties": { 36 | "version": "1.1.3", 37 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 38 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 39 | "dev": true, 40 | "requires": { 41 | "object-keys": "^1.0.12" 42 | } 43 | }, 44 | "defined": { 45 | "version": "1.0.0", 46 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 47 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 48 | "dev": true 49 | }, 50 | "es-abstract": { 51 | "version": "1.13.0", 52 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", 53 | "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", 54 | "dev": true, 55 | "requires": { 56 | "es-to-primitive": "^1.2.0", 57 | "function-bind": "^1.1.1", 58 | "has": "^1.0.3", 59 | "is-callable": "^1.1.4", 60 | "is-regex": "^1.0.4", 61 | "object-keys": "^1.0.12" 62 | } 63 | }, 64 | "es-to-primitive": { 65 | "version": "1.2.0", 66 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 67 | "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 68 | "dev": true, 69 | "requires": { 70 | "is-callable": "^1.1.4", 71 | "is-date-object": "^1.0.1", 72 | "is-symbol": "^1.0.2" 73 | } 74 | }, 75 | "for-each": { 76 | "version": "0.3.3", 77 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 78 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 79 | "dev": true, 80 | "requires": { 81 | "is-callable": "^1.1.3" 82 | } 83 | }, 84 | "fs.realpath": { 85 | "version": "1.0.0", 86 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 87 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 88 | "dev": true 89 | }, 90 | "function-bind": { 91 | "version": "1.1.1", 92 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 93 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 94 | "dev": true 95 | }, 96 | "glob": { 97 | "version": "7.1.3", 98 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 99 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 100 | "dev": true, 101 | "requires": { 102 | "fs.realpath": "^1.0.0", 103 | "inflight": "^1.0.4", 104 | "inherits": "2", 105 | "minimatch": "^3.0.4", 106 | "once": "^1.3.0", 107 | "path-is-absolute": "^1.0.0" 108 | } 109 | }, 110 | "has": { 111 | "version": "1.0.3", 112 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 113 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 114 | "dev": true, 115 | "requires": { 116 | "function-bind": "^1.1.1" 117 | } 118 | }, 119 | "has-symbols": { 120 | "version": "1.0.0", 121 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 122 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 123 | "dev": true 124 | }, 125 | "inflight": { 126 | "version": "1.0.6", 127 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 128 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 129 | "dev": true, 130 | "requires": { 131 | "once": "^1.3.0", 132 | "wrappy": "1" 133 | } 134 | }, 135 | "inherits": { 136 | "version": "2.0.3", 137 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 138 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 139 | "dev": true 140 | }, 141 | "is-callable": { 142 | "version": "1.1.4", 143 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 144 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 145 | "dev": true 146 | }, 147 | "is-date-object": { 148 | "version": "1.0.1", 149 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 150 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 151 | "dev": true 152 | }, 153 | "is-regex": { 154 | "version": "1.0.4", 155 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 156 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 157 | "dev": true, 158 | "requires": { 159 | "has": "^1.0.1" 160 | } 161 | }, 162 | "is-symbol": { 163 | "version": "1.0.2", 164 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 165 | "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 166 | "dev": true, 167 | "requires": { 168 | "has-symbols": "^1.0.0" 169 | } 170 | }, 171 | "minimatch": { 172 | "version": "3.0.4", 173 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 174 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 175 | "dev": true, 176 | "requires": { 177 | "brace-expansion": "^1.1.7" 178 | } 179 | }, 180 | "minimist": { 181 | "version": "1.2.0", 182 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 183 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 184 | "dev": true 185 | }, 186 | "object-inspect": { 187 | "version": "1.6.0", 188 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", 189 | "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", 190 | "dev": true 191 | }, 192 | "object-keys": { 193 | "version": "1.1.0", 194 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", 195 | "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", 196 | "dev": true 197 | }, 198 | "once": { 199 | "version": "1.4.0", 200 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 201 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 202 | "dev": true, 203 | "requires": { 204 | "wrappy": "1" 205 | } 206 | }, 207 | "path-is-absolute": { 208 | "version": "1.0.1", 209 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 210 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 211 | "dev": true 212 | }, 213 | "path-parse": { 214 | "version": "1.0.6", 215 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 216 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 217 | "dev": true 218 | }, 219 | "resolve": { 220 | "version": "1.10.0", 221 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 222 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 223 | "dev": true, 224 | "requires": { 225 | "path-parse": "^1.0.6" 226 | } 227 | }, 228 | "resumer": { 229 | "version": "0.0.0", 230 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 231 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 232 | "dev": true, 233 | "requires": { 234 | "through": "~2.3.4" 235 | } 236 | }, 237 | "string.prototype.trim": { 238 | "version": "1.1.2", 239 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", 240 | "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", 241 | "dev": true, 242 | "requires": { 243 | "define-properties": "^1.1.2", 244 | "es-abstract": "^1.5.0", 245 | "function-bind": "^1.0.2" 246 | } 247 | }, 248 | "tape": { 249 | "version": "4.10.1", 250 | "resolved": "https://registry.npmjs.org/tape/-/tape-4.10.1.tgz", 251 | "integrity": "sha512-G0DywYV1jQeY3axeYnXUOt6ktnxS9OPJh97FGR3nrua8lhWi1zPflLxcAHavZ7Jf3qUfY7cxcVIVFa4mY2IY1w==", 252 | "dev": true, 253 | "requires": { 254 | "deep-equal": "~1.0.1", 255 | "defined": "~1.0.0", 256 | "for-each": "~0.3.3", 257 | "function-bind": "~1.1.1", 258 | "glob": "~7.1.3", 259 | "has": "~1.0.3", 260 | "inherits": "~2.0.3", 261 | "minimist": "~1.2.0", 262 | "object-inspect": "~1.6.0", 263 | "resolve": "~1.10.0", 264 | "resumer": "~0.0.0", 265 | "string.prototype.trim": "~1.1.2", 266 | "through": "~2.3.8" 267 | } 268 | }, 269 | "through": { 270 | "version": "2.3.8", 271 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 272 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 273 | "dev": true 274 | }, 275 | "wrappy": { 276 | "version": "1.0.2", 277 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 278 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 279 | "dev": true 280 | } 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /Section-4/4.4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tape-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node_modules/.bin/tape tests/**/*.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "tape": "^4.10.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Section-4/4.4/tests/test.js: -------------------------------------------------------------------------------- 1 | const test = require('tape'); 2 | 3 | test('A passing test', assert => { 4 | assert.pass('This test will pass.'); 5 | assert.end(); 6 | }); 7 | test('Assertions with tape.', assert => { 8 | const expected = 'something to test'; 9 | const actual = 'something to test'; 10 | 11 | assert.equal( 12 | actual, 13 | expected, 14 | 'Given two mismatched values, .equal() should produce a nice bug report' 15 | ); 16 | 17 | assert.end(); 18 | }); 19 | test('My first test', function(assert) { 20 | assert.equal(1, 1, 'Numbers 1 and 2 are the same'); 21 | assert.end(); 22 | }); 23 | -------------------------------------------------------------------------------- /Section-4/4.5/intern.json: -------------------------------------------------------------------------------- 1 | { 2 | "suites": "tests/unit/**/*.js" 3 | } 4 | -------------------------------------------------------------------------------- /Section-4/4.5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "intern-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "intern": "^4.4.2" 8 | }, 9 | "devDependencies": {}, 10 | "scripts": { 11 | "test": "./node_modules/.bin/intern" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC" 16 | } 17 | -------------------------------------------------------------------------------- /Section-4/4.5/tests/unit/test.js: -------------------------------------------------------------------------------- 1 | const { suite, test } = intern.getInterface('tdd'); 2 | const { assert } = intern.getPlugin('chai'); 3 | 4 | suite('app', () => { 5 | test('print', () => { 6 | const result = 'Smith'; 7 | assert.equal(result, 'Smith'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /Section-5/config-overrides.js: -------------------------------------------------------------------------------- 1 | const { injectBabelPlugin } = require("react-app-rewired"); 2 | const rewireMobX = require("react-app-rewire-mobx"); 3 | 4 | module.exports = function override(config, env) { 5 | config = injectBabelPlugin("babel-plugin-styled-components", config); 6 | config = rewireMobX(config, env); 7 | 8 | return config; 9 | }; 10 | -------------------------------------------------------------------------------- /Section-5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jesttestingasync", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "axios": "^0.18.0", 7 | "babel-plugin-styled-components": "^1.5.1", 8 | "concurrently": "^3.5.1", 9 | "react": "^16.2.0", 10 | "react-app-rewire-mobx": "^1.0.7", 11 | "react-app-rewired": "^1.5.0", 12 | "react-dom": "^16.2.0" 13 | }, 14 | "devDependencies": { 15 | "react-scripts": "1.1.1", 16 | "enzyme": "^3.3.0", 17 | "enzyme-adapter-react-16": "^1.1.1", 18 | "enzyme-to-json": "^3.3.3", 19 | "sinon": "^4.4.9" 20 | }, 21 | "scripts": { 22 | "start": "react-app-rewired start", 23 | "build": "react-app-rewired build", 24 | "test": "react-app-rewired test --env=jsdom", 25 | "eject": "react-app-rewired eject", 26 | "watch": "concurrently --prefix \"[{name}]\" --names \"REACT,SASS\" -c \"bgBlue.bold,bgMagenta.bold\" \"yarn run start\" \"yarn run watch-styles\"", 27 | "watch-styles": "sass --watch src/css/styles.scss:src/css/styles.css" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Section-5/src/__mocks__/axios.js: -------------------------------------------------------------------------------- 1 | export default { 2 | get: jest.fn(() => Promise.resolve({ data: {} })) 3 | }; 4 | -------------------------------------------------------------------------------- /Section-5/src/services/__tests__/posts.js: -------------------------------------------------------------------------------- 1 | import mockAxios from 'axios'; 2 | import getPosts from '../posts'; 3 | 4 | it('calls axios and returns posts', async () => { 5 | // setup 6 | mockAxios.get.mockImplementationOnce(() => 7 | Promise.resolve({ 8 | data: { 9 | results: [ 10 | { 11 | userId: 1, 12 | id: 1, 13 | title: 14 | 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 15 | body: 16 | 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto' 17 | } 18 | ] 19 | } 20 | }) 21 | ); 22 | 23 | // work 24 | const posts = await getPosts(); 25 | 26 | // assertions / expects 27 | expect(posts).toEqual([ 28 | { 29 | userId: 1, 30 | id: 1, 31 | title: 32 | 'sunt aut facere repellat provident occaecati excepturi optio reprehenderit', 33 | body: 34 | 'quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto' 35 | } 36 | ]); 37 | expect(mockAxios.get).toHaveBeenCalledTimes(1); 38 | expect(mockAxios.get).toHaveBeenCalledWith( 39 | 'https://jsonplaceholder.typicode.com/posts' 40 | ); 41 | }); 42 | -------------------------------------------------------------------------------- /Section-5/src/services/__tests__/users.js: -------------------------------------------------------------------------------- 1 | import mockAxios from 'axios'; 2 | import getUsers from '../users'; 3 | 4 | it('calls axios and returns users', async () => { 5 | // setup 6 | mockAxios.get.mockImplementationOnce(() => 7 | Promise.resolve({ 8 | data: { 9 | results: [ 10 | { 11 | id: 1, 12 | name: 'Leanne Graham', 13 | username: 'Bret', 14 | email: 'Sincere@april.biz', 15 | address: { 16 | street: 'Kulas Light', 17 | suite: 'Apt. 556', 18 | city: 'Gwenborough', 19 | zipcode: '92998-3874', 20 | geo: { 21 | lat: '-37.3159', 22 | lng: '81.1496' 23 | } 24 | }, 25 | phone: '1-770-736-8031 x56442', 26 | website: 'hildegard.org', 27 | company: { 28 | name: 'Romaguera-Crona', 29 | catchPhrase: 'Multi-layered client-server neural-net', 30 | bs: 'harness real-time e-markets' 31 | } 32 | } 33 | ] 34 | } 35 | }) 36 | ); 37 | 38 | // work 39 | const users = await getUsers(); 40 | 41 | // assertions / expects 42 | expect(users).toEqual([ 43 | { 44 | id: 1, 45 | name: 'Leanne Graham', 46 | username: 'Bret', 47 | email: 'Sincere@april.biz', 48 | address: { 49 | street: 'Kulas Light', 50 | suite: 'Apt. 556', 51 | city: 'Gwenborough', 52 | zipcode: '92998-3874', 53 | geo: { 54 | lat: '-37.3159', 55 | lng: '81.1496' 56 | } 57 | }, 58 | phone: '1-770-736-8031 x56442', 59 | website: 'hildegard.org', 60 | company: { 61 | name: 'Romaguera-Crona', 62 | catchPhrase: 'Multi-layered client-server neural-net', 63 | bs: 'harness real-time e-markets' 64 | } 65 | } 66 | ]); 67 | expect(mockAxios.get).toHaveBeenCalledTimes(1); 68 | expect(mockAxios.get).toHaveBeenCalledWith( 69 | 'https://jsonplaceholder.typicode.com/users' 70 | ); 71 | }); 72 | -------------------------------------------------------------------------------- /Section-5/src/services/posts.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default async () => { 4 | const response = await axios.get( 5 | 'https://jsonplaceholder.typicode.com/posts' 6 | ); 7 | 8 | return response.data.results; 9 | }; 10 | -------------------------------------------------------------------------------- /Section-5/src/services/users.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default async () => { 4 | const response = await axios.get( 5 | 'https://jsonplaceholder.typicode.com/users' 6 | ); 7 | 8 | return response.data.results; 9 | }; 10 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/01-basic-spec/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/01-basic-spec/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "01", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "mocha": "5.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/01-basic-spec/test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | describe('Basic Mocha String Test', function () { 3 | it('should return number of charachters in a string', function () { 4 | assert.equal("Hello".length, 5); 5 | }); 6 | it('should return first charachter of the string', function () { 7 | assert.equal("Hello".charAt(0), 'H'); 8 | //throw {myError:'throwing error to fail test'} 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/02-testing-function/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/02-testing-function/controllers/login.controller.js: -------------------------------------------------------------------------------- 1 | function LoginController() { 2 | 3 | function isValidUserId(userList, user) { 4 | return userList.indexOf(user) >= 0; 5 | } 6 | 7 | return { 8 | isValidUserId 9 | } 10 | 11 | } 12 | 13 | module.exports = LoginController(); 14 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/02-testing-function/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "02", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha './test/**/*.spec.js'" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "mocha": "5.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/02-testing-function/test/controllers/login.controller.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var loginController = require('../../controllers/login.controller'); 3 | 4 | describe('LoginController', function () { 5 | 6 | describe('isValidUserId', function(){ 7 | 8 | it('should return true if valid user id', function(){ 9 | var isValid = loginController.isValidUserId(['abc123','xyz321'], 'abc123') 10 | assert.equal(isValid, true); 11 | }); 12 | 13 | it('should return false if invalid user id', function(){ 14 | var isValid = loginController.isValidUserId(['abc123','xyz321'],'abc1234') 15 | assert.equal(isValid, false); 16 | }); 17 | 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/03-async-callback/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/03-async-callback/controllers/login.controller.js: -------------------------------------------------------------------------------- 1 | function LoginController() { 2 | 3 | function isValidUserId(userList, user) { 4 | return userList.indexOf(user) >= 0; 5 | } 6 | 7 | function isValidUserIdAsync(userList, user, callback) { 8 | setTimeout(function(){ 9 | callback(userList.indexOf(user) >= 0) 10 | }, 1); 11 | } 12 | 13 | return { 14 | isValidUserId, 15 | isValidUserIdAsync 16 | } 17 | 18 | } 19 | 20 | module.exports = LoginController(); 21 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/03-async-callback/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "03", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha './test/**/*.spec.js'" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "mocha": "5.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/03-async-callback/test/controllers/login.controller.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var loginController = require('../../controllers/login.controller'); 3 | 4 | describe('LoginController', function () { 5 | 6 | describe('isValidUserId', function(){ 7 | 8 | it('should return true if valid user id', function(){ 9 | var isValid = loginController.isValidUserId(['abc123','xyz321'], 'abc123') 10 | assert.equal(isValid, true); 11 | }); 12 | 13 | it('should return false if invalid user id', function(){ 14 | var isValid = loginController.isValidUserId(['abc123','xyz321'],'abc1234') 15 | assert.equal(isValid, false); 16 | }); 17 | 18 | }); 19 | 20 | describe('isValidUserIdAsync', function(){ 21 | 22 | it('should return true if valid user id', function(done){ 23 | loginController.isValidUserIdAsync(['abc123','xyz321'], 'abc123', 24 | function(isValid){ 25 | assert.equal(isValid, true); 26 | done(); 27 | }); 28 | }); 29 | 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/04-hooks/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/04-hooks/controllers/login.controller.js: -------------------------------------------------------------------------------- 1 | function LoginController() { 2 | 3 | var userList; 4 | function loadUserList(users){ 5 | userList = users; 6 | } 7 | 8 | function isValidUserId(user) { 9 | return userList.indexOf(user) >= 0; 10 | } 11 | 12 | function isValidUserIdAsync(user, callback) { 13 | setTimeout(function(){ 14 | callback(userList.indexOf(user) >= 0) 15 | }, 1); 16 | } 17 | 18 | return { 19 | isValidUserId, 20 | isValidUserIdAsync, 21 | loadUserList 22 | } 23 | 24 | } 25 | 26 | module.exports = LoginController(); 27 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/04-hooks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "04", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha './test/**/*.spec.js'" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "mocha": "5.0.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/04-hooks/test/controllers/login.controller.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var loginController = require('../../controllers/login.controller'); 3 | 4 | beforeEach('Setting up the userList', function(){ 5 | console.log('beforeEach'); 6 | loginController.loadUserList(['abc123','xyz321']); 7 | //throw {error: 'Thrwoing Error to fail'} 8 | }); 9 | 10 | describe('LoginController', function () { 11 | 12 | describe('isValidUserId', function(){ 13 | 14 | it('should return true if valid user id', function(){ 15 | var isValid = loginController.isValidUserId('abc123') 16 | assert.equal(isValid, true); 17 | }); 18 | 19 | it('should return false if invalid user id', function(){ 20 | var isValid = loginController.isValidUserId('abc1234') 21 | assert.equal(isValid, false); 22 | }); 23 | 24 | }); 25 | 26 | describe('isValidUserIdAsync', function(){ 27 | 28 | it('should return true if valid user id', function(done){ 29 | loginController.isValidUserIdAsync('abc123', 30 | function(isValid){ 31 | assert.equal(isValid, true); 32 | done(); 33 | }); 34 | }); 35 | 36 | }); 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/05-expect-should/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/05-expect-should/controllers/login.controller.js: -------------------------------------------------------------------------------- 1 | function LoginController() { 2 | 3 | var userList; 4 | function loadUserList(users){ 5 | userList = users; 6 | } 7 | 8 | function isValidUserId(user) { 9 | return userList.indexOf(user) >= 0; 10 | } 11 | 12 | function isValidUserIdAsync(user, callback) { 13 | setTimeout(function(){ 14 | callback(userList.indexOf(user) >= 0) 15 | }, 1); 16 | } 17 | 18 | return { 19 | isValidUserId, 20 | isValidUserIdAsync, 21 | loadUserList 22 | } 23 | 24 | } 25 | 26 | module.exports = LoginController(); 27 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/05-expect-should/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "05", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha './test/**/*.spec.js'" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "chai": "4.1.2", 13 | "mocha": "5.0.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/05-expect-should/test/controllers/login.controller.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var loginController = require('../../controllers/login.controller'); 3 | 4 | var expect = require('chai').expect; 5 | var should = require('chai').should(); 6 | 7 | beforeEach('Setting up the userList', function(){ 8 | console.log('beforeEach'); 9 | loginController.loadUserList(['abc123','xyz321']); 10 | }); 11 | 12 | describe('LoginController', function () { 13 | 14 | describe('isValidUserId', function(){ 15 | 16 | it('should return true if valid user id', function(){ 17 | var isValid = loginController.isValidUserId('abc123') 18 | //assert.equal(isValid, true); 19 | expect(isValid).to.be.true; 20 | }); 21 | 22 | it('should return false if invalid user id', function(){ 23 | var isValid = loginController.isValidUserId('abc1234') 24 | //assert.equal(isValid, false); 25 | isValid.should.equal(false); 26 | }); 27 | 28 | }); 29 | 30 | describe('isValidUserIdAsync', function(){ 31 | 32 | it('should return true if valid user id', function(done){ 33 | loginController.isValidUserIdAsync('abc123', 34 | function(isValid){ 35 | //assert.equal(isValid, true); 36 | isValid.should.equal(true); 37 | done(); 38 | }); 39 | }); 40 | 41 | }); 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/06-promise/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/06-promise/controllers/login.controller.js: -------------------------------------------------------------------------------- 1 | function LoginController() { 2 | 3 | var userList; 4 | function loadUserList(users){ 5 | userList = users; 6 | } 7 | 8 | function isValidUserId(user) { 9 | return userList.indexOf(user) >= 0; 10 | } 11 | 12 | function isValidUserIdAsync(user, callback) { 13 | setTimeout(function(){ 14 | callback(userList.indexOf(user) >= 0) 15 | }, 1); 16 | } 17 | 18 | function isAuthorizedPromise(user){ 19 | return new Promise(function(resolve){ 20 | setTimeout(function(){resolve(userList.indexOf(user) >= 0)}, 10); 21 | }); 22 | } 23 | 24 | return { 25 | isValidUserId, 26 | isValidUserIdAsync, 27 | loadUserList, 28 | isAuthorizedPromise 29 | } 30 | 31 | } 32 | 33 | module.exports = LoginController(); 34 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/06-promise/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "06", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha './test/**/*.spec.js'" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "chai": "4.1.2", 13 | "chai-as-promised": "7.1.1", 14 | "mocha": "5.0.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/06-promise/test/controllers/login.controller.spec.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var loginController = require('../../controllers/login.controller'); 3 | 4 | var expect = require('chai').expect; 5 | var should = require('chai').should(); 6 | 7 | var chai = require('chai'); 8 | var chaiAsPromised = require('chai-as-promised'); 9 | chai.use(chaiAsPromised).should(); 10 | 11 | beforeEach('Setting up the userList', function(){ 12 | console.log('beforeEach'); 13 | loginController.loadUserList(['abc123','xyz321']); 14 | }); 15 | 16 | describe('LoginController', function () { 17 | 18 | describe('isValidUserId', function(){ 19 | 20 | it('should return true if valid user id', function(){ 21 | var isValid = loginController.isValidUserId('abc123') 22 | //assert.equal(isValid, true); 23 | expect(isValid).to.be.true; 24 | }); 25 | 26 | it('should return false if invalid user id', function(){ 27 | var isValid = loginController.isValidUserId('abc1234') 28 | //assert.equal(isValid, false); 29 | isValid.should.equal(false); 30 | }); 31 | 32 | }); 33 | 34 | describe('isValidUserIdAsync', function(){ 35 | 36 | it('should return true if valid user id', function(done){ 37 | loginController.isValidUserIdAsync('abc123', 38 | function(isValid){ 39 | //assert.equal(isValid, true); 40 | isValid.should.equal(true); 41 | done(); 42 | }); 43 | }); 44 | 45 | }); 46 | 47 | describe('isAuthorizedPromise', function(){ 48 | 49 | it('should return true if valid user id', function(){ 50 | return loginController.isAuthorizedPromise('abc123').should.eventually.be.true; 51 | }); 52 | 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/07-chai-assertion/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /coverage 6 | 7 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/07-chai-assertion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "07", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "chai": "4.2.0", 13 | "chai-as-promised": "^7.1.1", 14 | "mocha": "5.0.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/07-chai-assertion/test/test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert'); 3 | var should = require('chai').should(); 4 | 5 | describe('Object Test', function(){ 6 | it('should have property name', function(){ 7 | var car = {name:'Figo', Maker:'Ford'} 8 | 9 | car.should.have.property('name'); 10 | }); 11 | 12 | it('should have property name with value Figo', function(){ 13 | var car = {name:'Figo', Maker:'Ford'} 14 | car.should.have.property('name').equal('Figo'); 15 | }); 16 | 17 | it('should compare objects', function(){ 18 | var car = {name:'Figo', Maker:'Ford'} 19 | var car1 = {name:'Figo', Maker:'Ford'} 20 | 21 | // car.should.equal(car1); 22 | car.should.deep.equal(car1); 23 | }); 24 | 25 | it('handling null', function(){ 26 | var car = null; 27 | //car.should.not.exist; 28 | should.not.exist(car); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /javascript-unit-testing-with-mocha/README.md: -------------------------------------------------------------------------------- 1 | ## Javascript Unit Testing with Mocha 2 | code about JavaScript Unit test with Mocha, Chai, Sinon 3 | 4 | ### Setup 5 | * Install [Nodejs](http://nodejs.org) >= v6.10.3 6 | * Install Mocha by running the command `$ npm install --global mocha` 7 | * Clone this Project and navigate to the javascript-unit-testing-with-mocha/xx directory in command line (xx is like 01) 8 | * Run `npm install` to install all dependencies from package.json 9 | * Run `npm test` to run all test specs. 10 | OR 11 | * RUN `bash src/bash/install-n-run-them-all.sh` 12 | -------------------------------------------------------------------------------- /js-unit-test-examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | ## Ignore Visual Studio temporary files, build results, and 40 | ## files generated by popular Visual Studio add-ons. 41 | ## 42 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 43 | 44 | # User-specific files 45 | *.suo 46 | *.user 47 | *.userosscache 48 | *.sln.docstates 49 | 50 | # User-specific files (MonoDevelop/Xamarin Studio) 51 | *.userprefs 52 | 53 | # Build results 54 | [Dd]ebug/ 55 | [Dd]ebugPublic/ 56 | [Rr]elease/ 57 | [Rr]eleases/ 58 | x64/ 59 | x86/ 60 | bld/ 61 | [Bb]in/ 62 | [Oo]bj/ 63 | [Ll]og/ 64 | 65 | # Visual Studio 2015 cache/options directory 66 | .vs/ 67 | # Uncomment if you have tasks that create the project's static files in wwwroot 68 | #wwwroot/ 69 | 70 | # MSTest test Results 71 | [Tt]est[Rr]esult*/ 72 | [Bb]uild[Ll]og.* 73 | 74 | # NUNIT 75 | *.VisualState.xml 76 | TestResult.xml 77 | 78 | # Build Results of an ATL Project 79 | [Dd]ebugPS/ 80 | [Rr]eleasePS/ 81 | dlldata.c 82 | 83 | # .NET Core 84 | project.lock.json 85 | project.fragment.lock.json 86 | artifacts/ 87 | **/Properties/launchSettings.json 88 | 89 | *_i.c 90 | *_p.c 91 | *_i.h 92 | *.ilk 93 | *.meta 94 | *.obj 95 | *.pch 96 | *.pdb 97 | *.pgc 98 | *.pgd 99 | *.rsp 100 | *.sbr 101 | *.tlb 102 | *.tli 103 | *.tlh 104 | *.tmp 105 | *.tmp_proj 106 | *.log 107 | *.vspscc 108 | *.vssscc 109 | .builds 110 | *.pidb 111 | *.svclog 112 | *.scc 113 | 114 | # Chutzpah Test files 115 | _Chutzpah* 116 | 117 | # Visual C++ cache files 118 | ipch/ 119 | *.aps 120 | *.ncb 121 | *.opendb 122 | *.opensdf 123 | *.sdf 124 | *.cachefile 125 | *.VC.db 126 | *.VC.VC.opendb 127 | 128 | # Visual Studio profiler 129 | *.psess 130 | *.vsp 131 | *.vspx 132 | *.sap 133 | 134 | # TFS 2012 Local Workspace 135 | $tf/ 136 | 137 | # Guidance Automation Toolkit 138 | *.gpState 139 | 140 | # ReSharper is a .NET coding add-in 141 | _ReSharper*/ 142 | *.[Rr]e[Ss]harper 143 | *.DotSettings.user 144 | 145 | # JustCode is a .NET coding add-in 146 | .JustCode 147 | 148 | # TeamCity is a build add-in 149 | _TeamCity* 150 | 151 | # DotCover is a Code Coverage Tool 152 | *.dotCover 153 | 154 | # Visual Studio code coverage results 155 | *.coverage 156 | *.coveragexml 157 | 158 | # NCrunch 159 | _NCrunch_* 160 | .*crunch*.local.xml 161 | nCrunchTemp_* 162 | 163 | # MightyMoose 164 | *.mm.* 165 | AutoTest.Net/ 166 | 167 | # Web workbench (sass) 168 | .sass-cache/ 169 | 170 | # Installshield output folder 171 | [Ee]xpress/ 172 | 173 | # DocProject is a documentation generator add-in 174 | DocProject/buildhelp/ 175 | DocProject/Help/*.HxT 176 | DocProject/Help/*.HxC 177 | DocProject/Help/*.hhc 178 | DocProject/Help/*.hhk 179 | DocProject/Help/*.hhp 180 | DocProject/Help/Html2 181 | DocProject/Help/html 182 | 183 | # Click-Once directory 184 | publish/ 185 | 186 | # Publish Web Output 187 | *.[Pp]ublish.xml 188 | *.azurePubxml 189 | # TODO: Comment the next line if you want to checkin your web deploy settings 190 | # but database connection strings (with potential passwords) will be unencrypted 191 | *.pubxml 192 | *.publishproj 193 | 194 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 195 | # checkin your Azure Web App publish settings, but sensitive information contained 196 | # in these scripts will be unencrypted 197 | PublishScripts/ 198 | 199 | # NuGet Packages 200 | *.nupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/packages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/packages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/packages/repositories.config 207 | # NuGet v3's project.json files produces more ignoreable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | node_modules/ 241 | orleans.codegen.cs 242 | 243 | # Since there are multiple workflows, uncomment next line to ignore bower_components 244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 245 | #bower_components/ 246 | 247 | # RIA/Silverlight projects 248 | Generated_Code/ 249 | 250 | # Backup & report files from converting an old project file 251 | # to a newer Visual Studio version. Backup files are not needed, 252 | # because we have git ;-) 253 | _UpgradeReport_Files/ 254 | Backup*/ 255 | UpgradeLog*.XML 256 | UpgradeLog*.htm 257 | 258 | # SQL Server files 259 | *.mdf 260 | *.ldf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | 267 | # Microsoft Fakes 268 | FakesAssemblies/ 269 | 270 | # GhostDoc plugin setting file 271 | *.GhostDoc.xml 272 | 273 | # Node.js Tools for Visual Studio 274 | .ntvs_analysis.dat 275 | 276 | # Visual Studio 6 build log 277 | *.plg 278 | 279 | # Visual Studio 6 workspace options file 280 | *.opt 281 | 282 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 283 | *.vbw 284 | 285 | # Visual Studio LightSwitch build output 286 | **/*.HTMLClient/GeneratedArtifacts 287 | **/*.DesktopClient/GeneratedArtifacts 288 | **/*.DesktopClient/ModelManifest.xml 289 | **/*.Server/GeneratedArtifacts 290 | **/*.Server/ModelManifest.xml 291 | _Pvt_Extensions 292 | 293 | # Paket dependency manager 294 | .paket/paket.exe 295 | paket-files/ 296 | 297 | # FAKE - F# Make 298 | .fake/ 299 | 300 | # JetBrains Rider 301 | .idea/ 302 | *.sln.iml 303 | 304 | # CodeRush 305 | .cr/ 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | -------------------------------------------------------------------------------- /js-unit-test-examples/LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /js-unit-test-examples/README.md: -------------------------------------------------------------------------------- 1 | ## JavaScript Unit Test Examples 2 | This repository contains a collection of example setups for common JavaScript unit testing frameworks and tools. 3 | 4 | |Example|Coverage|ES6|TypeScript| 5 | |---|---|---|---| 6 | |[ava](https://github.com/Wedvich/js-unit-test-examples/tree/master/ava)|:heavy_check_mark:||| 7 | |[ava-nyc](https://github.com/Wedvich/js-unit-test-examples/tree/master/ava-nyc)|:heavy_check_mark:|:heavy_check_mark:|| 8 | |[jasmine](https://github.com/Wedvich/js-unit-test-examples/tree/master/jasmine)|||| 9 | |[jasmine-chutzpah](https://github.com/Wedvich/js-unit-test-examples/tree/master/jasmine-chutzpah)|||| 10 | |[jest](https://github.com/Wedvich/js-unit-test-examples/tree/master/jest)|:heavy_check_mark:|:heavy_check_mark:|| 11 | |[mocha-chai](https://github.com/Wedvich/js-unit-test-examples/tree/master/mocha-chai)|||| 12 | |[mocha-chai-istanbul](https://github.com/Wedvich/js-unit-test-examples/tree/master/mocha-chai-istanbul)|:heavy_check_mark:||| 13 | |[mocha-chai-ts](https://github.com/Wedvich/js-unit-test-examples/tree/master/mocha-chai-ts)||:heavy_check_mark:|:heavy_check_mark:| 14 | |[mocha-chai-ts-istanbul](https://github.com/Wedvich/js-unit-test-examples/tree/master/mocha-chai-ts-istanbul)|:heavy_check_mark:|:heavy_check_mark:|:heavy_check_mark:| 15 | |[tap-nyc](https://github.com/Wedvich/js-unit-test-examples/tree/master/tap-nyc)|:heavy_check_mark:||| 16 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava-nyc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-ava-nyc", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "nyc ava" 8 | }, 9 | "author": "", 10 | "license": "Unlicense", 11 | "devDependencies": { 12 | "ava": "^0.17.0", 13 | "nyc": "^10.1.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava-nyc/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava-nyc/test/MathLib/add.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('add', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.add(1, 2); 7 | t.is(result, 3); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava-nyc/test/MathLib/fibonacci.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('fibonacci', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.fibonacci(12); 7 | t.is(result[12], 144); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava-nyc/test/MathLib/multiply.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('multiply', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.multiply(3, 3); 7 | t.is(result, 9); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-ava", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "ava" 8 | }, 9 | "author": "", 10 | "license": "Unlicense", 11 | "devDependencies": { 12 | "ava": "^0.17.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava/test/MathLib/add.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('add', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.add(1, 2); 7 | t.is(result, 3); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava/test/MathLib/fibonacci.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('fibonacci', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.fibonacci(12); 7 | t.is(result[12], 144); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/ava/test/MathLib/multiply.test.js: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import MathLib from '../../src/index'; 3 | 4 | test('multiply', t => { 5 | const mathLib = new MathLib(); 6 | const result = mathLib.multiply(3, 3); 7 | t.is(result, 9); 8 | }); 9 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace jasmine_chutzpah 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/chutzpah.json: -------------------------------------------------------------------------------- 1 | { 2 | "Framework": "jasmine", 3 | "References": [ 4 | { 5 | "Path": "src", 6 | "Includes": ["*.js"] 7 | } 8 | ], 9 | "Tests": [ 10 | { "Includes": ["*.spec.js"] } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/jasmine-chutzpah.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B303D105-FF28-4F88-9B2F-751FE1485E9D} 8 | Exe 9 | Properties 10 | jasmine_chutzpah 11 | jasmine-chutzpah 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 68 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/jasmine-chutzpah.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "jasmine-chutzpah", "jasmine-chutzpah.csproj", "{B303D105-FF28-4F88-9B2F-751FE1485E9D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B303D105-FF28-4F88-9B2F-751FE1485E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {B303D105-FF28-4F88-9B2F-751FE1485E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {B303D105-FF28-4F88-9B2F-751FE1485E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {B303D105-FF28-4F88-9B2F-751FE1485E9D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/spec/index.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | describe('MathLib', function () { 5 | describe('add', function () { 6 | it('adds two numbers together', function () { 7 | var mathLib = new MathLib(); 8 | var result = mathLib.add(1, 2); 9 | expect(result).toEqual(3); 10 | }); 11 | }); 12 | 13 | describe('multiply', function () { 14 | it('multiply two numbers', function () { 15 | var mathLib = new MathLib(); 16 | var result = mathLib.multiply(3, 3); 17 | expect(result).toEqual(9); 18 | }); 19 | }); 20 | 21 | describe('fibonacci', function () { 22 | it('generates a valid fibonacci sequence', function () { 23 | var mathLib = new MathLib(); 24 | var result = mathLib.fibonacci(12); 25 | expect(result[12]).toEqual(144); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine-chutzpah/src/index.js: -------------------------------------------------------------------------------- 1 | var MathLib = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-jasmine", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jasmine" 8 | }, 9 | "author": "", 10 | "license": "Unlicense", 11 | "devDependencies": { 12 | "jasmine": "^2.5.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine/spec/index.spec.js: -------------------------------------------------------------------------------- 1 | describe('MathLib', function () { 2 | var MathLib = require('../src/index.js'); 3 | 4 | describe('add', function () { 5 | it('adds two numbers together', function () { 6 | var mathLib = new MathLib(); 7 | var result = mathLib.add(1, 2); 8 | expect(result).toEqual(3); 9 | }); 10 | }); 11 | 12 | describe('multiply', function () { 13 | it('multiply two numbers', function () { 14 | var mathLib = new MathLib(); 15 | var result = mathLib.multiply(3, 3); 16 | expect(result).toEqual(9); 17 | }); 18 | }); 19 | 20 | describe('fibonacci', function () { 21 | it('generates a valid fibonacci sequence', function () { 22 | var mathLib = new MathLib(); 23 | var result = mathLib.fibonacci(12); 24 | expect(result[12]).toEqual(144); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine/spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ], 9 | "stopSpecOnExpectationFailure": false, 10 | "random": false 11 | } 12 | -------------------------------------------------------------------------------- /js-unit-test-examples/jasmine/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-jest", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jest" 8 | }, 9 | "author": "", 10 | "license": "Unlicense", 11 | "devDependencies": { 12 | "jest": "^18.1.0" 13 | }, 14 | "jest": { 15 | "collectCoverage": true, 16 | "collectCoverageFrom": ["src/**/*.js"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /js-unit-test-examples/jest/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/jest/test/index.test.js: -------------------------------------------------------------------------------- 1 | const MathLib = require('../src'); 2 | 3 | describe('MathLib', () => { 4 | describe('add', () => { 5 | it('adds two numbers together', () => { 6 | const mathLib = new MathLib(); 7 | const result = mathLib.add(1, 2); 8 | expect(result).toBe(3); 9 | }); 10 | }); 11 | 12 | describe('multiply', () => { 13 | it('multiply two numbers', () => { 14 | const mathLib = new MathLib(); 15 | const result = mathLib.multiply(3, 3); 16 | expect(result).toBe(9); 17 | }); 18 | }); 19 | 20 | describe('fibonacci', () => { 21 | it('generates a valid fibonacci sequence', () => { 22 | const mathLib = new MathLib(); 23 | const result = mathLib.fibonacci(12); 24 | expect(result[12]).toBe(144); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-istanbul/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-mocha-chai-istanbul", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "istanbul cover node_modules/mocha/bin/_mocha" 11 | }, 12 | "author": "", 13 | "license": "Unlicense", 14 | "devDependencies": { 15 | "chai": "^3.5.0", 16 | "istanbul": "^0.4.5", 17 | "mocha": "^3.2.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-istanbul/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-istanbul/test/index.test.js: -------------------------------------------------------------------------------- 1 | describe('MathLib', function () { 2 | var expect = require('chai').expect; 3 | var MathLib = require('../src/index.js'); 4 | 5 | describe('add', function () { 6 | it('adds two numbers together', function () { 7 | var mathLib = new MathLib(); 8 | var result = mathLib.add(1, 2); 9 | expect(result).to.equal(3); 10 | }); 11 | }); 12 | 13 | describe('multiply', function () { 14 | it('multiply two numbers', function () { 15 | var mathLib = new MathLib(); 16 | var result = mathLib.multiply(3, 3); 17 | expect(result).to.equal(9); 18 | }); 19 | }); 20 | 21 | describe('fibonacci', function () { 22 | it('generates a valid fibonacci sequence', function () { 23 | var mathLib = new MathLib(); 24 | var result = mathLib.fibonacci(12); 25 | expect(result[12]).to.equal(144); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts-istanbul/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-mocha-chai-ts-istanbul", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "ts-node node_modules/istanbul/lib/cli.js cover -e .ts node_modules/mocha/bin/_mocha -- test/**/*.test.ts" 11 | }, 12 | "author": "", 13 | "license": "Unlicense", 14 | "devDependencies": { 15 | "@types/mocha": "^2.2.38", 16 | "@types/node": "^7.0.4", 17 | "chai": "^3.5.0", 18 | "istanbul": "^1.1.0-alpha.1", 19 | "mocha": "^3.2.0", 20 | "ts-node": "^2.0.0", 21 | "typescript": "^2.1.5" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts-istanbul/src/index.ts: -------------------------------------------------------------------------------- 1 | export class MathLib { 2 | add(a, b): Number { 3 | return a + b; 4 | } 5 | 6 | multiply(a, b): Number { 7 | return a * b; 8 | } 9 | 10 | fibonacci(length): Number[] { 11 | const sequence = [0, 1]; 12 | for (let i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts-istanbul/test/index.test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import { expect } from 'chai'; 5 | import { MathLib } from '../src'; 6 | 7 | describe('MathLib', () => { 8 | describe('add', () => { 9 | it('adds two numbers together', () => { 10 | const mathLib = new MathLib(); 11 | const result = mathLib.add(1, 2); 12 | expect(result).to.equal(3); 13 | }); 14 | }); 15 | 16 | describe('multiply', () => { 17 | it('multiply two numbers', () =>{ 18 | const mathLib = new MathLib(); 19 | const result = mathLib.multiply(3, 3); 20 | expect(result).to.equal(9); 21 | }); 22 | }); 23 | 24 | describe('fibonacci', () =>{ 25 | it('generates a valid fibonacci sequence', () =>{ 26 | const mathLib = new MathLib(); 27 | const result = mathLib.fibonacci(12); 28 | expect(result[12]).to.equal(144); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-mocha-chai-ts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "mocha --compilers ts:ts-node/register test/**/*.test.ts" 11 | }, 12 | "author": "", 13 | "license": "Unlicense", 14 | "devDependencies": { 15 | "@types/mocha": "^2.2.38", 16 | "@types/node": "^7.0.4", 17 | "chai": "^3.5.0", 18 | "mocha": "^3.2.0", 19 | "ts-node": "^2.0.0", 20 | "typescript": "^2.1.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts/src/index.ts: -------------------------------------------------------------------------------- 1 | export class MathLib { 2 | add(a, b): Number { 3 | return a + b; 4 | } 5 | 6 | multiply(a, b): Number { 7 | return a * b; 8 | } 9 | 10 | fibonacci(length): Number[] { 11 | const sequence = [0, 1]; 12 | for (let i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai-ts/test/index.test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | import { expect } from 'chai'; 5 | import { MathLib } from '../src'; 6 | 7 | describe('MathLib', () => { 8 | describe('add', () => { 9 | it('adds two numbers together', () => { 10 | const mathLib = new MathLib(); 11 | const result = mathLib.add(1, 2); 12 | expect(result).to.equal(3); 13 | }); 14 | }); 15 | 16 | describe('multiply', () => { 17 | it('multiply two numbers', () =>{ 18 | const mathLib = new MathLib(); 19 | const result = mathLib.multiply(3, 3); 20 | expect(result).to.equal(9); 21 | }); 22 | }); 23 | 24 | describe('fibonacci', () =>{ 25 | it('generates a valid fibonacci sequence', () =>{ 26 | const mathLib = new MathLib(); 27 | const result = mathLib.fibonacci(12); 28 | expect(result[12]).to.equal(144); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-mocha-chai", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "mocha" 11 | }, 12 | "author": "", 13 | "license": "Unlicense", 14 | "devDependencies": { 15 | "chai": "^3.5.0", 16 | "mocha": "^3.2.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/mocha-chai/test/index.test.js: -------------------------------------------------------------------------------- 1 | describe('MathLib', function () { 2 | var expect = require('chai').expect; 3 | var MathLib = require('../src/index.js'); 4 | 5 | describe('add', function () { 6 | it('adds two numbers together', function () { 7 | var mathLib = new MathLib(); 8 | var result = mathLib.add(1, 2); 9 | expect(result).to.equal(3); 10 | }); 11 | }); 12 | 13 | describe('multiply', function () { 14 | it('multiply two numbers', function () { 15 | var mathLib = new MathLib(); 16 | var result = mathLib.multiply(3, 3); 17 | expect(result).to.equal(9); 18 | }); 19 | }); 20 | 21 | describe('fibonacci', function () { 22 | it('generates a valid fibonacci sequence', function () { 23 | var mathLib = new MathLib(); 24 | var result = mathLib.fibonacci(12); 25 | expect(result[12]).to.equal(144); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /js-unit-test-examples/tap-nyc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-test-examples-tap-nyc", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "nyc --reporter=html tap ./test/**/*.spec.js" 8 | }, 9 | "author": "", 10 | "license": "Unlicense", 11 | "devDependencies": { 12 | "nyc": "^10.1.2", 13 | "tap": "^9.0.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /js-unit-test-examples/tap-nyc/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | this.add = function (a, b) { 3 | return a + b; 4 | }; 5 | 6 | this.multiply = function (a, b) { 7 | return a * b; 8 | }; 9 | 10 | this.fibonacci = function (length) { 11 | var sequence = [0, 1]; 12 | for (var i = 2; i <= length; ++i) { 13 | sequence[i] = sequence[i - 1] + sequence[i - 2]; 14 | } 15 | return sequence; 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /js-unit-test-examples/tap-nyc/test/MathLib/add.spec.js: -------------------------------------------------------------------------------- 1 | var tap = require('tap'); 2 | var MathLib = require('../../src/index.js'); 3 | 4 | var mathLib = new MathLib(); 5 | var result = mathLib.add(1, 2); 6 | tap.equal(result, 3); 7 | -------------------------------------------------------------------------------- /js-unit-test-examples/tap-nyc/test/MathLib/fibonacci.spec.js: -------------------------------------------------------------------------------- 1 | var tap = require('tap'); 2 | var MathLib = require('../../src/index.js'); 3 | 4 | var mathLib = new MathLib(); 5 | var result = mathLib.fibonacci(12); 6 | tap.equal(result[12], 144); 7 | -------------------------------------------------------------------------------- /js-unit-test-examples/tap-nyc/test/MathLib/multiply.spec.js: -------------------------------------------------------------------------------- 1 | var tap = require('tap'); 2 | var MathLib = require('../../src/index.js'); 3 | 4 | var mathLib = new MathLib(); 5 | var result = mathLib.multiply(3, 3); 6 | tap.equal(result, 9); 7 | -------------------------------------------------------------------------------- /js-unit-testing-examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } -------------------------------------------------------------------------------- /js-unit-testing-examples/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | end_of_line = lf 8 | 9 | [*.{js,md}] 10 | indent_style = space 11 | indent_size = 4 12 | 13 | [{package.json,.travis.yml}] 14 | indent_style = space 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /js-unit-testing-examples/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "globals": { 8 | "chai": true, 9 | "expect": true, 10 | "sinon": true 11 | }, 12 | "extends": "eslint:recommended", 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "indent": [ 18 | "error", 19 | 4 20 | ], 21 | "linebreak-style": [ 22 | "error", 23 | "unix" 24 | ], 25 | "quotes": [ 26 | "error", 27 | "single" 28 | ], 29 | "semi": [ 30 | "error", 31 | "always" 32 | ], 33 | "no-console": "warn" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /js-unit-testing-examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /js-unit-testing-examples/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vsicons.presets.angular": false 3 | } -------------------------------------------------------------------------------- /js-unit-testing-examples/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Marc Littlemore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /js-unit-testing-examples/README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Unit Testing Examples 2 | 3 | Example project to allow me to show how best to unit test a JavaScript Express application. 4 | 5 | ## Install 6 | 7 | Clone this repository and install the dependencies as follows: 8 | 9 | ``` 10 | git clone git@github.com:MarcL/js-unit-testing-framework.git 11 | npm install 12 | ``` 13 | 14 | ## Running the tests 15 | 16 | The code sets up a basic Express server with a few routes and some tests which cover testing the server setup. Run the test suite using npm: 17 | 18 | ``` 19 | npm test 20 | ``` 21 | 22 | ## JavaScript Tests 23 | 24 | Take a look in the `test` directory to see all of the test code. There are lots of examples of different types of tests and how to create them. 25 | 26 | ### Asynchronous functions and promises 27 | 28 | Some examples of how to test asynchronous functions and promises, including some tips and tricks and gotchas. 29 | 30 | #### Asynchronous function 31 | - Timeout because `done` callback isn't called when function succeeds 32 | - Passing test but slow because timer isn't stubbed 33 | - Passing test and fast because timer is stubbed 34 | - Timeout because `done` callback isn't called when function throws an error 35 | - Passing test to call `done` callback when function throws an error 36 | 37 | #### Promise : resolving 38 | - Test passes incorrectly because Promise isn't returned 39 | - Passing test because promise is returned 40 | - Passing test because `done` callback is called after resolution 41 | - Passing test because `done` callback is called after resolution using `chai-as-promised` syntax 42 | 43 | #### Promise : rejecting 44 | - Test passes incorrectly because Promise isn't returned 45 | - Failing test because rejected Promise error isn't caught 46 | - Passing test because Promise is returned and rejection is caught 47 | - Passing test because Promise rejection is caught and `done` callback is called 48 | - Passing test because Promise rejection is caught and `done` callback is called using `chai-as-promised` syntax 49 | 50 | #### Slow tests 51 | - Passing test but is slow due to Promise function in chain taking a long time 52 | - Passing test and much faster as longer function is now stubbed to execute immediately 53 | 54 | -------------------------------------------------------------------------------- /js-unit-testing-examples/index.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | 3 | var server = require('./src/launch'); 4 | server.start(); -------------------------------------------------------------------------------- /js-unit-testing-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-unit-testing-framework", 3 | "version": "0.0.1", 4 | "description": "Unit testing Express routes using Mocha", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "eslint src/ test/", 8 | "precommit": "npm run lint", 9 | "prepush": "npm run test", 10 | "start": "node .", 11 | "test": "mocha", 12 | "test:watch": "mocha --watch" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+ssh://git@github.com/MarcL/js-unit-testing-framework.git" 17 | }, 18 | "keywords": [ 19 | "unit", 20 | "testing", 21 | "mocha", 22 | "express", 23 | "routes" 24 | ], 25 | "author": "Marc Littlemore", 26 | "license": "MIT", 27 | "homepage": "https://github.com/MarcL/unit-test-express-routes#readme", 28 | "dependencies": { 29 | "babel-preset-es2015": "^6.24.1", 30 | "babel-register": "^6.24.1", 31 | "bluebird": "^3.5.0", 32 | "express": "^4.15.2" 33 | }, 34 | "devDependencies": { 35 | "chai": "^3.5.0", 36 | "chai-as-promised": "~6.0.0", 37 | "eslint": "^3.19.0", 38 | "eslint-config-airbnb-base": "^11.1.3", 39 | "eslint-plugin-import": "~2.2.0", 40 | "husky": "^0.13.3", 41 | "mocha": "~3.4.1", 42 | "node-mocks-http": "^1.6.1", 43 | "proxyquire": "^1.7.10", 44 | "sinon": "^2.2.0", 45 | "sinon-chai": "^2.10.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/data/fakeData.js: -------------------------------------------------------------------------------- 1 | export default { 2 | events: [] 3 | }; 4 | 5 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/launch.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | import homepage from './middleware/homepage'; 4 | import login from './middleware/login'; 5 | import authenticate from './middleware/authenticate'; 6 | import dashboard from './middleware/dashboard'; 7 | import promiseTest from './middleware/promiseTest'; 8 | import apiRoutes from './routes/api'; 9 | 10 | function setupRoutes(app) { 11 | app.get('/', homepage); 12 | app.get('/login', login); 13 | app.get('/dashboard', 14 | authenticate, 15 | dashboard 16 | ); 17 | app.get('/promises', promiseTest); 18 | 19 | app.use('/api', apiRoutes); 20 | } 21 | 22 | function start(port = 7080) { 23 | const app = express(); 24 | 25 | setupRoutes(app); 26 | 27 | const server = app.listen(port, () => { 28 | console.log(`Server running on: ${port}`); 29 | }); 30 | 31 | return server; 32 | } 33 | 34 | export { 35 | start 36 | }; 37 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/api/eventsGetAll.js: -------------------------------------------------------------------------------- 1 | import * as events from '../../services/events'; 2 | 3 | const eventsGetAll = (request, response) => { 4 | const renderJsonResponse = (dataObject, success = true) => { 5 | const jsonResponse = Object.assign( 6 | dataObject, 7 | {success} 8 | ); 9 | response.json(jsonResponse); 10 | }; 11 | 12 | return events.getAll() 13 | .then((data) => { 14 | renderJsonResponse({ 15 | data 16 | }); 17 | }) 18 | .catch((error) => { 19 | renderJsonResponse({ 20 | message: error.name 21 | }, false); 22 | }); 23 | }; 24 | 25 | export default eventsGetAll; 26 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/authenticate.js: -------------------------------------------------------------------------------- 1 | function authenticate(request, response, next) { 2 | // TODO: Authenticate request and redirect to login if not authenticated 3 | console.log('verify authentication or redirect'); 4 | next(); 5 | } 6 | 7 | export default authenticate; 8 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/dashboard.js: -------------------------------------------------------------------------------- 1 | function dashboard(request, response) { 2 | response.send('dashboard is here'); 3 | } 4 | 5 | export default dashboard; 6 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/homepage.js: -------------------------------------------------------------------------------- 1 | function homepage(request, response) { 2 | response.send('homepage is here'); 3 | } 4 | 5 | export default homepage; 6 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/login.js: -------------------------------------------------------------------------------- 1 | function homepage(request, response) { 2 | response.send('login is here'); 3 | } 4 | 5 | export default homepage; 6 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/middleware/promiseTest.js: -------------------------------------------------------------------------------- 1 | function promiseWrapper(shouldFail) { 2 | return shouldFail ? 3 | Promise.reject() : 4 | Promise.resolve(); 5 | } 6 | 7 | function promiseTest(request, response) { 8 | const {fail: shouldFail = false} = request.query; 9 | 10 | return promiseWrapper(shouldFail) 11 | .then(() => { 12 | response.json({ 13 | message: 'resolved Promise', 14 | error: false 15 | }); 16 | }) 17 | .catch(() => { 18 | response.json({ 19 | message: 'rejected Promise', 20 | error: true 21 | }); 22 | }); 23 | } 24 | 25 | export default promiseTest; 26 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/routes/api.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import eventsGetAll from '../middleware/api/eventsGetAll'; 3 | 4 | const router = express.Router(); 5 | 6 | router.get('/', (request, response) => { 7 | response.json({success: true}); 8 | }); 9 | 10 | // TODO 11 | // - Add GET for all data /events - return data + 200 12 | router.get('/events', eventsGetAll); 13 | //router.get('/events/:id', dataGetById); 14 | 15 | // - Add POST to add new data /events - return 201 16 | // - Add GET for single data element /events/:id -200 / 404 17 | // - Add PUT to update single data element /events/:id - 200/204 (no content)/4040 18 | // - Add DELETE to delete single data element /events/:id - 200/404 19 | // - Add authentication - basic auth - 'auth' -> 'key:' (no password) + base64 encoded - 401 if failed 20 | 21 | export default router; 22 | -------------------------------------------------------------------------------- /js-unit-testing-examples/src/services/events.js: -------------------------------------------------------------------------------- 1 | import fakeData from '../data/fakeData'; 2 | 3 | const getAll = () => { 4 | return Promise.resolve(fakeData.events); 5 | }; 6 | 7 | export { 8 | getAll 9 | }; 10 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/examples/asynchronous.test.js: -------------------------------------------------------------------------------- 1 | // All tests that are skipped are done so because otherwise I won't allow 2 | // them to be pushed to a git repo due to running the tests on the prepush rule in package.json 3 | describe('Example asynchronous JavaScript tests', () => { 4 | describe('while testing asynchronous function', () => { 5 | // eslint-disable-next-line no-unused-vars 6 | it.skip('[FAILING TEST] should timeout because the done callback is not called', (done) => { 7 | setTimeout(() => { 8 | expect(true).to.be.true; 9 | }, 1000); 10 | }); 11 | 12 | it('[PASSING BUT BAD TEST] should pass because the done callback is called but takes too long (~1000ms) to run', (done) => { 13 | setTimeout(() => { 14 | expect(true).to.be.true; 15 | done(); 16 | }, 1000); 17 | }); 18 | 19 | describe('better asynchronous test that stubs timer', () => { 20 | let fakeClock; 21 | 22 | beforeEach(() => { 23 | fakeClock = sinon.useFakeTimers(); 24 | }); 25 | 26 | afterEach(() => { 27 | fakeClock.restore(); 28 | }); 29 | 30 | it('[PASSING AND BETTER TEST] should stub clock to allow quick resolution of asynchronous function', (done) => { 31 | setTimeout(() => { 32 | expect(true).to.be.true; 33 | done(); 34 | }, 1000); 35 | 36 | fakeClock.tick(1000); 37 | }); 38 | }); 39 | 40 | // eslint-disable-next-line no-unused-vars 41 | it.skip('[FAILING TEST] should timeout because the done callback is not called when function has errors', (done) => { 42 | setTimeout(() => { 43 | throw new Error('Something has gone wrong'); 44 | 45 | // eslint-disable-next-line no-unreachable 46 | expect(true).to.be.true; 47 | }, 10); 48 | }); 49 | 50 | it('[PASSING TEST] should call the done callback when error occurs', (done) => { 51 | setTimeout(() => { 52 | try { 53 | throw new Error('Something has gone wrong'); 54 | 55 | } catch(error) { 56 | expect(true).to.be.true; 57 | done(); 58 | } 59 | }, 10); 60 | }); 61 | }); 62 | 63 | describe('while testing Promises', () => { 64 | describe('when Promise resolves', () => { 65 | it('[INCORRECT TEST] should pass but it never checks expectation', () => { 66 | const givenString = 'finished'; 67 | Promise.resolve(givenString) 68 | .then((data) => { 69 | expect(data).to.equal(givenString); 70 | }); 71 | }); 72 | 73 | it('[PASSING TEST] should pass because it returns the promise', () => { 74 | const givenString = 'finished'; 75 | return Promise.resolve(givenString) 76 | .then((data) => { 77 | expect(data).to.equal(givenString); 78 | }); 79 | }); 80 | 81 | it('[PASSING TEST] should pass because it calls the done callback when Promise has resolved', (done) => { 82 | const givenString = 'finished'; 83 | Promise.resolve(givenString) 84 | .then((data) => { 85 | expect(data).to.equal(givenString); 86 | done(); 87 | }); 88 | }); 89 | 90 | it('[PASSING TEST] should pass because it calls the done callback when Promise has resolved using chai-as-promised syntax', (done) => { 91 | const givenString = 'finished'; 92 | Promise.resolve(givenString) 93 | .then((data) => { 94 | expect(data).to.equal(givenString); 95 | }) 96 | .should.notify(done); 97 | }); 98 | }); 99 | 100 | describe('when Promise rejects', () => { 101 | it('[FAILING TEST] should pass because it does not return the Promise', () => { 102 | const givenString = 'error'; 103 | Promise.reject(givenString); 104 | }); 105 | 106 | it.skip('[FAILING TEST] should fail because it does not catch the rejection when returning the Promise', () => { 107 | const givenString = 'error'; 108 | return Promise.reject(givenString); 109 | }); 110 | 111 | it('[PASSING TEST] should pass because it catches the rejection and returns the Promise', () => { 112 | const givenString = 'error'; 113 | return Promise.reject(givenString) 114 | .catch((error) => { 115 | expect(error).to.equal(givenString); 116 | }); 117 | }); 118 | 119 | it('[PASSING TEST] should pass because it catches the rejection and calls the done callback', (done) => { 120 | const givenString = 'error'; 121 | Promise.reject(givenString) 122 | .catch((error) => { 123 | expect(error).to.equal(givenString); 124 | done(); 125 | }); 126 | }); 127 | 128 | it('[PASSING TEST] should pass because it catches the rejection and calls the done callback using chai-as-promised syntax', (done) => { 129 | const givenString = 'error'; 130 | Promise.reject(givenString) 131 | .catch((error) => { 132 | expect(error).to.equal(givenString); 133 | }) 134 | .should.notify(done); 135 | }); 136 | }); 137 | }); 138 | 139 | describe('while testing function with internal function which takes some time', () => { 140 | const moduleUnderTest = { 141 | longFunction(data) { 142 | return new Promise((resolve) => { 143 | setTimeout(() => { 144 | resolve(data); 145 | }, 1000); 146 | }); 147 | } 148 | }; 149 | 150 | it('[BAD TEST] should pass but takes too long (~1000ms) to run', () => { 151 | const givenString = 'finished'; 152 | 153 | return Promise.resolve(givenString) 154 | .then(data => moduleUnderTest.longFunction(data)) 155 | .then((data) => { 156 | expect(data).to.equal(givenString); 157 | }); 158 | }); 159 | 160 | describe('when long function is stubbed to execute immediately', () => { 161 | let stubLongFunction; 162 | 163 | beforeEach(() => { 164 | stubLongFunction = sinon.stub(moduleUnderTest, 'longFunction'); 165 | }); 166 | 167 | afterEach(() => { 168 | stubLongFunction.restore(); 169 | }); 170 | 171 | it('[FIXED TEST] should pass and long function will execute immediately', () => { 172 | const givenString = 'finished'; 173 | 174 | // Stub our long function so it returns immediately 175 | // with the data we expect it to return 176 | stubLongFunction.resolves(givenString); 177 | 178 | return Promise.resolve(givenString) 179 | .then(data => moduleUnderTest.longFunction(data)) 180 | .then((data) => { 181 | expect(data).to.equal(givenString); 182 | }); 183 | }); 184 | }); 185 | }); 186 | }); 187 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | --require test/support/base 3 | --compilers js:babel-register 4 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/src/launch.test.js: -------------------------------------------------------------------------------- 1 | import proxyquire from 'proxyquire'; 2 | 3 | describe('Express server', () => { 4 | let stubExpress; 5 | let spyExpressGet; 6 | let stubExpressListen; 7 | let spyHomepage; 8 | let spyLogin; 9 | let spyAuthenticate; 10 | let spyDashboard; 11 | let fakeExpress; 12 | let server; 13 | const fakeHttpServer = {}; 14 | 15 | beforeEach(() => { 16 | spyExpressGet = sinon.spy(); 17 | stubExpressListen = sinon.stub(); 18 | spyHomepage = sinon.spy(); 19 | spyLogin = sinon.spy(); 20 | spyAuthenticate = sinon.spy(); 21 | spyDashboard = sinon.spy(); 22 | 23 | // Create fake express application with spy methods 24 | fakeExpress = { 25 | get: spyExpressGet, 26 | listen: stubExpressListen, 27 | use: () => {} 28 | }; 29 | 30 | // Return fake express application when express() is called 31 | stubExpress = sinon.stub().returns(fakeExpress); 32 | 33 | // app.listen returns a fake HttpServer 34 | stubExpressListen.returns(fakeHttpServer); 35 | 36 | // Use proxyquire to stub required modules and return 37 | // our spies so we can check assertions 38 | server = proxyquire('../../src/launch', { 39 | express: stubExpress, 40 | './middleware/homepage' : {default: spyHomepage}, 41 | './middleware/login': {default: spyLogin}, 42 | './middleware/authenticate': {default: spyAuthenticate}, 43 | './middleware/dashboard': {default: spyDashboard} 44 | }); 45 | }); 46 | 47 | it('should return expected http server', () => { 48 | const returnedServer = server.start(); 49 | expect(returnedServer).to.eql(fakeHttpServer); 50 | }); 51 | 52 | it('should setup default route', () => { 53 | server.start(); 54 | spyExpressGet.should.have.been.calledWithExactly('/', spyHomepage); 55 | }); 56 | 57 | it('should setup login route', () => { 58 | server.start(); 59 | spyExpressGet.should.have.been.calledWithExactly('/login', spyLogin); 60 | }); 61 | 62 | it('should setup dashboard route', () => { 63 | server.start(); 64 | spyExpressGet.should.have.been.calledWithExactly( 65 | '/dashboard', 66 | spyAuthenticate, 67 | spyDashboard 68 | ); 69 | }); 70 | 71 | it('should listen on default port 7080', () => { 72 | server.start(); 73 | stubExpressListen.should.have.been.calledWithExactly(7080, sinon.match.func); 74 | }); 75 | 76 | it('should listen on expected port if passed', () => { 77 | const expectedPort = 8888; 78 | server.start(expectedPort); 79 | stubExpressListen.should.have.been.calledWithExactly(expectedPort, sinon.match.func); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/src/middleware/api/dataGetAll.test.js: -------------------------------------------------------------------------------- 1 | import {createRequest, createResponse} from 'node-mocks-http'; 2 | import eventsGetAll from '../../../../src/middleware/api/eventsGetAll'; 3 | import * as eventsService from '../../../../src/services/events'; 4 | 5 | describe('eventsGetAll()', () => { 6 | let fakeRequest; 7 | let fakeResponse; 8 | let stubEventServiceGetAll; 9 | let spyResponseJson; 10 | 11 | const fakeData = []; 12 | 13 | beforeEach(() => { 14 | fakeRequest = createRequest(); 15 | fakeResponse = createResponse(); 16 | 17 | stubEventServiceGetAll = sinon.stub(eventsService, 'getAll'); 18 | stubEventServiceGetAll.resolves(fakeData); 19 | spyResponseJson = sinon.spy(fakeResponse, 'json'); 20 | }); 21 | 22 | afterEach(() => { 23 | stubEventServiceGetAll.restore(); 24 | }); 25 | 26 | it('should call data service getAll()', (done) => { 27 | eventsGetAll(fakeRequest, fakeResponse) 28 | .should.be.fulfilled 29 | .then(() => { 30 | expect(stubEventServiceGetAll.callCount).to.equal(1); 31 | }) 32 | .should.notify(done); 33 | }); 34 | 35 | it('should render expected json when data request succeeds', (done) => { 36 | const expectedData = { 37 | data: [], 38 | success: true 39 | }; 40 | 41 | eventsGetAll(fakeRequest, fakeResponse) 42 | .should.be.fulfilled 43 | .then(() => { 44 | expect(spyResponseJson) 45 | .to.have.been.calledWithExactly(expectedData); 46 | }) 47 | .should.notify(done); 48 | }); 49 | 50 | it('should render expected failure json when data request fails', (done) => { 51 | const givenFailureData = 'error connecting to database'; 52 | stubEventServiceGetAll.rejects(givenFailureData); 53 | 54 | const expectedData = { 55 | success: false, 56 | message: givenFailureData 57 | }; 58 | 59 | eventsGetAll(fakeRequest, fakeResponse) 60 | .should.be.fulfilled 61 | .then(() => { 62 | expect(spyResponseJson) 63 | .to.have.been.calledWithExactly(expectedData); 64 | }) 65 | .should.notify(done); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/src/middleware/promiseTest.test.js: -------------------------------------------------------------------------------- 1 | import {createRequest, createResponse} from 'node-mocks-http'; 2 | import promiseTest from '../../../src/middleware/promiseTest'; 3 | 4 | describe('promiseTest middleware', () => { 5 | let fakeRequest; 6 | let fakeResponse; 7 | let stubResponseJson; 8 | 9 | beforeEach(() => { 10 | fakeRequest = createRequest(); 11 | fakeResponse = createResponse(); 12 | 13 | stubResponseJson = sinon.stub(fakeResponse, 'json'); 14 | }); 15 | 16 | afterEach(() => { 17 | stubResponseJson.restore(); 18 | }); 19 | 20 | it('should render expected json when Promise resolves', () => { 21 | const expectedJson = { 22 | message: 'resolved Promise', 23 | error: false 24 | }; 25 | 26 | return promiseTest(fakeRequest, fakeResponse) 27 | .then(() => { 28 | expect(stubResponseJson) 29 | .to.have.been.calledWithExactly(expectedJson); 30 | }); 31 | }); 32 | 33 | it('should render expected json when Promise rejects', () => { 34 | fakeRequest.query.fail = true; 35 | const expectedJson = { 36 | message: 'rejected Promise', 37 | error: true 38 | }; 39 | 40 | return promiseTest(fakeRequest, fakeResponse) 41 | .then(() => { 42 | expect(stubResponseJson) 43 | .to.have.been.calledWithExactly(expectedJson); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/src/middleware/services/events.test.js: -------------------------------------------------------------------------------- 1 | import * as eventsService from '../../../../src/services/events'; 2 | 3 | describe('events service', () => { 4 | describe('getAll()', () => { 5 | it('should resolve with expected data', () => { 6 | const expectedData = []; 7 | 8 | eventsService.getAll() 9 | .should.be.fulfilled 10 | .then((data) => { 11 | expect(data).to.deep.equal(expectedData); 12 | }); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /js-unit-testing-examples/test/support/base.js: -------------------------------------------------------------------------------- 1 | import Bluebird from 'bluebird'; 2 | import sinon from 'sinon'; 3 | import chai, {expect} from 'chai'; 4 | import chaiAsPromised from 'chai-as-promised'; 5 | import chaiSinon from 'sinon-chai'; 6 | 7 | process.env.NODE_ENV = 'test'; 8 | 9 | chai.use(chaiAsPromised); 10 | chai.use(chaiSinon); 11 | chai.should(); 12 | 13 | // Expose all modules to node.js modules 14 | global.Promise = Bluebird; 15 | global.sinon = sinon; 16 | global.chai = chai; 17 | global.expect = expect; 18 | --------------------------------------------------------------------------------