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.
An alternative: JEST
2. 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.
3. 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/
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 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
7. 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
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 a module bundler.
This means webpack takes modules with dependencies
and emits static assets representing those modules.
10. 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
11. 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
12. 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'
};
13. 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'
}
};
14. 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'
}
]
},
};
15. 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;
16. 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
17.
18. 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.
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
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'
}
21. Much More..
Watcher
$ webpack -w
Live reload
$ node_modules/.bin/webpack-dev-server
Minification & other things
Plugins are here.
22. A hello world angular app in ES6 - app
// app.js
import angular from 'angular';
const app = angular.module('demo', []);
export default app;
23. 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;
25. 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)
26. 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
27. 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”
28. 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.
29. 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
30. 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
31. 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");
});
});
32. TDD - Test Driven Development - Writing some code
https://jsfiddle.net/ayusharma/z369j7Lj/2/
33. 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);
34. Jasmine - Matchers in 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..
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);
45. 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.