Qcon 2014 simplificado -...

Post on 03-Jun-2020

4 views 0 download

Transcript of Qcon 2014 simplificado -...

AngularJS aplicadoConstruindo aplicações client-side

bem testadas

@FelippeNardi

Objetivos!

• Elementos essenciais!• Testes: e2e e unitários • Mindset AngularJS

Felippe NardiFront-end Engineer e Designer

client-side web apps

client-side web apps

Service

Controller

View

Angular vai te ajudar:

• Organizar o javascript • Criar sites responsivos •Testar com facilidade

Framework Javascript

Extensão do HTML

<input type=“text” autofocus>

Service

Controller

ViewDirectives Expressions

ng-model

<input ng-model="teste">!Hello {{ teste }}!

AngularJS

Digest Loop

Iniciando a aplicação

<html ng-app>!!<!-- (...) -->!</html>!

<input ng-model="teste">Hello {{ teste }}!<span ng-hide="!teste">!!

</span>

<input ng-model="teste"><span ng-show="teste">!!

</span>Hello {{ teste }}!

Recapitulando

• Directives • {{ Expressions }} • Digest Loop

Service

Controller

ViewDirectives Expressions

Service

Controller

ViewDirectives Expressions

Filters

Filters

{{"Olá"}}!

Filters

{{"Olá"|uppercase}}!

Filters

{{"Olá"|lowercase}}!

Filters<input ng-model="busca">!!

{{users|filter:busca}}!

Recapitulando

• {{ expression | filter }} • Array • String

I18n

{{1228212|number}}!

I18n

{{12.82|currency}}!

{{1411676100000!|date}}!

I18n

Suporte pt-BR

<script src="angular.js">!<script src="angular-locale_pt-br.js">!

Todos os arquivos de locale do Angular

{{1228212|number}}!

I18n

{{12.82|currency}}!

I18n

{{1411676100000!|date}}!

I18n

Indo alémangular-translate

github.com/angular-translate/angular-translate

Service

Controller

ViewDirectives Expressions

function MyCtrl($scope){!!$scope.teste ="Olá!";!};!

Controllers

<div!ng-controller="MyCtrl">!!{{ teste }}!</div>!

function MyCtrl($scope){!!$scope.teste ="Olá!";!};!

Directives Essenciais

ng-repeat

<li ng-repeat="name in names">!!{{ name }}!</li>!

$scope.names = [!!"Antônio", "Carlos", "Souza"!];!

ng-pluralize<ng-pluralize count="names"!when="{'0':'Nenhum nome',!! '1':'Só um nome',!! 'other': '{} nomes'}">!</ng-pluralize>!

ng-pluralize<ng-pluralize count="names"!when="{'0':'Nenhum nome',!! '1':'Só um nome',!! 'other': '{} nomes'}">!</ng-pluralize>!

Recapitulando

• Controllers • $scope • ng-controller

Service

Controller

ViewDirectives Expressions

function MyCtrl( ){!!

};!

$scope$scope.teste ="World!";!

Service

$filter('uppercase')("Hello");!

{{"Hello"|uppercase}}!

Service

$http({ method: 'GET',!url: '/home' })!

XMLHttpRequest ou JSONP

.then(!!

!

);

!function() { /*...*/ },!!function() { /*...*/}

Service

Recapitulando:

• Data-binding!• Digest Loop!• Dependency Injection

Unit Tests!no AngularJS

TestRunner.html:• jasmine-all.js

• angular.js

• angular-mocks.js

• arquivos javascript

• arquivos de test

moourl.com/tryangular

2 exemplos!Service

Controller

github.com/felippenardi/mini-lero-lero

Nomeando o App

var leroLeroApp = angular.module('leroLeroApp', []);!

app.js

<html ng-app="leroLeroApp">!!<!-- (...) -->!</html>!

Nomeando o Appindex.html

Carregando as frasesapp.js

Serviceapp.js

});

