Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AngularJS Aplicado — QCon Rio 2014
Search
Felippe Nardi
September 25, 2014
Programming
1
200
AngularJS Aplicado — QCon Rio 2014
Construindo aplicações client-side bem testadas
Felippe Nardi
September 25, 2014
Tweet
Share
More Decks by Felippe Nardi
See All by Felippe Nardi
Trabalhando Remoto como Desenvolvedor Web
felippenardi
2
170
Other Decks in Programming
See All in Programming
Trem on Rails - Prompt Engineering com Ruby
elainenaomi
1
100
MCPとデザインシステムに立脚したデザインと実装の融合
yukukotani
1
690
go test -json そして testing.T.Attr / Kyoto.go #63
utgwkk
1
190
TanStack DB ~状態管理の新しい考え方~
bmthd
2
370
為你自己學 Python - 冷知識篇
eddie
1
310
KessokuでDIでもgoroutineを活用する / Go Connect #6
mazrean
0
120
LLMOpsのパフォーマンスを支える技術と現場で実践した改善
po3rin
8
1k
複雑なドメインに挑む.pdf
yukisakai1225
4
740
Kiroで始めるAI-DLC
kaonash
2
480
詳解!defer panic recover のしくみ / Understanding defer, panic, and recover
convto
0
210
CSC305 Summer Lecture 12
javiergs
PRO
0
130
Laravel Boost 超入門
fire_arlo
2
170
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
6k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
500
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Why Our Code Smells
bkeepers
PRO
339
57k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6.1k
Building Applications with DynamoDB
mza
96
6.6k
RailsConf 2023
tenderlove
30
1.2k
Speed Design
sergeychernyshev
32
1.1k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
570
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
Transcript
AngularJS aplicado Construindo aplicações client-side bem testadas @FelippeNardi
Objetivos ! • Elementos essenciais! • Testes: e2e e unitários
• Mindset AngularJS
Felippe Nardi Front-end Engineer e Designer
client-side web apps
client-side web apps
None
Service Controller View
Angular vai te ajudar: • Organizar o javascript • Criar
sites responsivos •Testar com facilidade
Framework Javascript
Extensão do HTML
None
<input type=“text” autofocus>
Service Controller View Directives 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 View Directives Expressions
Service Controller View Directives 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ém angular-translate github.com/angular-translate/angular-translate
Service Controller View Directives 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 View Directives 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
None
github.com/felippenardi/ mini-lero-lero
Nomeando o App var leroLeroApp = angular.module('leroLeroApp', []);! app.js
<html ng-app="leroLeroApp">! !<!-- (...) -->! </html>! Nomeando o App index.html
Carregando as frases app.js
Service app.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! });! !
Testando o Service appSpecs.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(inject(! ! ! ! ! ! ));! ! ! function(_geradorDeFrases_,! ! ! ! ! ! ! ! ! $httpBackend) {! ! ! ! ! } ! ! ! geradorDeFrases = _geradorDeFrases_;! ! ! ! httpBackend = $httpBackend;
}); ! ! ! ! ! ! ! ! !
! 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);
None
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);
None
Recapitulando • Carregar a aplicação • Injetar serviços • Usar
variáveis para armazenar os serviços
Mostrando as frases index.html
frase.gerar()
Expor objeto frases pra view app.js
Controller app.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 Controller appSpecs.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);! });
None
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>!
None
Recapitulando • Mesma estrutura básica! • Sobrescrever serviços! • Simular
promessas
Testes Unitários! prontos
Vamos para os Testes End to End!
None
None
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/hub specs: ['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);! });! });! });
None
None
None
Recapitulando • Rodar servidor selenium! • Preparar arquivo conf.js! •
Rodar protractor conf.js
Seus próximos passos:
github.com/felippenardi/mini-lero-lero
None
moourl.com/tryangular
None
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!