ES6 & AngularJs

ES6 Main features
- OO approach based on classes
ES6 Main features
- OO approach based on classes
ES6 Main features
- Module system
- OO approach based on classes
ES6 Main features
- Module system
- let & const hoisting
- OO approach based on classes
ES6 Main features
- Module system
- let & const hoisting
- Native promises
- OO approach based on classes
ES6 Main features
- Module system
- let & const hoisting
- Native promises
- Map & Set
- OO approach based on classes
ES6 Main features
- Module system
- let & const hoisting
- Native promises
- Map & Set
- Tail call optimizations
ES6 Syntactic sugar
- Arrow functions
ES6 Syntactic sugar
- Arrow functions
ES6 Syntactic sugar
- String interpolation
- Arrow functions
ES6 Syntactic sugar
- String interpolation
- Destructuring
- Arrow functions
ES6 Syntactic sugar
- String interpolation
- Destructuring
- Default parameter values
- Arrow functions
ES6 Syntactic sugar
- String interpolation
- Destructuring
- Default parameter values
- Spread operator
- Arrow functions
ES6 Syntactic sugar
- String interpolation
- Destructuring
- Default parameter values
- Spread operator
- And much more...
Are browsers prepared?

Do we have a solution?














Nobody said it was easy!
Let's see an example

TODO Controller
class TodoController {
/* @ngInject */
constructor(todoService, log) {
this.todoService = todoService;
this.log = log;
this.title = 'todos';
this.helpText = 'What needs to be done?';
this.newTodo = {};
}
loadTodos() {
return this.todoService.loadTodos().catch(() => this.log.error('Error loading todos'));
}
add() {
return this.todoService.add(this.newTodo).then(() => this._resetNewTodo());
}
toggleCompleted(todo) {
return this.todoService.toggleCompleted(todo);
}
get todos() {
return this.todoService.todos;
}
_resetNewTodo() {
this.newTodo = {};
}
}
export default TodoController;
TODO Service
import _ from 'lodash';
import Todo from '~/src/app/model/todo';
const TODO = 'todo';
class TodoService {
/* @ngInject */
constructor(restService) {
this.restService = restService;
this.todos = [];
}
loadTodos() {
return this.restService.list(TODO).then((todos) => this._setTodos(todos));
}
add(newTodo) {
const todo = new Todo(newTodo);
this.todos = _.union(this.todos, [todo]);
return this.restService.add(TODO, todo);
}
_setTodos(todos) {
this.todos = _.map(todos, (todo) => new Todo(todo));
}
}
export default TodoService;
TODO Domain model
class Todo {
constructor(args) {
this.id = args.id;
this.content = args.content;
this.completed = args.completed;
}
toggleCompleted() {
return new Todo({
id: this.id,
content: this.content,
completed: !this.completed
});
}
}
export default Todo;
Unit tests
import TodoService from '~/src/app/components/todo-service';
import Todo from '~/src/app/model/todo';
describe('Todo service', () => {
let todoService, restService, rootScope, q;
beforeEach(angular.mock.module('todo-app'));
beforeEach(angular.mock.inject(($injector, $rootScope, $q) => {
restService = $injector.get('restService');
todoService = new TodoService(restService);
rootScope = $rootScope;
q = $q;
}));
it('loads the list of todos', () => {
given:
const todo1 = { id: 1, content: 'Buy milk', completed: true };
const todo2 = { id: 2, content: 'Buy beer', completed: true };
const response = q.when([todo1, todo2]);
const loadTodosAction = sinon.stub(restService, 'list').returns(response);
when:
todoService.loadTodos();
then:
chai.expect(loadTodosAction).to.have.been.calledWith('todo');
and:
rootScope.$apply();
then:
chai.expect(todoService.todos).to.be.deep.equal([new Todo(todo1), new Todo(todo2)]);
});
});
Integration tests
import _ from 'lodash';
import fixtures from '~/src/fixtures/fixtures';
import httpMock from '~/spec/integration/http-mock';
import Todo from '~/src/app/model/todo';
describe('Todo app controller', () => {
let controller;
const todos = _.map(fixtures.todos, (todo) => new Todo(todo));
beforeEach(angular.mock.module('todo-app'));
beforeEach(httpMock.init());
afterEach(httpMock.reset());
beforeEach(angular.mock.inject(($controller) => {
controller = $controller('TodoController');
}));
it('deletes a todo', (done) => {
controller.loadTodos()
.then(() => controller.delete(_.first(controller.todos)))
.then(() => {
chai.expect(controller.todos).to.be.deep.equal(_.tail(todos));
done();
}
);
});
});
Browser tests
class MainPage {
constructor() {
this.title = element(by.css('h1'));
this.todos = element.all(by.repeater('todo in todoController.todos'));
}
}
export default MainPage;
import Main from '~/spec/e2e/main.po';
describe('The main view', () => {
const page = new Main();
browser.get('/index.html');
it('displays the list of todos', () => {
expect(page.title.getText()).toBe('todos');
expect(page.todos.count()).toBe(2);
});
});
Coverage test report

Conclusions?
http://www.kenfos.co.uk/tdd-es6-angularjs-part-i-of-ii/
References
http://www.kenfos.co.uk/tdd-es6-angularjs-part-ii-of-ii/
http://www.github.com/doktor500
QA?
es6-angularjs
By David Molinero
es6-angularjs
- 497