leroLeroApp.factory('geradorDeFrases',!! function ($http) {!!

var promise =!! ! $http.get('frases.json')! .then(function (response) {! return response.data;! });!!

return {! get: function() {! return promise;! }! };!});

Syntax Jasmine

describe('Descrição', function() {! ! beforeEach(function() {!! ! // Roda antes de cada teste! });! ! afterEach(function() {!! ! // Roda depois de cada teste! });! ! it('Descrição do teste', function() {!

Testando o ServiceappSpecs.js

});

describe('Service: Gerador De Frases', function() {!!

!

!

!

!

!

!

!

!

!

!

!

! var geradorDeFrases,!! ! ! httpBackend,!! ! ! frases; beforeEach(module('leroLeroApp'));!

! beforeEach(inject(!!

!

!

!

!

));!

! ! function(_geradorDeFrases_,!! ! ! ! ! ! ! ! $httpBackend) {!!

!

! ! }

! ! ! geradorDeFrases = _geradorDeFrases_;!! ! ! httpBackend = $httpBackend;

});

describe('Service: Gerador De Frases', function() {!!

!

!

!

!

!

!

!

!

!

!

!

! var geradorDeFrases,!! ! ! httpBackend,!! ! ! frases; beforeEach(module('leroLeroApp'));!

! beforeEach(inject(!!

!

!

!

!

));!

! ! function(_geradorDeFrases_,!! ! ! ! ! ! ! ! $httpBackend) {!!

!

! ! }

! ! ! geradorDeFrases = _geradorDeFrases_;!! ! ! httpBackend = $httpBackend;

});

afteEach(function() {!! ! httpBackend! .verifyNoOutstandingExpectation();! httpBackend! .verifyNoOutstandingRequest();! });

!

!

!

!

!

!

!

!

!

beforeEach(module('leroLeroApp'));!

! beforeEach(inject(!!

!

!

!

!

));!

! ! function(_geradorDeFrases_,!! ! ! ! ! ! ! ! $httpBackend) {!!

!

! ! }

! ! ! geradorDeFrases = _geradorDeFrases_;!! ! ! httpBackend = $httpBackend;

});

!

!

!

!

!

!

!

!

!

!

beforeEach(module('leroLeroApp'));!

! beforeEach(inject(!!

!

!

!

!

));!

! ! function(_geradorDeFrases_,!! ! ! ! ! ! ! ! $httpBackend) {!!

!

! ! }

! ! ! geradorDeFrases = _geradorDeFrases_;!! ! ! httpBackend = $httpBackend;

afteEach(function() {!! ! httpBackend! .verifyNoOutstandingExpectation();! httpBackend! .verifyNoOutstandingRequest();! });

});

it('fornece frases', function() {!!

!

!

!

!

!

!

!

!

!

!

!

});

httpBackend! .expectGET('frases.json').respond([! "Frase 1", "Frase 2", "Frase 3"! ]);

geradorDeFrases.get()! .then(function(response) {! frases = response;! });

expect(frases)! .toEqual(jasmine.any(Array));expect(frases.length).toBe(3);

});

it('fornece frases', function() {!!

!

!

!

!

!

!

!

!

!

!

!

});

httpBackend! .expectGET('frases.json').respond([! "Frase 1", "Frase 2", "Frase 3"! ]);

geradorDeFrases.get()! .then(function(response) {! frases = response;! });httpBackend.flush();expect(frases)! .toEqual(jasmine.any(Array));expect(frases.length).toBe(3);

Recapitulando

• Carregar a aplicação • Injetar serviços • Usar variáveis para armazenar os serviços

Mostrando as frasesindex.html

frase.gerar()

Expor objeto frases pra view

app.js

Controllerapp.js

});

leroLeroApp.controller('MainCtrl',!! function ($scope, geradorDeFrases) {! !! ! var i = 0, frases;! geradorDeFrases.get()! .then(function(response){! frases = response;! $scope.frase.gerar();! });! $scope.frase = {! gerar: function() {! $scope.frase.atual = frases[i];! i < frases.length - 1? i++ : i = 0;! }! };!});

