Flashback Friday AngularJS in 2017
Agenda Setting up an angular app. Introduction to tools - Babel, Webpack Alternative to Gulp, Grunt & Bower. Writing Controllers, Services, Directives etc.. Testing Javascript with Jasmine. Setting up Karma with Webpack. Let’s understand code coverage.
Babel is a tool for transpiling (compiling) ES6/ES7 code to ECMAScript 5 code, which can be used today in any modern browser. Reference : https://kangax.github.io/compat-table/es6/
Installing Babel CLI $ npm install babel-cli -g $ babel example.js --out-file compiled.js babel - calling Babel example.js - the input ES6/ES7 file --out-file - the option passed to Babel for compiling a file. We can also use --out-dirfor compiling all files in a directory. The short versions of the options are -o for --out- fileand -d for --output-dir compiled.js - the output file
babel-register babel-register is a require hook, that will bind node’s require method and automatically transpile the file on the fly. $ npm install babel-register --save-dev babel-node For running some code via the command line the easiest way to integrate Babel is to use babel-node CLI, which is a replacement of node CLI. babel-node comes with babel-cli
Configure Babel - .babelrc { "presets": [], "plugins": [] } Let’s start telling Babel to transpile ES6 code to ES5. npm install babel-preset-es2015 --save-dev { "presets": [es2015], "plugins": [] }
Babel - Understanding Preset JavaScript has some proposals for new features that are not yet finalized. They are separated into 5 states (0 to 4). Look TC39 In Babel, these changes are bundled in 4 different presets: babel-preset-stage-0 babel-preset-stage-1 babel-preset-stage-2 babel-preset-stage-3 There is no babel-preset-stage-4 as it’s simply babel-preset-es2015
Configure Babel - A final look npm install babel-preset-stage-2 // You can also install stages. { "presets": [“es2015”,”stage-2”], "plugins": [“undeclared-variables-check”] } We shall configure babel with webpack later. References: https://babeljs.io/docs/ http://kleopetrov.me/2016/03/18/everything-about-babel/
webpack is a module bundler. This means webpack takes modules with dependencies and emits static assets representing those modules.
The state of JavaScript modules Fear You would copy and paste a library into a vendor folder, rely on global variables, try to concat everything in the right order and still would had to deal with namespace issues. Currently, We have UMD : Universal Module Definition AMD: Asynchronous Module Definition CJS: Common JS ESM: ECMA Script Modules
Let’s start Install it as dev dependency npm install webpack --save-dev There are four key parts to a basic Webpack configuration. entry - the starting point of your application loaders  -  the transformations you want to make on your code output  - where you want your compiled code to go plugins -transformations on chunks and bundles
Webpack - entry webpack creates a graph of all of your application's dependencies. The starting point of this graph is known as an entry point. It tells webpack where to start and follows the graph of dependencies to know what to bundle. It is application's entry point as the contextual root or the first file to kick off your app. module.exports = { entry: './path/to/my/entry/file.js' };
Webpack - output It tells webpack where to bundle your application. The webpack output property tells webpack how to treat bundled code. Webpack.config.js const path = require('path'); module.exports = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' } };
Webpack - loaders Loaders are transformations that are applied on the source code of a module. They allow you to pre-process files as you import or “load” them. Thus, loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle front-end build steps. const config = { module: { rules: [ { test: /.(js|jsx)$/, use: 'babel-loader' } ] }, };
Webpack - plugins Loaders only execute transforms on a per-file basis, plugins are most commonly used performing actions and custom functionality on "compilations" or "chunks" of your bundled modules . // webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); const config = { plugins: [ new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
Webpack - A final look var path = require('path'); module.exports = { entry: './foo.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'foo.bundle.js' } }; https://github.com/Innovaccer/angular-wizard/blob/test-cases/webpack.config.js
Webpack should replace your gulp/bower build pipeline. It allows for modular imports of npm modules, plenty of which are either front-end or universal.
Hot Module Replacement - HMR Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways: Retain application state which is lost during a full reload. Save valuable development time by only updating what's changed. Tweak styling faster -- almost comparable to changing styles in the browser's debugger.
Webpack Dev Server Use webpack with a development server that provides live reloading. This should be used for development only. It uses webpack-dev-middleware under the hood, which provides fast in-memory access to the webpack assets. devServer: { contentBase: './demo', stats: 'minimal' }
Much More.. Watcher $ webpack -w Live reload $ node_modules/.bin/webpack-dev-server Minification & other things Plugins are here.
A hello world angular app in ES6 - app // app.js import angular from 'angular'; const app = angular.module('demo', []); export default app;
A hello world angular app in ES6 - controller / service /Providers // controller.js import app from './app.js'; class TestCtrl { constructor() { 'ngInject'; this.name = 'ayush'; this.lastname = 'sharma'; } sayHello() { console.log(`Hello ${this.name} ${this.lastname}`); } } const ctrl = app.controller('TestCtrl', TestCtrl); export default ctrl;
Example https://github.com/Innovaccer/angular-wizard
TDD - Test Driven Development 1. Write test cases for a specific part of your code and these tests should fail! 2. Write your code to “fill in” the tests. Your code only serves to make all of your tests pass, and nothing more. 3. Once all of your tests pass, go back and clean up your code (this is called refactoring)
TDD - Test Driven Development - Program 1. Write a program to removes all vowels from a string. Think of specifications: ● It should remove all lowercase vowels. ● It should remove all uppercase vowels. ● It shouldn’t change empty strings. ● It shouldn’t change strings with no vowels
TDD - Test Driven Development - Examples • Remove all lowercase vowels: “Hello world” should become “Hll wrld”. • Remove all uppercase vowels: “Artistic Eagle” should become “rtstc gl”. • Don’t change empty strings: “” should stay “”. • Don’t change strings with no vowels: “Mhmm” should stay “Mhmm”
Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.
TDD - Test Driven Development - Jasmine T E S T S U I T E | * S P E C I F I C A T I O N S | * E X P E C T A T I O N S
TDD - Test Driven Development - Back to example describe("removeVowel", function () { it("should remove all lowercase vowels", function () { expect(removeVowel("Hello world")) .toEqual("Hll wrld"); }); it("should remove all uppercase vowels", function () { expect(removeVowel("Artistic Eagle")) .toEqual("rtstc gl"); }); // continue
TDD - Test Driven Development - Back to example // continue it("shouldn't change empty strings", function () { expect(removeVowel("")) .toEqual(""); }); it("shouldn't change strings with no vowels", function () { expect(removeVowel("Mhmm")) .toEqual("Mhmm"); }); });
TDD - Test Driven Development - Writing some code https://jsfiddle.net/ayusharma/z369j7Lj/2/
Jasmine - Matchers in Depth - Equality: toEqual The following expect functions will pass: expect(true).toEqual(true); expect([1, 2, 3]).toEqual([1, 2, 3]); expect({}).toEqual({}); Here are some examples of toEqual that will fail: expect(5).toEqual(12); expect([1, 2, 3, 4]).toEqual([1, 2, 3]); expect(true).toEqual(100);
Jasmine - Matchers in Depth https://jasmine.github.io/api/2.6/matchers.html
Jasmine - Spy (जासूस) Spies allow us to hook into certain functions, and check whether they were called, how many times they were called, what arguments they were called with, and so on. Spying allows you to replace a part of your program with a spy. A spy can pretend to be a function or an object. Let’s take a look..
Jasmine - Spy - Dictionary var Dictionary = function() {}; Dictionary.prototype.hello = function() { return "hello"; }; Dictionary.prototype.world = function() { return "world"; };
Jasmine - Spy - Person var Person = function() {}; Person.prototype.sayHelloWorld = function(dict) { return dict.hello() + " " + dict.world(); }; var dictionary = new Dictionary(); var person = new Person(); person.sayHelloWorld(dictionary); // returns "hello world"
Jasmine - Spy - Test Case describe("Person", function() { it('uses the dictionary to say "hello world"', function() { var dictionary = new Dictionary; var person = new Person; spyOn(dictionary, "hello"); // replace hello function with a spy spyOn(dictionary, "world"); // replace world function with another person.sayHelloWorld(dictionary); // spy expect(dictionary.hello).toHaveBeenCalled(); // first spy expect(dictionary.world).toHaveBeenCalled(); // second spy }); });
Jasmine - Spy - Test Case - Spy returns a specific value it("can give a Spanish hello", function() { var dictionary = new Dictionary; var person = new Person; spyOn(dictionary, "hello").andReturn("bonjour"); // note this new piece var result = person.sayHelloWorld(dictionary); expect(result).toEqual("bonjour world"); });
Jasmine - Spy - Test Case - F A K E it("can call a fake function", function() { var fakeHello = function() { alert("I am a spy! Ha ha!"); return "hello"; }; var dictionary = new Dictionary(); spyOn(dictionary, "hello").andCallFake(fakeHello); dictionary.hello(); // does an alert });
Jasmine - Spy - Test Case - New Spies In the previous examples, we were building spies that replaced existing functions. It is sometimes useful to create a spy for a function that doesn’t yet exist. it("can have a spy function", function() { var person = new Person(); person.getName = jasmine.createSpy("Name spy"); person.getName(); expect(person.getName).toHaveBeenCalled(); });
Jasmine - Spy - Test Case - New Spies person.getSecretAgentName = jasmine.createSpy("Name spy") .andReturn("James Bond "); person.getRealName = jasmine.createSpy("Name spy 2") .andCallFake(function() { alert("I am also a spy! Ha ha!"); return "Evan Hahn"; });
Jasmine - Spy - Test Case - Objects var tape = jasmine.createSpyObj('tape', ['play', 'pause', 'stop', 'rewind']); It can be used like this: tape.play(); tape.rewind(10);
Back to Wizard https://github.com/Innovaccer/angular-wizard
Test Runner for Javascript. Karma is not a testing framework, nor an assertion library. Karma just launches an HTTP server, and generates the test runner HTML file you probably already know from your favourite testing framework.
Karma with Webpack https://github.com/Innovaccer/angular-wizard/blob/test-cases/karma.conf.js Running test cases https://travis-ci.org/Innovaccer/angular- wizard/builds/250516935?utm_source=github_status&utm_medium=notification
Code Coverage
Understanding Coverage // max.js function max(a, b) { return a > b ? a : b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); });
Code Coverage
Understanding Coverage // max.js function max(a, b) { if (a > b) { return a; } return b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); });
Code Coverage
Understanding Coverage // max.js function max(a, b) { if (a > b) { return a; } return b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); it('should return max', function() { expect(max(3, 2)).toEqual(3); }); });
Code Coverage Reference: http://jasonrudolph.com/blog/2008/06/10/a-brief-discussion-of-code-coverage-types/
JEST https://github.com/rantiev/template-jest-with-angular/ References: https://medium.com/powtoon-engineering/a-complete-guide- to-testing-javascript-in-2017-a217b4cd5a2a You can take a look:
Thanks !

Angular JS in 2017

  • 1.
  • 2.
    Agenda Setting up anangular app. Introduction to tools - Babel, Webpack Alternative to Gulp, Grunt & Bower. Writing Controllers, Services, Directives etc.. Testing Javascript with Jasmine. Setting up Karma with Webpack. Let’s understand code coverage.
  • 3.
    Babel is atool for transpiling (compiling) ES6/ES7 code to ECMAScript 5 code, which can be used today in any modern browser. Reference : https://kangax.github.io/compat-table/es6/
  • 4.
    Installing Babel CLI $npm install babel-cli -g $ babel example.js --out-file compiled.js babel - calling Babel example.js - the input ES6/ES7 file --out-file - the option passed to Babel for compiling a file. We can also use --out-dirfor compiling all files in a directory. The short versions of the options are -o for --out- fileand -d for --output-dir compiled.js - the output file
  • 5.
    babel-register babel-register is arequire hook, that will bind node’s require method and automatically transpile the file on the fly. $ npm install babel-register --save-dev babel-node For running some code via the command line the easiest way to integrate Babel is to use babel-node CLI, which is a replacement of node CLI. babel-node comes with babel-cli
  • 6.
    Configure Babel -.babelrc { "presets": [], "plugins": [] } Let’s start telling Babel to transpile ES6 code to ES5. npm install babel-preset-es2015 --save-dev { "presets": [es2015], "plugins": [] }
  • 7.
    Babel - UnderstandingPreset JavaScript has some proposals for new features that are not yet finalized. They are separated into 5 states (0 to 4). Look TC39 In Babel, these changes are bundled in 4 different presets: babel-preset-stage-0 babel-preset-stage-1 babel-preset-stage-2 babel-preset-stage-3 There is no babel-preset-stage-4 as it’s simply babel-preset-es2015
  • 8.
    Configure Babel -A final look npm install babel-preset-stage-2 // You can also install stages. { "presets": [“es2015”,”stage-2”], "plugins": [“undeclared-variables-check”] } We shall configure babel with webpack later. References: https://babeljs.io/docs/ http://kleopetrov.me/2016/03/18/everything-about-babel/
  • 9.
    webpack is amodule bundler. This means webpack takes modules with dependencies and emits static assets representing those modules.
  • 10.
    The state ofJavaScript modules Fear You would copy and paste a library into a vendor folder, rely on global variables, try to concat everything in the right order and still would had to deal with namespace issues. Currently, We have UMD : Universal Module Definition AMD: Asynchronous Module Definition CJS: Common JS ESM: ECMA Script Modules
  • 11.
    Let’s start Install itas dev dependency npm install webpack --save-dev There are four key parts to a basic Webpack configuration. entry - the starting point of your application loaders  -  the transformations you want to make on your code output  - where you want your compiled code to go plugins -transformations on chunks and bundles
  • 12.
    Webpack - entry webpackcreates a graph of all of your application's dependencies. The starting point of this graph is known as an entry point. It tells webpack where to start and follows the graph of dependencies to know what to bundle. It is application's entry point as the contextual root or the first file to kick off your app. module.exports = { entry: './path/to/my/entry/file.js' };
  • 13.
    Webpack - output Ittells webpack where to bundle your application. The webpack output property tells webpack how to treat bundled code. Webpack.config.js const path = require('path'); module.exports = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' } };
  • 14.
    Webpack - loaders Loadersare transformations that are applied on the source code of a module. They allow you to pre-process files as you import or “load” them. Thus, loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle front-end build steps. const config = { module: { rules: [ { test: /.(js|jsx)$/, use: 'babel-loader' } ] }, };
  • 15.
    Webpack - plugins Loadersonly execute transforms on a per-file basis, plugins are most commonly used performing actions and custom functionality on "compilations" or "chunks" of your bundled modules . // webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); const config = { plugins: [ new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
  • 16.
    Webpack - Afinal look var path = require('path'); module.exports = { entry: './foo.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'foo.bundle.js' } }; https://github.com/Innovaccer/angular-wizard/blob/test-cases/webpack.config.js
  • 18.
    Webpack should replaceyour gulp/bower build pipeline. It allows for modular imports of npm modules, plenty of which are either front-end or universal.
  • 19.
    Hot Module Replacement- HMR Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways: Retain application state which is lost during a full reload. Save valuable development time by only updating what's changed. Tweak styling faster -- almost comparable to changing styles in the browser's debugger.
  • 20.
    Webpack Dev Server Usewebpack with a development server that provides live reloading. This should be used for development only. It uses webpack-dev-middleware under the hood, which provides fast in-memory access to the webpack assets. devServer: { contentBase: './demo', stats: 'minimal' }
  • 21.
    Much More.. Watcher $ webpack-w Live reload $ node_modules/.bin/webpack-dev-server Minification & other things Plugins are here.
  • 22.
    A hello worldangular app in ES6 - app // app.js import angular from 'angular'; const app = angular.module('demo', []); export default app;
  • 23.
    A hello worldangular app in ES6 - controller / service /Providers // controller.js import app from './app.js'; class TestCtrl { constructor() { 'ngInject'; this.name = 'ayush'; this.lastname = 'sharma'; } sayHello() { console.log(`Hello ${this.name} ${this.lastname}`); } } const ctrl = app.controller('TestCtrl', TestCtrl); export default ctrl;
  • 24.
  • 25.
    TDD - TestDriven Development 1. Write test cases for a specific part of your code and these tests should fail! 2. Write your code to “fill in” the tests. Your code only serves to make all of your tests pass, and nothing more. 3. Once all of your tests pass, go back and clean up your code (this is called refactoring)
  • 26.
    TDD - TestDriven Development - Program 1. Write a program to removes all vowels from a string. Think of specifications: ● It should remove all lowercase vowels. ● It should remove all uppercase vowels. ● It shouldn’t change empty strings. ● It shouldn’t change strings with no vowels
  • 27.
    TDD - TestDriven Development - Examples • Remove all lowercase vowels: “Hello world” should become “Hll wrld”. • Remove all uppercase vowels: “Artistic Eagle” should become “rtstc gl”. • Don’t change empty strings: “” should stay “”. • Don’t change strings with no vowels: “Mhmm” should stay “Mhmm”
  • 28.
    Jasmine is abehavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests.
  • 29.
    TDD - TestDriven Development - Jasmine T E S T S U I T E | * S P E C I F I C A T I O N S | * E X P E C T A T I O N S
  • 30.
    TDD - TestDriven Development - Back to example describe("removeVowel", function () { it("should remove all lowercase vowels", function () { expect(removeVowel("Hello world")) .toEqual("Hll wrld"); }); it("should remove all uppercase vowels", function () { expect(removeVowel("Artistic Eagle")) .toEqual("rtstc gl"); }); // continue
  • 31.
    TDD - TestDriven Development - Back to example // continue it("shouldn't change empty strings", function () { expect(removeVowel("")) .toEqual(""); }); it("shouldn't change strings with no vowels", function () { expect(removeVowel("Mhmm")) .toEqual("Mhmm"); }); });
  • 32.
    TDD - TestDriven Development - Writing some code https://jsfiddle.net/ayusharma/z369j7Lj/2/
  • 33.
    Jasmine - Matchersin Depth - Equality: toEqual The following expect functions will pass: expect(true).toEqual(true); expect([1, 2, 3]).toEqual([1, 2, 3]); expect({}).toEqual({}); Here are some examples of toEqual that will fail: expect(5).toEqual(12); expect([1, 2, 3, 4]).toEqual([1, 2, 3]); expect(true).toEqual(100);
  • 34.
    Jasmine - Matchersin Depth https://jasmine.github.io/api/2.6/matchers.html
  • 35.
    Jasmine - Spy(जासूस) Spies allow us to hook into certain functions, and check whether they were called, how many times they were called, what arguments they were called with, and so on. Spying allows you to replace a part of your program with a spy. A spy can pretend to be a function or an object. Let’s take a look..
  • 36.
    Jasmine - Spy- Dictionary var Dictionary = function() {}; Dictionary.prototype.hello = function() { return "hello"; }; Dictionary.prototype.world = function() { return "world"; };
  • 37.
    Jasmine - Spy- Person var Person = function() {}; Person.prototype.sayHelloWorld = function(dict) { return dict.hello() + " " + dict.world(); }; var dictionary = new Dictionary(); var person = new Person(); person.sayHelloWorld(dictionary); // returns "hello world"
  • 38.
    Jasmine - Spy- Test Case describe("Person", function() { it('uses the dictionary to say "hello world"', function() { var dictionary = new Dictionary; var person = new Person; spyOn(dictionary, "hello"); // replace hello function with a spy spyOn(dictionary, "world"); // replace world function with another person.sayHelloWorld(dictionary); // spy expect(dictionary.hello).toHaveBeenCalled(); // first spy expect(dictionary.world).toHaveBeenCalled(); // second spy }); });
  • 39.
    Jasmine - Spy- Test Case - Spy returns a specific value it("can give a Spanish hello", function() { var dictionary = new Dictionary; var person = new Person; spyOn(dictionary, "hello").andReturn("bonjour"); // note this new piece var result = person.sayHelloWorld(dictionary); expect(result).toEqual("bonjour world"); });
  • 40.
    Jasmine - Spy- Test Case - F A K E it("can call a fake function", function() { var fakeHello = function() { alert("I am a spy! Ha ha!"); return "hello"; }; var dictionary = new Dictionary(); spyOn(dictionary, "hello").andCallFake(fakeHello); dictionary.hello(); // does an alert });
  • 41.
    Jasmine - Spy- Test Case - New Spies In the previous examples, we were building spies that replaced existing functions. It is sometimes useful to create a spy for a function that doesn’t yet exist. it("can have a spy function", function() { var person = new Person(); person.getName = jasmine.createSpy("Name spy"); person.getName(); expect(person.getName).toHaveBeenCalled(); });
  • 42.
    Jasmine - Spy- Test Case - New Spies person.getSecretAgentName = jasmine.createSpy("Name spy") .andReturn("James Bond "); person.getRealName = jasmine.createSpy("Name spy 2") .andCallFake(function() { alert("I am also a spy! Ha ha!"); return "Evan Hahn"; });
  • 43.
    Jasmine - Spy- Test Case - Objects var tape = jasmine.createSpyObj('tape', ['play', 'pause', 'stop', 'rewind']); It can be used like this: tape.play(); tape.rewind(10);
  • 44.
  • 45.
    Test Runner forJavascript. Karma is not a testing framework, nor an assertion library. Karma just launches an HTTP server, and generates the test runner HTML file you probably already know from your favourite testing framework.
  • 46.
    Karma with Webpack https://github.com/Innovaccer/angular-wizard/blob/test-cases/karma.conf.js Runningtest cases https://travis-ci.org/Innovaccer/angular- wizard/builds/250516935?utm_source=github_status&utm_medium=notification
  • 47.
  • 48.
    Understanding Coverage // max.js functionmax(a, b) { return a > b ? a : b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); });
  • 49.
  • 50.
    Understanding Coverage // max.js functionmax(a, b) { if (a > b) { return a; } return b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); });
  • 51.
  • 52.
    Understanding Coverage // max.js functionmax(a, b) { if (a > b) { return a; } return b; } export default max; // max-test.js const max = require('./max.js'); describe('max', function() { it('should return max', function() { expect(max(2, 3)).toEqual(3); }); it('should return max', function() { expect(max(3, 2)).toEqual(3); }); });
  • 53.
  • 55.
  • 56.