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
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
AI巻き込み型コードレビューのススメ
nealle
2
400
CSC307 Lecture 05
javiergs
PRO
0
500
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
Honoを使ったリモートMCPサーバでAIツールとの連携を加速させる!
tosuri13
1
180
高速開発のためのコード整理術
sutetotanuki
1
400
[KNOTS 2026登壇資料]AIで拡張‧交差する プロダクト開発のプロセス および携わるメンバーの役割
hisatake
0
290
AI時代のキャリアプラン「技術の引力」からの脱出と「問い」へのいざない / tech-gravity
minodriven
21
7.3k
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
380
コントリビューターによるDenoのすゝめ / Deno Recommendations by a Contributor
petamoriken
0
200
Raku Raku Notion 20260128
hareyakayuruyaka
0
330
CSC307 Lecture 01
javiergs
PRO
0
690
Architectural Extensions
denyspoltorak
0
290
Featured
See All Featured
Bash Introduction
62gerente
615
210k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
How to Think Like a Performance Engineer
csswizardry
28
2.4k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2k
Heart Work Chapter 1 - Part 1
lfama
PRO
5
35k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
ラッコキーワード サービス紹介資料
rakko
1
2.3M
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Navigating Team Friction
lara
192
16k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
Building AI with AI
inesmontani
PRO
1
700
Rails Girls Zürich Keynote
gr2m
96
14k
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!