Testando o ControllerappSpecs.js

});

describe('Controller: MainCtrl',!function() {! var scope, MainCtrl, geradorMock, q;!!

beforeEach(module('leroLeroApp'));!!

beforeEach(inject(! function($controller, $rootScope, $q) {! q = $q;! scope = $rootScope.$new();! ! MainCtrl = $controller('MainCtrl', {! $scope: scope,! geradorDeFrases: geradorMock! });

});

!

beforeEach(inject(! function($controller, $rootScope, $q) {! q = $q;! scope = $rootScope.$new();! ! MainCtrl = $controller('MainCtrl', {! $scope: scope,! geradorDeFrases: geradorMock! });!

scope.$apply();! }! ));!

});

));! geradorMock = {! get: function() {! var frases = q.defer();! frases.resolve(["A","B","C"]);! return frases.promise;! }! };!!

it('começa com uma frase', function() {! expect(scope.frase.atual)! .toEqual(jasmine.any(String));! });

});

));! };!!

it('começa com uma frase', function() {! expect(scope.frase.atual)! .toEqual(jasmine.any(String));! });!

it('gera nova a frase', function() {! var primeiraFrase = scope.frase.atual;! ! scope.frase.gerar();! ! var segundaFrase = scope.frase.atual;! ! expect(primeiraFrase)! .not.toEqual(segundaFrase);! });

});

it('gera infinitas frases', function() {! var i = 4;! do { scope.frase.gerar() } while (--i);!!

expect(scope.frase.atual!! ! .toBeDefined();! });!});!

! scope.frase.gerar();! ! var segundaFrase = scope.frase.atual;! ! expect(primeiraFrase)! .not.toEqual(segundaFrase);! });

frase.gerar()

});

<div ng-controller="MainCtrl">!!

<h1>Lero Lero</h1>!!

<a ng-click=" ">! Gerar frase! </a>!!

<blockquote>! ! </blockquote>!!

</div>!

<div ng-controller="MainCtrl">!!

<h1>Lero Lero</h1>!!

<a ng-click="frase.gerar()">! Gerar frase! </a>!!

<blockquote>! {{ frase.atual }}! </blockquote>!!

</div>!

Recapitulando

• Mesma estrutura básica!• Sobrescrever serviços!• Simular promessas

Testes Unitários!prontos

Vamos para os Testes End to End!

1 teste:!gera frase

Setup do Protractor$ npm install -g protractor

$ webdriver-manager update

$ webdriver-manager start

$ webdriver-manager start

http://localhost:4444/wd/hub

Arquivo de configuração

// conf.js!exports.config = {! seleniumAddress:! ' ',! !}!

$ protractor conf.js

http://localhost:4444/wd/hubspecs: ['spec.js']!

beforeEach(function() {! browser.get('http://localhost:8000/');!});!!describe('Frase', function() {!! it('gera frase', function() {! var frase1,! frase2;!! element(by.binding('frase.atual')).getText()! .then(function(frase) {! frase1 = frase;! });!! element(by.id('gerar-frase')).click();

! it('gera frase', function() {! var frase1,! frase2;!! element(by.binding('frase.atual')).getText()! .then(function(frase) {! frase1 = frase;! });!! element(by.id('gerar-frase')).click();

element(by.binding('frase.atual')).getText()! .then(function(frase) {! frase2 = frase;! expect(frase1).not.toBe(frase2);! });! });!});

Recapitulando

• Rodar servidor selenium!• Preparar arquivo conf.js!• Rodar protractor conf.js

Seus próximos passos:

github.com/felippenardi/mini-lero-lero

moourl.com/tryangular

moourl.com/tryangular

angular.github.io/protractor/

angular.github.io/protractor/

jasmine.github.io

jasmine.github.io

moourl.com/angularjs

youtube: A Tiny Piece of AngularJS

egghead.io

@felippenardi

Obrigado!