2.droppdf.com2.droppdf.com/files/6uxtx/angularjs-test-driven-development.pdf · table of contents...

288
www.it-ebooks.info

Upload: others

Post on 22-May-2020

10 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

www.it-ebooks.info

Page 2: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AngularJSTest-drivenDevelopment

www.it-ebooks.info

Page 3: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TableofContents

AngularJSTest-drivenDevelopment

Credits

AbouttheAuthor

AbouttheReviewers

www.PacktPub.com

Supportfiles,eBooks,discountoffers,andmore

Whysubscribe?

FreeaccessforPacktaccountholders

Preface

Whatthisbookcovers

Whothisbookisfor

Conventions

Readerfeedback

Customersupport

Downloadingtheexamplecode

Errata

Piracy

Questions

1.IntroductiontoTest-drivenDevelopment

AnoverviewofTDD

FundamentalsofTDD

Measuringsuccess

Breakingdownthesteps

Measuretwicecutonce

Divingin

Settingupthetest

Creatingadevelopmentto-dolist

Testfirst

Makingitrun

www.it-ebooks.info

Page 4: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Makingitbetter

Testingtechniques

Testingwithaframework

TestingdoubleswithJasminespies

Stubbingareturnvalue

Testingarguments

Refactoring

Buildingwithabuilder

Self-testquestions

Summary

2.TheKarmaWay

JavaScripttestingtools

Karma

Protractor

JavaScripttestingframeworks

Jasmine

Selenium

Mocha

BirthofKarma

TheKarmadifference

ImportanceofcombiningKarmawithAngularJS

InstallingKarma

Installationprerequisites

ConfiguringKarma

CustomizingKarma’sconfiguration

ConfirmingKarma’sinstallationandconfiguration

Commoninstallation/configurationissues

TestingwithKarma

ConfirmingtheKarmainstallation

UsingKarmawithAngularJS

GettingAngularJS

www.it-ebooks.info

Page 5: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Bower

Bowerinstallation

InstallingAngularJS

InstallingAngularmocks

InitializingKarma

TestingwithAngularJSandKarma

Adevelopmentto-dolist

Testingalistofitems

Testfirst

Assemble,Act,andAssert(3A’s)

Makeitrun

Makeitbetter

Addingafunctiontothecontroller

Testfirst

Assemble,Act,andAssert(3A’s)

Makeitrun

Makeitbetter

Self-testquestions

Summary

3.End-to-endTestingwithProtractor

AnoverviewofProtractor

OriginsofProtractor

Endoflife

ThebirthofProtractor

LifewithoutProtractor

Protractorinstallation

Installationprerequisites

InstallingProtractor

InstallingWebDriverforChrome

Customizingconfiguration

Confirminginstallationandconfiguration

www.it-ebooks.info

Page 6: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Commoninstallation/configurationissues

HelloProtractor

TDDend-to-end

Thepre-setup

Thesetup

Testfirst

Installingthetestwebserver

ConfiguringProtractor

Gettingdowntobusiness

Specification

Thedevelopmentto-dolist

Testfirst

Assemble,Act,Assert(3A’s)

Runningthetest

Makeitrun

Makeitbetter

Cleaningupthegaps

Asyncmagic

Loadingapagebeforetestexecution

Assertiononelementsthatgetloadedinpromises

TDDwithProtractor

Self-testquestions

Summary

4.TheFirstStep

Preparingtheapplication’sspecification

Settinguptheproject

Settingupthedirectory

SettingupProtractor

SettingupKarma

Settinguphttp-server

Top-downorbottom-upapproach

www.it-ebooks.info

Page 7: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Testingacontroller

Asimplecontrollertestsetup

Initializingthescope

Bringonthecomments

Testfirst

Assemble

Act

Assert

Makeitrun

Addingthemodule

Addingtheinput

Controller

Makeitpass

Makeitbetter

ImplementingtheSubmitbutton

ConfiguringKarma

Testfirst

Assemble

Act

Assert

Makeitrun

Makeitbetter

Backupthetestchain

Bindtheinput

Onwardsandupwards

Testfirst

Assemble

Act

Assert

Makeitrun

Fixingtheunittests

www.it-ebooks.info

Page 8: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Makeitbetter

Couplingofthetest

Self-testquestions

Summary

5.FlipFlop

Fundamentals

Protractorlocators

CSSlocators

Buttonandlinklocators

Angularlocators

URLlocationreferences

Creatinganewproject

SettingupheadlessbrowsertestingforKarma

Preconfiguration

Configuration

Walk-throughofAngularroutes

SettingupAngularJSroutes

Definingdirections

ConfiguringngRoute

Definingtheroutecontrollers

Definingtherouteviews

Assemblingtheflipfloptest

Makingtheviewsflip

Assertingaflip

Makingflipfloprun

Makingflipflopbetter

SearchingtheTDDway

Decidingontheapproach

Walk-throughofsearchquery

Thesearchquerytest

ThesearchqueryHTMLpage

www.it-ebooks.info

Page 9: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Thesearchapplication

Showmesomeresults!

Creatingthesearchresultroutes

Testingthesearchresults

Assemblingthesearchresulttest

Selectingasearchresult

Confirmingasearchresult

Makingthesearchresulttestrun

Creatingalocation-awaretest

Makingthesearchresultbetter

ConfirmingtherouteID

SettinguptherouteIDunittest

ConfirmingtheID

Makingtherouteparameter’stestrun

Self-testquestions

Summary

6.TellingtheWorld

Beforetheplunge

Karmaconfiguration

Filewatching

Usingabottom-upapproach

Services

Publishingandsubscribingmessages

Emitting

Testingemit

Testingbroadcast

Testingbroadcast

Publishingandsubscribing–thegoodandbad

Thegood

Communicatingthroughevents

Reducingcoupling

www.it-ebooks.info

Page 10: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Harnessingthepowerofevents

Theplan

Rebranding

Seeingrecentlyvieweditems

Testfirst

AssemblingSearchController

Selectingaproduct

Expectingeventstobepublished

Makingthesearchcontrollerrun

Recentlyviewedunittest

Testfirst

AssemblingRecentlyViewedController

Invokingarecentlyvieweditem

ConfirmingRecentlyViewedController

MakingRecentlyViewedControllerrun

End-to-endtesting

Testfirst

Assemblingtherecentlyviewedend-to-endtest

Selectingasearchresult

Confirmingrecentlyvieweditems

MakingtherecentlyViewedItemstestpass

Makingrecentlyvieweditemsbetter

Creatingaproductcart

Publishertestfirst

AssemblingsearchDetailController

Invokingthesavingofaproduct

Confirmingthesaveevent

MakingthesaveProducttestpass

Testforthesubscriberfirst

Assemblingtheproductcarttest

Invokingasavedcartevent

www.it-ebooks.info

Page 11: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Confirmingthesavedcart

Makingthecartcontrollertestrun

End-to-endtesting

Assemblingthecart’send-to-endtest

Invokingasavetocartaction

Confirmingproductshavebeensaved

Makingthecart’send-to-endtestpass

Self-testquestions

Summary

7.GiveMeSomeData

REST–thelanguageoftheWeb

GettingstartedwithREST

Testingasynchronouscalls

CreatingasynchronouscallsinKarma

CreatingasynchronouscallsinProtractor

MakingRESTrequestsusingAngularJS

TestingwithAngularJSREST

Testingtheproductservice

Testing$httpwithKarma

MockingrequestswithProtractor

DisplayingproductswithREST

Unittestingproductrequests

Settinguptheproject

Karmaconfiguration

UsinganAPIbuilderpattern

Theproductdataservice

Theproductdatacontroller

Assemblingtheproductcontrollertest

Gettingproducts

Assertingproductdataresults

Makingtheproductdatatestsrun

www.it-ebooks.info

Page 12: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Testingmiddle-to-end

Testfirst

Assemblingtheproducttest

Gettingproducts

Expectingproductdataresults

Makingtheproductdatarun

Testingend-to-end

Gettingtheproductdata

Self-testquestions

Summary

A.IntegratingSeleniumServerwithProtractor

Installation

Protractorconfiguration

RunningSelenium

Letitrun

Testfirst

Assemble

Assert

Makeitrun

Summary

B.AutomatingKarmaUnitTestingonCommit

GitHub

Testsetup

Testscripts

Settingthehook

Creatingthehook

AddingaTravisconfigurationfile

References

C.Answers

Chapter1,IntroductiontoTest-drivenDevelopment

Chapter2,TheKarmaWay

www.it-ebooks.info

Page 13: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter3,End-to-endTestingwithProtractor

Chapter4,TheFirstStep

Chapter5,FlipFlop

Chapter6,TellingtheWorld

Chapter7,GiveMeSomeData

Index

www.it-ebooks.info

Page 14: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AngularJSTest-drivenDevelopment

www.it-ebooks.info

Page 15: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AngularJSTest-drivenDevelopmentCopyright©2015PacktPublishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:January2015

Productionreference:1230115

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

BirminghamB32PB,UK.

ISBN978-1-78439-883-5

www.packtpub.com

www.it-ebooks.info

Page 16: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreditsAuthor

TimChaplin

Reviewers

Md.ZiaulHaq

NiveJayasekar

TimPei

AndiSmith

CommissioningEditor

PramilaBalan

AcquisitionEditor

ReshmaRaman

ContentDevelopmentEditor

ManasiPandire

TechnicalEditor

MadhunikitaSunilChindarkar

CopyEditors

GladsonMonteiro

AdithiShetty

StutiSrivastava

ProjectCoordinator

LeenaPurkait

Proofreaders

SimranBhogal

MariaGould

AmeeshaGreen

PaulHindle

Indexer

HemanginiBari

ProductionCoordinator

www.it-ebooks.info

Page 17: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AparnaBhagat

CoverWork

AparnaBhagat

www.it-ebooks.info

Page 18: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AbouttheAuthorTimChaplinlivesandbreathessoftwaresolutionsandinnovations.Duringtheday,heworkswithFortune100enterpriseapplications,andintheevening,heperfectshiscraftbycontributingtoanddistributingopensourcesoftware,writing,andconstantlylookingforwaystoincreasehisknowledgeoftechnologyandtheworld.Atanearlyage,Timbegandevelopingsoftwareandhasbeenhookedonitsince.TimisanestablishedconferencespeakerwhohasextensiveexperienceindevelopingandleadingAngularJSprojects.HehasawidebackgroundofJavaScript,C#,Java,andC++languages.Timspecializesinleadingcodequalityandtestingthroughoutallhisapplications.AfterattendingCaliforniaStateUniversity,Chico,hehasgoneontoworkinShanghai,LosAngeles,andLondon.

Iwouldliketothankmywife,Pierra,foralwaysmakingmethinkanddreambigger.Iwouldalsoliketothankmyfamilyfortheirconstantloveandsupport.Pops,thisone’sforyoubabe.

www.it-ebooks.info

Page 19: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AbouttheReviewersMd.ZiaulHaqisaseniorsoftwareengineerfromDhaka,Bangladesh,whohasbeenworkingwiththeoDeskcoreplatformdevelopmentteamasaseniorJavaScriptdevelopersince2011.Helikestoworkmostlyonthefrontend,thoughheisafull-stackdeveloper.JavaScriptishispassionandhelikestocodeinitalldaylong.Heiswellknownasjquerygeekinthewebcommunity.

Md.Ziaulstartedhiscareerin2005asasoftwaredeveloper.HehasworkexperiencewithUNICEFlocallyandinternationally,whereheworkedwithUNICEF’swebCMS.Heiscurrentlypursuingamaster’sdegreeincomputersciencefromUnitedInternationalUniversity,Dhaka,Bangladesh.

Iwouldliketothankmywife,Richi,andmynewbornson,Arabi,whoismyinspiration.

NiveJayasekarstartedprogramminginhighschool.Inherlastyearofhighschool,shewon$10,500ataHackathonforbuildingamobileartificial-intelligenceapp.ShehasinternedatFacebookandLinkedIn,andwillsoongraduatefromCarnegieMellonUniversitywithadegreeincomputerscienceandaminorinmachinelearning.Sheisalwaysinterestedinbuildinggame-changingproducts.Shehas5yearsofexperiencebuildingwebandmobileapplicationsusingPython,AngularJS,Java,andObjectiveC.

I’dliketothankthepeopleatPacktPublishing,LeenaPurkaitandKirtiPatil,fortheirhelpinproducingthisbook.

TimPieisacomputerscienceandbusinessadministrationdoubledegreestudentattheUniversityofWaterloo,Ontario.Hehasgainedawiderangeoftechnicalskillsthroughpastprojectsandinternships,includingcloudcomputing,datamining,andfullstackwebdevelopment.Tim’scurrenttechnicalinterestisfocusingonbuildingwebapplicationsusingmodernwebtechnologies,specificallyHTML5andwebcomponents.

I’dliketothankmyparentsfortheirconstantsupportofmypursuits,whileprovidingmegreatadvicealongtheway.

AndiSmith(@andismith)isaseniorarchitectwhospecializesinfrontendsolutionsatideasandinnovationagency,AKQA.

Andihasover15yearsofexperiencebuildingfortheWebandhasworkedwithclientssuchasNike,Ubisoft,Sainsburys,Barclays,Heineken,andMINI.HehasalsocreatedanumberofopensourcepluginsandsitessuchasGruntResponsiveImages(http://www.andismith.com/grunt-responsive-images/)andSecretsoftheBrowserDeveloperTools(http://devtoolsecrets.com/).

Andimaintainsablogfocusedonfrontenddevelopmentathttp://www.andismith.com/.

Iwouldliketothankmywife,Amy,forallherloveandsupport.

www.it-ebooks.info

Page 20: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

www.PacktPub.com

www.it-ebooks.info

Page 21: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www2.packtpub.com/books/subscription/packtlib

DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.

www.it-ebooks.info

Page 22: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

www.it-ebooks.info

Page 23: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

www.it-ebooks.info

Page 24: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

PrefaceThebookwillprovidethereaderwithacompleteguidetothetest-drivendevelopment(TDD)approachforAngularJS.Itwillprovidestep-by-step,clearexamplestocontinuallyreinforceTDDbestpractices.ThebookwilllookatbothunittestingwithKarmaandend-to-endtestingwithProtractor.Itwillnotonlyfocusonhowtousethetools,butalsoonunderstandingthereasontheywerebuilt,andwhytheyshouldbeused.Throughout,therewillbefocusonwhen,where,andhowtousethesetools,constantlyreinforcingtheprinciplesoftheTDDlifecycle(test,execute,refactor).

www.it-ebooks.info

Page 25: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

WhatthisbookcoversThisbookisbasicallysplitintotwoparts.TheinitialchaptersfocusontheTDDlifecycle,andhowKarmaandProtractorfitintothelifecycleanddevelopmentofanAngularJSapplication.Asweproceed,you’llgetastep-by-stepapproachtoAngularJSTDDusingKarmaandProtractor.EachofthechaptersbuildsuponthepreviousoneandintroduceshowtotestseveraldifferentAngularJScomponents.

Chapter1,IntroductiontoTest-drivenDevelopment,isanintroductiontotheconceptsofTDDandtestingtechniques.

Chapter2,TheKarmaWay,explorestheoriginsofKarmaandwhyitisanessentialtoolforanyAngularJSproject.

Chapter3,End-to-endTestingwithProtractor,introducesthesimplicityofProtractor,anend-to-endtestingtoolbuiltspecificallyforAngularJS.

Chapter4,TheFirstSteps,coverstheTDDjourneyandshowsthefundamentalsandtoolsinaction.

Chapter5,FlipFlop,expandstoincludetestingformultiplecontrollers,partialviews,locationreferences,CSS,andHTMLelementbuildingontheinitialfoundationalaspectslearnedinthepreviouschapter.

Chapter6,TellingtheWorld,divesintocommunicatingacrosscontrollers,andtestingservicesandbroadcasting.

Chapter7,GiveMeSomeData,divesintohowtoapplyseveraloftheconceptsshownpreviously,andextendthemtopulldatausinganexternalAPI.

AppendixA,IntegratingSeleniumServerwithProtractor,walksthroughsettingupandconfiguringProtractortouseastandaloneSeleniumserver.

AppendixB,AutomatingKarmaUnitTestingonCommit,covershowtosetupTravisCI,aplatformforcontinuousintegration,andsettingupKarmatotestyourapplication.

www.it-ebooks.info

Page 26: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

WhothisbookisforThisbookisforthedeveloperwhowantstogobeyondthebasictutorials,andwantstotaketheplungeintoAngularJSdevelopment.ThisbookisforthedeveloperwhohasexperiencewithAngularJSandhaswalkedthroughthebasictutorialsbutwantstounderstandthewidercontextofwhen,why,andhowtoapplytestingtechniquesandbestpracticestocreatequality-cleancode.Togetthemostoutofthisbook,itispreferredthatthereaderhasbasicunderstandingofHTML,JavaScript,andAngularJS.

www.it-ebooks.info

Page 27: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ConventionsInthisbook,youwillfindanumberofstylesoftextthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Createawebpageandimportcalculator.jsfortesting.”

Ablockofcodeissetasfollows:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

<scriptsrc="calculator.js"></script>

</body>

</html>

Anycommand-lineinputoroutputiswrittenasfollows:

$nodecalculator.js

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,inmenusordialogboxesforexample,appearinthetextlikethis:“Traditionally,testswererunbyhavingtomanuallylaunchabrowserandcheckforresultsbycontinuallyhittingtheRefreshbutton.”

NoteWarningsorimportantnotesappearinaboxlikethis.

TipTipsandtricksappearlikethis.

www.it-ebooks.info

Page 28: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

www.it-ebooks.info

Page 29: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

www.it-ebooks.info

Page 30: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

www.it-ebooks.info

Page 31: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

www.it-ebooks.info

Page 32: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

PiracyPiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucomeacrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.

www.it-ebooks.info

Page 33: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

QuestionsYoucancontactusat<[email protected]>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.

www.it-ebooks.info

Page 34: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter1.IntroductiontoTest-drivenDevelopmentAngularJSisattheforefrontofclient-sideJavaScripttesting.EveryAngularJStutorialincludesanaccompanyingtest,andeventtestmodulesarepartofthecoreAngularJSpackage.TheAngularteamisfocusedonmakingtestingfundamentaltowebdevelopment.

Thischapterintroducesyoutothefundamentalsoftest-drivendevelopmentwithAngularJSincluding:

Anoverviewoftest-drivendevelopment(TDD)TheTDDlifecycle:testfirst,makeitrun,makeitbetterCommontestingtechniques

www.it-ebooks.info

Page 35: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AnoverviewofTDDTDDisnotusedonlytodevelopsoftware.Thefundamentalprinciplescanbeseeninmanyindustries.ThissectionwillexplorethefundamentalsofTDDandhowtheyareappliedbyatailor.

www.it-ebooks.info

Page 36: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

FundamentalsofTDDKnowwhattocodebeforeyoucode.Thismaysoundcliché,butthisisessentiallywhatTDDgivesyou.TDDbeginsbydefiningexpectations,thenmakesyoumeettheexpectations,andfinallyforcesyoutorefinethechangesaftertheexpectationshavebeenmet.

HereareacoupleofclearbenefitsofusingTDD:

Knowingbeforeyoucode:Atestprovidesaclearvisionofwhatcodeneedstodoinordertobesuccessful.Settinguptestsfirstallowsfocusononlycomponentsthathavebeendefinedintests.Confidenceinrefactoring:Refactoringinvolvesmoving,fixing,andchangingaproject.Testsprotectthecorelogicfromrefactoringbyensuringthatthelogicbehavesindependentlyofthecodestructure.Documentation:Testsdefineexpectationsthataparticularobjectorfunctionmustmeet.Theexpectationactsasacontract,andcanbeusedtoseehowamethodshouldorcanbeused.Thismakesthecodereadableandeasiertounderstand.

www.it-ebooks.info

Page 37: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MeasuringsuccessTDDisnotjustasoftwaredevelopmentpractice.Thefundamentalprinciplesaresharedbyothercraftsmenaswell.Oneofthesecraftsmenisatailor,whosesuccessdependsonprecisemeasurementsandcarefulplanning.

BreakingdownthestepsHerearethehigh-levelstepsatailortakestomakeasuit:

1. Testfirst:

DeterminingthemeasurementsforthesuitHavingthecustomerdeterminethestyleandmaterialtheywantfortheirsuitMeasuringthecustomer’sarms,shoulders,torso,waist,andlegs

2. Makingthecuts:

MeasuringthefabricandcutSelectingthefabricbasedonthedesiredstyleMeasuringthefabricbasedonthecustomer’swaistandlegsCuttingthefabricbasedonthemeasurements

3. Refactoring:

Comparingtheresultingproducttotheexpectedstyle,reviewing,andmakingchangesComparingthecutandlooktothecustomer’sdesiredstyleMakingadjustmentstomeetthedesiredstyle

4. Repeating:

Testfirst:DeterminingthemeasurementsforthepantsMakingthecuts:MeasuringthefabricandmakingthecutsRefactor:Makingchangesbasedonthereviews

TheprecedingstepsareanexampleofaTDDapproach.Themeasurementsmustbetakenbeforethetailorcanstartcuttinguptherawmaterial.Imagineforamomentifthetailordidn’tuseatest-drivenapproachanddidn’tuseameasuringtape(testingtool).Itwouldberidiculousifthetailorstartedcuttingbeforemeasuring.

Asadeveloper,doyou“cutbeforemeasuring”?Wouldyoutrustatailorwithoutameasuringtape?Howwouldyoufeelaboutadeveloperwhodoesn’ttest?

MeasuretwicecutonceThetailoralwaysstartswithmeasurements.Whatwouldhappenifthetailormadecutsbeforemeasuring?Whatwouldhappenifthefabricwascuttooshort?Howmuchextratimewouldgointothetailoring?Measuretwice,cutonce.

Softwaredeveloperscanchoosefromanendlessamountofapproachestousebefore

www.it-ebooks.info

Page 38: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

startingdeveloping.Onecommonapproachistoworkoffaspecification.Adocumentedapproachmayhelpindefiningwhatneedstobebuilt;however,withouttangiblecriteriaforhowtomeetaspecification,theactualapplicationthatgetsdevelopedmaybecompletelydifferentthanthespecification.WithaTDDapproach(testfirst,makeitrun,andmakeitbetter),everystageoftheprocessverifiesthattheresultmeetsthespecification.Thinkabouthowatailorcontinuestouseameasuringtapetoverifythesuitthroughouttheprocess.

TDDembodiesatest-firstmethodology.TDDgivesdeveloperstheabilitytostartwithacleargoalandwritecodethatwilldirectlymeetaspecification.Developlikeaprofessionalandfollowthepracticesthatwillhelpyouwritequalitysoftware.

www.it-ebooks.info

Page 39: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

DivinginItistimetodiveintosomeactualcode.Thiswalk-throughwilltakeyouthroughaddingthemultiplicationfunctionalitytoacalculator.RemembertheTDDlifecycle:testfirst,makeitrun,andmakeitbetter.

SettingupthetestTheinitialcalculatorisinafilecalledcalculator.jsandisinitializedasanobjectasfollows:

varcalculator={};

ThetestwillberunthroughawebbrowserusingabasicHTMLpage.Createawebpageandimportcalculator.jstotestit.SavethewebpageastestRunner.html.Torunthetest,openabrowserandruntestRunner.html.HereisthecodefortestRunner.html:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

<scriptsrc="calculator.js"></script>

</body>

</html>

Nowthattheprojectissetup,thenextstepistocreatethedevelopmentto-dolist.

Creatingadevelopmentto-dolistAdevelopmentto-dolisthelpsorganizeandfocusyourtasks.Italsoprovidesaplacetowritedownideasduringthedevelopmentprocess.

Hereistheinitialstepforcreatingadevelopmentto-dolist:

Addmultiplicationfunctionality:3*3=9

Theprecedinglistdescribeswhatneedstobedone.Italsoprovidesaclearexampleofhowtoverifymultiplication:3*3=9.

TestfirstAlthoughyoucanwritethemultiplicationfunctionquickly,rememberthatoncethehabitofTDDissetinplace,itwillbejustasquicktowritethetestandcode.Herearethestepsforthefirsttest:

1. Opencalculator.js.2. Createanewfunctiontotestmultiplying3*3:

functionmultipleTest1(){

//Test

www.it-ebooks.info

Page 40: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

varresult=calculator.multiply(3,3);

//AssertResultisexpected

if(result===9){

console.log('TestPassed');

}

else{

console.log('TestFailed');

}

};

Thetestcallsamultiplyfunction,whichstillneedstobedefined.Itthenassertsthattheresultsareasexpectedbydisplayingapassorfailmessage.Remember,inTDD,youarelookingattheuseofthemethodandexplicitlywritinghowitshouldbeused.Thisallowsyoutodefinetheinterfacethroughausecase,asopposedtoonlylookingatthelimitedscopeofthefunctionbeingdeveloped.

ThenextstepintheTDDlifecyclewillbefocusedonmakingthetestrun.

MakingitrunThisstepisaboutmakingthetestrun,justasthetailordidwiththesuit.Themeasurementsweretakenduringtheteststep,andnowtheapplicationcanbemoldedtofitthemeasurements.Herearethestepstorunthetest:

1. OpenthebrowserwithtestRunner.html.2. OpentheJavaScriptdeveloperConsolewindow.

Thetestthrowsanerror,asshowninthefollowingscreenshot:

Theerrorthrownisexpectedasthecalculatorapplicationcallsafunctionthathasn’tbeencreatedyet:calculator.multiply.

InTDD,thefocusisonaddingthesmallestchangetogetatesttopass.Thereisnoneedtoactuallyimplementthemultiplicationlogic.Thismayseemunintuitive.Thepointisonceapassingtestexists,itshouldalwayspass.Whenamethodcontainsfairlycomplexlogic,itiseasiertorunapassingtestagainstittoensureitmeetstheexpectations.

Whatisthesmallestchangethatcanbemadetomakethetestpass?Byreturningtheexpectedvalueof9,thetestshouldpass.Althoughthiswon’taddthemultiplyfunction,itwillconfirmtheapplicationwiring.Inaddition,afteryouhavepassedthetest,makingfuturechangeswillbeeasyasyouhavetosimplykeepthetestpassing!

Now,addthemultiplyfunctionandhaveitreturntherequiredvalue9:

www.it-ebooks.info

Page 41: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

varcalculator={

multiply:function(){

return9;

}

};

Inthebrowser,theJavaScriptconsolererunsthetest.Theresultshouldbeasfollows:

Yes!Thetestpassed.Timetocrossoutthefirstitemfromtheto-dolist:

Addmultiplicationfunctionality:3*3=9

Nowthatthereisapassingtest,thenextstepwillbetoremovethehardcodedvalueinthemultiplyfunction.

MakingitbetterTherefactoringstepneedstoremovethehardcodedreturnvalueofthemultiplyfunction.Therequiredlogicisasfollows:

varcalculator={

multiply:function(amount1,amount2){

returnamount1*amount2;

}

};

Rerunthetestsandconfirmthetestpasses.Excellent!Nowthemultiplyfunctioniscomplete.Hereisthefullcodeforthecalculatorandtest:

varcalculator={

multiply:function(amount1,amount2){

returnamount1*amount2;

}

};

varmultipleTest1=function(){

varresult=calculator.multiply(3,3);

if(result===9){

console.log('TestPassed');

}

else{

console.log('TestFailed');

}

};

www.it-ebooks.info

Page 42: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

multipleTest1();

www.it-ebooks.info

Page 43: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingtechniquesItisimportanttounderstandsomefundamentaltechniquesandapproachestotesting.Thissectionwillwalkyouthroughacoupleofexamplesoftechniquesthatwillbeleveragedinthisbook.Thisincludes:

TestingdoubleswithJasminespiesRefactoringBuildingpatterns

Inaddition,hereareadditionaltermsthatwillbeused:

Functionundertest:Thisisthefunctionbeingtested.Itisalsoreferredtoassystemundertest,objectundertest,andsoon.The3A’s(Arrange,Act,andAssert):Thisisatechniqueusedtosetuptests,firstdescribedbyBillWake(http://xp123.com/articles/3a-arrange-act-assert/).The3A’swillbediscussedfurtherinChapter2,TheKarmaWay.

www.it-ebooks.info

Page 44: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingwithaframeworkAlthoughasimplewebpagecanbeusedtoperformtests,asseenearlierinthischapter,itismucheasiertouseatestingframework.Atestingframeworkprovidesmethodsandstructurestotest.Thisincludesastandardstructuretocreateandruntests,theabilitytocreateassertions/expectations,theabilitytousetestdoubles,andmore.ThisbookusesJasmineasthetestframework.Jasmineisabehavior-driventestingframework.ItishighlycompatiblewithtestingAngularJSapplications.InChapter2,TheKarmaWay,wewilltakeamorein-depthlookatJasmine.

www.it-ebooks.info

Page 45: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingdoubleswithJasminespiesAtestdoubleisanobjectthatactsandisusedinplaceofanotherobject.Takealookatthefollowingobjectthatneedstobetested:

varobjectUnderTest={

someFunction:function(){}

};

Usingatestdouble,youcandeterminethenumberoftimessomeFunctiongetscalled.Hereisanexample:

varobjectUnderTest={

someFunction:function(){}

};

jasmine.spyOn(objectUnderTest,'someFunction');

objectUnderTest.someFunction();

objectUnderTest.someFunction();

console.log(objectUnderTest.someFunction.count);

TheprecedingcodecreatesatestdoubleusingaJasminespy(jasmine.spyOn).ThetestdoubleisthenusedtodeterminethenumberoftimessomeFunctiongetscalled.AJasminetestdoubleoffersthefollowingfeaturesandmore:

ThecountofcallsonafunctionTheabilitytospecifyareturnvalue(stubareturnvalue)Theabilitytopassacalltotheunderlyingfunction(passthrough)

Throughoutthisbook,youwillgainfurtherexperienceintheuseoftestdoubles.

StubbingareturnvalueThegreatthingaboutusingatestdoubleisthattheunderlyingcodeofamethoddoesnothavetobecalled.Withatestdouble,youcanspecifyexactlywhatamethodshouldreturnforagiventest.Hereisanexamplefunction:

varobjectUnderTest={

someFunction:function(){return'stubme!';}

};

Theprecedingobject(objectUnderTest)hasafunction(someFunction)thatneedstobestubbed.HereishowyoucanstubthereturnvalueusingJasmine:

jasmine.spyOn(objectUnderTest,'someFunction')

.and

.returnValue('stubbedvalue');

Now,whenobjectUnderTest.someFunctioniscalled,stubbedvaluewillbereturned.Hereishowtheprecedingstubbedvaluecanbeconfirmedusingconsole.log:

varobjectUnderTest={

www.it-ebooks.info

Page 46: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

someFunction:function(){return'stubme!';}

};

//beforethereturnvalueisstubbed

Console.log(objectUnderTest.someFunction());

//displays'stubme'

jasmine.spyOn(objectUnderTest,'someFunction')

.and

.returnValue('stubbedvalue');

//Afterthereturnvalueisstubbed

Console.log(objectUnderTest.someFunction());

//displays'stubbedvalue'

TestingargumentsAtestdoubleprovidesinsightsintohowamethodisusedinanapplication.Asanexample,atestmightwanttoassertwhatargumentsamethodwascalledwithorthenumberoftimesamethodwascalled.Hereisanexamplefunction:

varobjectUnderTest={

someFunction:function(arg1,arg2){}

};

Herearethestepstotesttheargumentstheprecedingfunctioniscalledwith:

1. Createaspysothattheargumentscalledcanbecaptured:

jasmine.spyOn(objectUnderTest,'someFunction');

2. Thentoaccessthearguments,dothefollowing:

//Gettheargumentsforthefirstcallofthefunction

varcallArgs=objectUnderTest.someFunction.call.argsFor(0);

console.log(callArgs);

//displays['param1','param2']

3. Hereishowtheargumentscanbedisplayedusingconsole.log:

varobjectUnderTest={

someFunction:function(arg1,arg2){}

};

//createthespy

jasmine.spyOn(objectUnderTest,'someFunction');

//Callthemethodwithspecificarguments

objectUnderTest.someFunction('param1','param2');

//Gettheargumentsforthefirstcallofthefunction

varcallArgs=objectUnderTest.someFunction.call.argsFor(0);

console.log(callArgs);

//displays['param1','param2']

www.it-ebooks.info

Page 47: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

www.it-ebooks.info

Page 48: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

RefactoringRefactoringistheactofrestructuring,rewriting,renaming,andremovingcodeinordertoimprovethedesign,readability,maintainability,andoverallaestheticofapieceofcode.TheTDDlifecyclestepof“makingitbetter”isprimarilyconcernedwithrefactoring.Thissectionwillwalkyouthrougharefactoringexample.Hereisanexampleofafunctionthatneedstoberefactored:

varabc=function(z){

varx=false;

if(z>10)

returntrue;

returnx;

}

Thisfunctionworksfineanddoesnotcontainanysyntacticalorlogicalissues.Theproblemisthatthefunctionisdifficulttoreadandunderstand.Refactoringthisfunctionwillimprovethenaming,structure,anddefinition.Theexercisewillremovethemasqueradingcomplexityandrevealthefunction’struemeaningandintention.Herearethesteps:

1. Renamethefunctionandvariablenamestobemoremeaningful,thatis,renamexandzsothattheymakesense:

varisTenOrGreater=function(value){

varfalseValue=false;

if(value>10)

returntrue;

returnfalseValue;

}

2. Now,thefunctioncaneasilybereadandthenamingmakessense.3. Removeunnecessarycomplexity.Inthiscase,theifconditionalstatementcanbe

removedcompletely:

varisTenOrGreater=function(value){

returnvalue>10;

};

4. Reflectontheresult.

Atthispoint,therefactoriscomplete,andthefunction’spurposeshouldjumpoutatyou.Theremainingquestionthatshouldbeaskedis“whydoesthismethodexistinthefirstplace?”.

Thisexampleonlyprovidedabriefwalk-throughofthestepsthatcanbetakentoidentifyissuesincodeandhowtoimprovethem.Otherexampleswillbeusedthroughoutthisbook.

www.it-ebooks.info

Page 49: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

BuildingwithabuilderThebuilderpatternusesabuilderobjecttocreateanotherobject.Imagineanobjectwithtenproperties.Howwilltestdatabecreatedforeveryproperty?Willtheobjecthavetoberecreatedineverytest?

Abuilderobjectdefinesanobjecttobereusedacrossmultipletests.Thefollowingcodesnippetprovidesanexampleoftheuseofthispattern.Thisexamplewillusebuilderobjectinthevalidatemethod:

varbook={

id:null,

author:null,

dateTime:null

};

Thebookobjecthasthreeproperties:id,author,anddateTime.Fromatestingperspective,youwouldwanttheabilitytocreateavalidobject,thatis,onethathasallthefieldsdefined.Youmayalsowanttocreateaninvalidobjectwithmissingproperties,oryoumaywanttosetcertainvaluesintheobjecttotestthevalidationlogic,thatis,dateTimeisanactualdate.

HerearethestepstocreateabuilderforthedateTimeobject:

1. Createabuilderfunction:

varbookBuilder=function();

2. Createavalidobjectwithinthebuilder:

varbookBuilder=function(){

var_resultBook={

id:1,

author:'AnyAuthor',

dateTime:newDateTime()

};

}

3. Createafunctiontoreturnthebuiltobject:

varbookBuilder=function(){

var_resultBook={

id:1,

author:"AnyAuthor",

dateTime:newDateTime()

};

this.build=function(){

return_resultBook;

}

}

4. Createanotherfunctiontosetthe_resultBookauthorfield:

varbookBuilder=function(){

www.it-ebooks.info

Page 50: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

var_resultBook={

id:1,

author:'AnyAuthor',

dateTime:newDateTime()

};

this.build=function(){

return_resultBook;

};

this.setAuthor=function(author){

_resultBook.author=author;

};

};

5. Makethefunctionfluentsothatcallscanbechained:

this.setAuthor=function(author){

_resultBook.author=author;

returnthis;

};

6. AsetterfunctionwillalsobecreatedfordateTime:

this.setDateTime=function(dateTime){

_resultBook.dateTime=dateTime;

returnthis;

};

Now,bookBuildercanbeusedtocreateanewbookasfollows:

varbuiltBook=bookBuilder.setAuthor('TimChaplin')

.setDateTime(newDate())

.build();

Theprecedingbuildercannowbeusedthroughoutyourteststocreateasingleconsistentobject.Hereisthecompletebuilderforyourreference:

varbookBuilder=function(){

var_resultBook={

id:1,

author:'AnyAuthor',

dateTime:newDateTime()

};

this.build=function(){

return_resultBook;

};

this.setAuthor=function(author){

_resultBook.author=author;

returnthis;

};

this.setDateTime=function(dateTime){

_resultBook.dateTime=dateTime;

returnthis;

};

www.it-ebooks.info

Page 51: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

};

TipDownloadingtheexamplecode

Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.

www.it-ebooks.info

Page 52: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsQ1.Atestdoubleisanothernameforaduplicatetest.

1. True2. False

Q2.TDDstandsfortest-drivendevelopment.

1. True2. False

Q3.Thepurposeofrefactoringistoimprovecodequality.

1. True2. False

Q4.Atestobjectbuilderconsolidatesthecreationofobjectsfortesting.

1. True2. False

Q5.The3A’sareasportsteam.

1. True2. False

www.it-ebooks.info

Page 53: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThischapterprovidedanintroductiontoTDD.ItdiscussedtheTDDlifecycle(testfirst,makeitrun,makeitbetter)andshowedhowthesamestepsareusedbyatailor.Finally,itlookedoversomeofthetestingtechniquesthatwillbediscussedthroughoutthisbookincluding:

TestdoublesRefactoringBuildingpatterns

AlthoughTDDisahugetopic,thisbookissolelyfocusedontheTDDprinciplesandpracticestobeusedwithAngularJS.Inthenextchapter,youwillstartthejourneyandseehowtosetuptheKarmatestrunner.

www.it-ebooks.info

Page 54: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter2.TheKarmaWayJavaScripttestinghashitthemainstream,thankstoKarma.KarmamakesitseamlesstotestJavaScript.AngularJSwascreatedaroundtesting.ThischapterexplorestheoriginsofKarmaandwhyithastobeusedinanyAngularJSproject.Bytheendofthischapter,youwillnotonlyunderstandtheproblemthatKarmasolves,butalsowalkthroughacompleteexampleusingit.

www.it-ebooks.info

Page 55: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

JavaScripttestingtoolsKnowingwhatthedifferenttestingtoolsareishalfthebattle.Inthissection,youwilllearnaboutthetwoprimarytoolsthatwillbediscussedandusedthroughoutthebook.Theyare:

Karma:ThisisatestrunnerProtractor:Thisisanend-to-endtestingframework

www.it-ebooks.info

Page 56: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

KarmaBeforediscussingwhatKarmais,itisbesttodiscusswhatitisn’t.Itisn’taframeworktowritetests.Itisatestrunner.WhatthismeansisthatKarmagivesyoutheabilitytoruntestsinseveraldifferentbrowsersinanautomatedway.Inthepast,developershadtoperformmanualstepstodothis,including:

1. Openingupabrowser2. PointingthebrowsertotheprojectURL3. Runningthetests4. Confirmingthatalltestshavepassed5. Makingchanges6. Refreshingthepage

WithKarma,automationgivesthedevelopertheabilitytorunasinglecommandanddeterminewhetheranentiretestsuitehaspassedorfailed.FromaTDDperspective,thisgivesyoutheabilitytofindandfixfailingtestsquickly.SomeoftheprosandconsofusingKarmacomparedtoamanualprocessareasfollows:

Pros Cons

Abilitytoautomatetestsinmultiplebrowsersanddevices. Additionaltooltolearn,configure,andmaintain.

Abilitytowatchfiles.

Onlinedocumentationandsupport.

Doesonething—runsJavaScripttests—anddoesitwell.

Easytointegratewithacontinuousintegrationserver.

AutomatingtheprocessoftestingandusingKarmaisextremelyadvantageous.IntheTDDjourneythroughthisbook,Karmawillbeoneofyourprimarytools.

www.it-ebooks.info

Page 57: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ProtractorProtractorisanend-to-endtestingtool.Itallowsdeveloperstomimicuserinteractions.Itautomatesthetestingoffunctionalityandfeaturesthroughtheinteractionofawebbrowser.ProtractorhasspecificmethodstoassistwithtestingAngularJS,buttheyarenotexclusivetoAngularJS.SomeoftheprosandconsofusingProtractorareasfollows:

Pros Cons

Configurabletotestmultipleenvironments Documentationandexamplesarelimited

EasyintegrationwithAngularJS

Syntaxandtestingcanbesimilartothetestingframeworkchosenforunittesting

www.it-ebooks.info

Page 58: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

JavaScripttestingframeworksInthissection,youwilllearnaboutthetestingframeworksthatwillsupportyouinyourTDDpractices.Theseinclude:

JasmineSeleniumMocha

www.it-ebooks.info

Page 59: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

JasmineJasmineisaJavaScripttestingframework.ItcanbeeasilyintegratedandrunforwebsitesandisagnostictoAngularJS.Itprovidesspiesandotherfeatures.ItcanalsoberunonitsownwithoutKarma.Someoftheprosandconsareasfollows:

Pros Cons

DefaultintegrationwithKarma. Nofile-watchingfeatureavailablewhenrunningtests.Thismeansthattestshavetobererunbytheuserastheychange.

Providesadditionalfunctionstoassistwithtesting,suchastestspies,fakes,andthepass-throughfunctionality. ThelearningcurvecanbesteepforalltheProtractormethodsandfeatures.

Cleansreadablesyntaxthatallowsteststobeformattedinawaythatrelatestothebehaviorbeingtested.

Integrationwithseveraloutputreporters.

www.it-ebooks.info

Page 60: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SeleniumSelenium(http://www.seleniumhq.org/)definesitselfas:

“Seleniumautomatesbrowsers.That’sit!”

Automationofbrowsersmeansthatdeveloperscaninteractwithbrowserseasily.Theycanclickonbuttonsorlinks,enterdata,andsoon.Seleniumisapowerfultoolsetthat,whenusedandsetupproperly,haslotsofbenefits;however,itcanbeconfusingandcumbersometosetitup.SomeoftheprosandconsofSeleniumareasfollows:

Pros Cons

Largefeatureset Hastoberunasaseparateprocess

Distributedtesting Severalstepstoconfigure

SaaSsupportthroughservicessuchasSauceLabs

Documentationandresourcesavailable

AsProtractorisawrapperaroundSelenium,itwon’tbediscussedindetail.ProtractorwillbefurtherintroducedinChapter3,End-to-endTestingwithProtractor.

www.it-ebooks.info

Page 61: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MochaMochaisatestingframeworkoriginallywrittenforNode.jsapplicationsbutsupportsbrowsertestingaswell.ItisverysimilartoJasmineandmirrorsmuchofitssyntax.Let’sdiscusssomeoftheprosandconsofMocha:

Pros Cons

Easytoinstall Separateplugins/modulesrequiredforassertions,spies,andsoon

Gooddocumentationavailable AdditionalconfigurationrequiredtouseitwithKarma

Hasseveralreporters

Plugsinwithseveralnodeprojects

TheapproachofbeingjustatestrunnerandnotworryingaboutassertionsandmockingfitsintotheNode.jsmantra—smallindividualmodulesthatdoonething.ForNode.jsprojects,IprefertogowithMocha.ThereasonisthatyoucanaddnewNodePackageManager(npm)modulesforthespecificpluginsneeded.Whenworkingwithawebsite,andspecificallyAngularJS,IprefertouseJasmine.Itprovidesthefeaturesneededwithouthavingtoinstalladditionalnpmmodulestoanon-Node.jsproject.

www.it-ebooks.info

Page 62: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

BirthofKarmaWhenpickingupanewtool,itisimportanttounderstandwhereitcamefromandwhyitwasbuilt.ThissectiongivesyousomebackgroundoftheoriginsofKarma.

www.it-ebooks.info

Page 63: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TheKarmadifferenceKarmawascreatedbyVojtechJína.Theprojectwasoriginallycalledtestacular.InVojtechJína’sthesis,hediscussesthedesign,purpose,andimplementationofKarma.Inhisthesis(JavasScriptTestRunner,page6,https://github.com/karma-runner/karma/raw/master/thesis.pdf),hedescribesKarmaas:

“…atestrunner,thathelpswebapplicationdeveloperstobemoreproductiveandeffectivebymakingautomatedtestingsimplerandfaster.Infact,Ihaveamuchhigherambitionandthisthesisisonlyapartofit-IwanttopromoteTestDrivenDevelopment(TDD)as“the”waytodevelopwebapplications,becauseIbelieveitisthemosteffectivewaytodevelophighqualitysoftware.”

KarmahastheabilitytoeasilyandautomaticallyrunJavaScriptunittestsonrealbrowsers.Traditionally,testswererunbyhavingtomanuallylaunchabrowserandcheckforresultsbycontinuallyhittingtheRefreshbutton.Thismethodwasawkwardandoftenresultedindeveloperslimitingtheamountofteststhatwerewritten.

WithKarma,adevelopercanwriteatestinalmostanystandardtestframework,chooseabrowsertorunagainst,setthefilestowatchforchanges,andbam!Continuousautomatedtesting.Simplychecktheoutputwindowforfailedorpassedtests.

www.it-ebooks.info

Page 64: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ImportanceofcombiningKarmawithAngularJSKarmawasbuiltforAngularJS.PriortoKarma,therewasalackofautomatedtestingtoolsforweb-basedJavaScriptdevelopers.

Remember,Karmaisatestrunner,notatestframework.Itsjobistoruntestsandreportwhichtestswillpassorfail.Whyisthishelpful?Atestframeworkiswhereyouwillwriteyourtests.Apartfromdoingthis,youwillneedtobefocusedonrunningthetestseasilyandseeingresults.Karmaeasilyrunstestsacrossseveraldifferentbrowsers.Karmaalsohassomeotherfeatures,suchasfilewatching,whichwillbediscussedfurtherindetaillaterinthebook.

www.it-ebooks.info

Page 65: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InstallingKarmaTimetostartusingKarma.Installationsandapplicationsareconstantlychanging.ThefollowingguideisintendedtobebriefinthehopethatyouwillgototheKarmawebsite,http://karma-runner.github.io/,andfindthelatestinstructions.

Themainfocusofthissectionwillbeonthespecificconfigurationusedinthisbookandnotanin-depthinstallationguide.

www.it-ebooks.info

Page 66: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InstallationprerequisitesToinstallKarma,youneedtohaveNode.jsonyourcomputer.Node.jsrunsonGoogle’sV8engineandallowsJavaScripttoberunonseveraloperatingsystems.

Developerscanpublishnodeapplicationsandmodulesusingnpm.Thisallowsdeveloperstoquicklyintegrateapplicationsandmodulesintotheirapplications.

Karmarunsandisinstalledthroughthenpmpackage,andthereforeyouneedNode.jsbeforeyouuseorinstallKarma.ToinstallNode.js,gotohttp://nodejs.org/andfollowtheinstallationinstructions.

AssumingyouhaveNode.jsinstalled,typethefollowingcommandinthecommandprompttoinstallKarma:

$npminstallkarma-g

TheprecedingcommandusesnpmtoinstallKarmagloballyusing-g.WhatthismeansisthatyoucanuseKarmaonthecommandpromptbysimplytypingthefollowing:

$karma-–version

Bydefault,installingKarmawillinstallkarma-chrome-launcherandkarma-jasmineasdependencies.Ensurethatthesemodulesareinstalledgloballyaswell.

www.it-ebooks.info

Page 67: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ConfiguringKarmaKarmacomesequippedwithanautomatedwaytocreateaconfigurationfile.Tousetheautomatedway,typethefollowingcommand:

$karmainit

Hereisasampleoftheoptionschosen:

CustomizingKarma’sconfigurationThefollowinginstructionsdescribethespecificconfigurationrequiredtogetKarmarunningfortheproject.Customizationincludesthetestframework(Jasmine),browser(Chrome)totestwith,andfilestotest.Tocustomizetheconfiguration,openupkarma.confandperformthefollowingsteps:

1. Ensurethattheenabledframeworksaysjasmineusingthefollowingcode:

frameworks:['jasmine'],

2. Configurethetestdirectory.Notethatthefollowingdefinitionneedstoincludethetestsrequiredtorunalongwithanypotentialdependencies.Thedirectorythatwillholdourtestsis/test/unit/:

files:[

'test/unit/**/*.js'

],

3. SetthetestbrowsertoChrome.Itwillthenbeinitializedandwillrunapopupaftereverytest:

www.it-ebooks.info

Page 68: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

browsers:['Chrome'],

ConfirmingKarma’sinstallationandconfigurationToconfirmKarma’sinstallationandconfiguration,performthefollowingsteps:

1. RunthefollowingcommandtoconfirmthatKarmastartswithnoerrors:

$karmastart

2. Theoutputshouldbesomethinglikethis:

$INFO[karma]:Karmav0.12.16serverstartedathttp://localhost:9876/

3. Inaddition,theoutputshouldstatethatnotestfileswerefound:

$WARN[watcher]:Pattern"test/unit/**/*.js"doesnotmatchanyfile.

4. Theoutputshoulddothisalongwithafailedtestmessage:

$Chrome35.0.1916(Windows7):Executed0of0ERROR(0.016secs/0

secs)

Thisisexpectedasnotestshavebeencreatedyet.ContinuetothenextstepifKarmaisstartedandyouwillseeyourChromebrowserwiththefollowingoutput:

Commoninstallation/configurationissuesIfJasmineorChromeLauncheraremissing,performthefollowingsteps:

Whenrunningthetest,anerrormightoccursayingmissingJasmineorChromeLauncher.Ifyougetthiserror,typethefollowingcommandtoinstallthemissingdependencies:

$npminstallkarma-jasmine-g

$npminstallkarma-chrome-launcher-g

Retrythetestandconfirmthattheerrorshavebeenresolved.

Thefollowingiswhatyouneedtodotoprovidepermissions(sudo/administrator):

Insomecases,youmightnotbeabletoinstallnpm_modulesgloballyusingthe–gcommand.Thisisgenerallyduetopermissionissuesonyourcomputer.TheresolutionistoinstallKarmadirectlyinyourprojectfolder.Usethesamecommandwithout–gtodothis:

$npminstallkarma

RunKarmausingtherelativepath:

www.it-ebooks.info

Page 69: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

$./node_modules/karma/bin/karma--version

NowthatKarmaisinstalledandrunning,it’stimetoputittouse.

www.it-ebooks.info

Page 70: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingwithKarmaInthissection,youwillcreateatesttoconfirmKarmaisworkingasexpected.Todothis,performthefollowingsteps:

1. Createthetestdirectory.IntheKarmaconfiguration,testsweredefinedinthefollowingdirectory:

files:[

'test/unit/**/*.js'

],

Goaheadandcreatethetest/unitdirectory.

2. CreateanewfilenamedfirstTest.jsinthetest/unitdirectory.3. Writethefirsttestasfollows:

describe('whentestingkarma',function(){

it('shouldreportasuccessfultest',function(){

expect(true).toBeTruthy();

});

});

4. TheprecedingtestusesJasminefunctionsandhasthefollowingproperties:

describe:Thisprovidesabriefstringdescriptionofthethingsthatwillbetestedit:Thisprovidesabriefstringofthespecificassertionexpect:ThisprovidesawaytoassertvaluestoBeTruthy:Thisisoneofseveralpropertiesonanexpectationthatcanbeusedtomakeassertions

Thistesthasnorealvalueotherthantoconfirmtheoutputofapassingtest.

5. Bam!CheckyourconsolewindowandseethatKarmahasexecutedyourtest.Yourcommandlineshouldsaysomethinglikethis:

$INFO[watcher]:Addedfile"./test/unit/firstTest.js"

ThisoutputmeansthatKarmaautomagicallyrecognizedthatanewfilewasadded.Thenextoutputshouldsaysomethinglikethis:

$Chrome35.0.1916(Windows7):Executed1of1SUCCESS(0.02secs/

0.015secs)

Thismeansyourtesthaspassed!

www.it-ebooks.info

Page 71: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ConfirmingtheKarmainstallationNowtheinitialsetupandconfigurationofKarmaiscomplete.Hereisareviewofthesteps:

InstalledKarmathroughthenpmcommandInitializedadefaultconfigurationthroughthekarmainitcommandConfiguredKarmawithJasmineandatest/unittestdirectoryStartedKarmaandconfirmeditcouldbeopenedwithChromeAddedaJasminetest,firstTest.js,toourtest/unittestdirectoryKarmarecognizedthatfirstTest.jshadbeenaddedtothetestdirectoryKarmaexecutedourfirstTest.jsandreportedouroutput

Withacoupleofsteps,youwereabletoseeKarmarunningandexecutingtestsautomatically.FromaTDDperspective,youcanfocusonmovingtestsfromfailingtopassingwithoutmucheffort.Noneedtorefreshthebrowser;justcheckthecommandoutputwindow.KeepKarmarunningandallyourtestsandfileswillautomaticallybeaddedandrun.

Inthenextsections,youwillseehowtoapplyKarmawithaTDDapproach.Ifyou’reOKwithKarmasofarandwanttomoveontoProtractor,continuetothenextchapter.

www.it-ebooks.info

Page 72: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

UsingKarmawithAngularJSHere,youwillwalkthroughaTDDapproachtoanAngularJScomponent.Bytheendofthischapter,youshouldbeableto:

FeelconfidentaboutusingKarmaanditsconfigurationUnderstandthebasiccomponentsofaJasminetestStarttounderstandhowtointegrateaTDDapproachinanAngularJSapplication

www.it-ebooks.info

Page 73: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

GettingAngularJSAneasymethodforinstallingAngularJSintoprojectsistouseBower.FeelfreetoinstallAngularJSintoyourprojectinanywayyouprefer.FollowingisabriefdescriptiononhowtoinstallanduseBower.

BowerBowerisapackagemanagerforJavaScriptcomponents.Bowerallowsclient-sideJavaScriptcomponentstobeversionedandautomaticallydownloadedintoyourprojects.Thisallowsyoutoupgradethird-partytoolsandcomponentsandprovideaneasy,standardwaytousetoolssuchasAngularJS,Bootstrap,andmanymore.

Bowerinstallation

Bowerisannpmmodule,justlikeKarma.EnsureyouhaveNode.jsinstalledbeforeyoutrytoinstallBowerusingthefollowingsteps:

1. EnsureyouhaveBowerinstalledusingthiscode:

$npminstallbower-g

2. Initializethebower.jsonconfigurationintherootoftheproject:

$bowerinit

//Thiswillcreateabower.jsonfilewhichcontainsthedependent

packages

//Answerdefaulttoallthequestions.

Theoutputshouldbesomethinglikewhatisshowninthefollowingscreenshot:

Thatisit.NowBowerisinstalledandreadytodownloadJavaScriptpackagesintoyourproject.

InstallingAngularJSUsethefollowingcommandtoinstallAngularJSusingBower:

www.it-ebooks.info

Page 74: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

$bowerinstallangular

Typethepreviouscommandinyourcommandpromptforthedirectoryyouwillbeworkingin.Aftertheinstallationiscomplete,lookatyourdirectoryandconfirmthatabower_componetsdirectorywascreated.Insidethis,thereshouldbeafolderforAngularJS:

InstallingAngularmocksAngularmocksallowsyoutotestAngularJScomponents.Theofficialdefinition,whichisfoundathttps://docs.angularjs.org/api/ngMock,isasfollows:

“ThengMockmoduleprovidessupporttoinjectandmockAngularservicesintounittests.Inaddition,ngMockalsoextendsvariouscorengservicessuchthattheycanbeinspectedandcontrolledinasynchronousmannerwithintestcode.”

ToinstallAngularmocks,simplyuseBower:

$bowerinstallangular-mocks

InitializingKarmaAkarma.conffileisrequiredtotellKarmahowitshouldrunfortheapplicationinquestion.Thebestwaytoinitializeitistorunthefollowingcommandinthecommandprompt:

$karmainit

Usethedefaultanswers.Afterkarma.confhasbeencreatedinthecurrentdirectory,openuptheconfiguration.TheoneconfigurationthatneedstochangeisthedefinitionofthefilesforKarmatouse.Usethefollowingdefinitioninthefilessection,whichdefinesthefilesrequiredtorunthetest:

files:[

'bower_components/angular/angular.js',

'bower_components/angular-mocks/angular-mocks.js',

'app/**/*.js',

'spec/**/*.js'

],

Theprecedingconfigurationloadsangular.js,JavaScriptfilesintheappdirectory,andyourtestsinthespecfolder.

EnsurethatKarmacanrunyourconfiguration:

$karmastart

Thecommandoutputshouldstatesomethinglikethis:

www.it-ebooks.info

Page 75: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

$Chrome35.0.1916(Windows7):Executed0of0ERROR(0.01secs/0secs)

Thatisit.KarmaisnowrunningforthefirstAngularJSapplication.

www.it-ebooks.info

Page 76: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingwithAngularJSandKarmaThepurposeofthisfirsttestusingKarmaistocreateadynamicto-dolist.ThiswalkthroughwillfollowtheTDDstepswediscussedinChapter1,IntroductiontoTest-drivenDevelopment:testfirst,makeitrun,andmakeitbetter.ThiswillallowyoutogainmoreexperienceinusingTDDwithAngularJS.

www.it-ebooks.info

Page 77: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Adevelopmentto-dolistBeforeyoustartthetest,setyourfocusonwhatneedstobedevelopedusingadevelopmentto-dolist.Thiswillallowyoutoorganizeyourthoughts.Hereistheto-dolist:

Maintainalistofitems:

Theexamplelistconsistsoftest,execute,andrefactor

Addanitemtothelist:

Theexamplelistafteryouaddtheitemistest,execute,refactor,andrepeat

Removeanitemfromthelist:

Theexamplelistafteryouaddandremovetheitemistest,execute,andrefactor

www.it-ebooks.info

Page 78: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingalistofitemsThefirstdevelopmentitemistoprovideyouwiththeabilitytohavealistofitemsonacontroller.ThenextcoupleofstepswillwalkyouthroughtheTDDprocessofaddingthefirstfeatureusingtheTDDlifecyclethatistestfirst,makeitrun,makeitbetter.

TestfirstDeterminingwheretostartisoftenthehardestpart.Thebestwayistorememberthe3A’s(Assemble,Act,andAssert)andstartwiththebaseJasminetemplateformat.Thecodetodothisisasfollows:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

describe:Thisdefinesthemainfeaturewearetesting.Thestringwillexplainthefeatureinreadabletermsandthenthefunctionwillfollowwiththetest.beforeEach:Thisistheassemblestep.ThefunctiondefinedinbeforeEachwillgetexecutedbeforeeveryassert.Itisbesttoputthetestsetuprequiredbeforeeachtestinthisfunction.it:Thisistheactandassertstep.Intheitsection,youwillperformtheactionbeingtested,followedbysomeassertion.Theactstepdoesn’thavetogointotheitfunction.Dependingonthetest,itmightbemoresuitedinthebeforeEachfunction.

Assemble,Act,andAssert(3A’s)Nowthatthetemplateisthere,wecanstartfillinginthepieces.Wewillagainfollowthe3A’smantra.

Thefollowingarethetwopartsoftheassemblesection.

Inthefirstpart,weinitializethemoduleusingthefollowingcode:

...

beforeEach(function(){

module('todo');

});

...

ThiscodewillusetheAngularmocksJavaScriptlibrarytoinitializetheAngularJSmodulebeingtested.Wehaven’tdefinedthetodomodule,butwewilldothisafterwegetafailingtest.

ThesecondparttalksaboutthescopeofTodoController.TheTodoControllerscopewillcontainthelistofitemsonitsscopevariable.ItisrequiredthatthetesthasaccesstothescopeofTodoController.Angularmockswillbeusedtogetthis.Addthefollowing

www.it-ebooks.info

Page 79: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

codetobeforeEachtogetthecontroller’sscope:

//scope–holditemsonthecontroller

varscope={};

beforeEach(function(){

//...

//inject–accessangularcontrollerinject(function($controller){

//$controller–initializecontrollerwithtestscope

$controller('TodoController',{$scope:scope});

});

//...

});

Thefollowingisabriefexplanationofeachofthecodeelements:

scope:Thisvariableisusedtoholdandtestthelistitemsonthecontroller.inject:TheAngularmocksfunctionisusedtoaccessAngularJS’s$controller.ThisessentiallyallowsyoutogetaccessandinjectdependenciesintoAngularJSobjects.$controller:ThisinitializesthescopeofTodoController.Thetest’sscopevariablewillnowcontainthecontroller’sscope.

Inthecaseof“act”,thereisnomethodtoacton.Thescopeobjecthasalreadybeenretrievedaspartoftheassemblestep.

Inassert,therearetwopartsagain:

ThefirstassertionistoensuretheTodoControllerscopehasalistvariabledefinedwiththreeitems.Thelistvariablewillbeusedtoholdthelistofalltheitems:

it('shoulddefinealistobject',function(){

expect(scope.list).toBeDefined();

});

Thesecond,third,andfourthassertionswillbeusedtoconfirmwhetherthedatainthelistisinthecorrectorder,thatis,firstistest,secondisexecute,andthirdisrefactor:

//Secondtest

it('shoulddefinealistobject',function(){

expect(scope.list[0]).toEqual('test');

});

//Thirdtest

it('shoulddefinealistobject',function(){

expect(scope.list[1]).toEqual('execute');

});

//Fourthtest

it('shoulddefinealistobject',function(){

expect(scope.list[2]).toEqual('refactor');

});

MakeitrunThenextstepintheTDDlifecycleistomaketheapplicationrunandfixthecodesothat

www.it-ebooks.info

Page 80: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

thetestspass.Remember,thinkaboutthesmallestcomponentsthatcanbeaddedtomakethetestpassbyproceedingwiththefollowingsteps:

1. RunKarmabytypingthefollowingcommand:

$karmastart

2. Ifyouencounter[$injector:moduler]Failedtoinstantiatemoduletododuetoerror,thenitcanbeduetothefollowing:

Theprecedingerrormessageissayingthatthetodomodulehasn’tbeendefined.Sincetheerrormessageistellingyouwhatisrequired,thisistheperfectplacetostart.Createanewfileintheappdirectorynamedtodo.Theworkingdirectoryshouldnowlooksomethinglikethis:

Addthetodomoduletothebeginningofyournewfileasfollows:

angular.module('todo',[]);

ReviewtheconsolewindowwhereKarmaisrunning.Youshouldnowseeanewerror.

3. Error:The[ng:areq]argumentTodoControllerisnotafunction,gotundefined:

Thiserrormessageisdescribingexactlywhatneedstobedone.Thereisnoneedtodeciphererrormessagesorstacktraces.Simplyupdatethetodo.jsfilesoitcontainsanAngularJScontrollerasfollows:

angular.module('todo',[])

.controller('TodoController',[])

Inthepreviouscode,wedidn’ttryanddefinethelogicrequired;weonlyaddedthesmallestcomponenttomeettheerrormessage.Reviewtheconsolewindowforthenexterror.

4. Error:Theexpectedundefinedtobedefinedasfollows:

Thenewerrormessageisagainclear.Wecanalsoseethatthecodehasnowpasseduptothepointofourassertionatthefollowingpoint:

expect(scope.list).toBeDefined();

Asthereisnolistonthescope,youneedtoaddone.Updatetheapp/todo.jsfileasfollows:

www.it-ebooks.info

Page 81: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

.controller('TodoController',['$scope',function($scope){

$scope.list=[];

}])

Reviewtheconsolewindow.

5. Youshouldnowseeoneofthefourtestspass!ThismeansyouhavesuccessfullyusedTDDandKarmatogetyourfirsttesttopass.Nowyouneedtofixtheotherthree.ThenexterrorisExpectedundefinedtoequal'test':

Theerroroutputagaindescribesexactlywhatneedstohappen.Youjustneedtoinitializethearraywiththeelementstest,execute,andrun.Gotoapp/todo.jsandaddthedatatothearrayinitialization:

angular.module('todo',[])

.controller('TodoController',['$scope',function($scope){

$scope.list=['test','execute','refactor'];

}]);

ReviewtheoutputintheKarmawindow.

6. Excellent!Theoutputisingreenandstatesthatallthetestshavepassed.

Theresultmoduleandcontrollercodefromthisstepisasfollows:

//Amodulefortheapplication

angular.module('todo',[])

//Acontrollertomanagetheto-doitems.controller('TodoController',

['$scope',function($scope){

//theinitializationofitemsonthecontrollerscope

$scope.list=['test','execute','refactor'];

}]);

Nowthatthe“makeitrun”stepiscomplete,youcanmoveontothenextstepandmakeitbetter.

MakeitbetterUntilthispoint,therewasnothingrequiredtodirectlyrefactororthathadbeenidentifiedinthedevelopmentto-dolist.Areviewofthedevelopmentto-dolistshowsthatanitemcanbecrossedout:

Viewalistofto-dolistitems:

Theexamplelistconsistsoftest,execute,andrefactor

Addanitemtoato-do-list:

Theexamplelistafteryouaddtheitemwillconsistoftest,execute,refactor,andrepeat

Removeanitemfromato-do-list:

Theexamplelistafteryouaddandthenremovetheitemwillconsistoftest,execute,andrefactor

www.it-ebooks.info

Page 82: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Nextupistherequirementtoaddanewitemtothelist.TheTDDrhythmwillbefollowedagain:testfirst,makeitrun,andmakeitbetter.

www.it-ebooks.info

Page 83: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AddingafunctiontothecontrollerThenexttaskistogivethecontrollertheabilitytoadditemstothescopelist.Thiswillrequiretheadditionofamethodtothescope.Thiswalk-throughwillfollowthesameTDDstepsasdonepreviously.

TestfirstInsteadofcreatinganewfileandduplicatingsomeoftheassemblesteps,thefollowingtestwillbeinsertedunderthelastitmethod.Thereasonisbecausethesamemoduleandcontrollerwillbeused:

describe('whenusingato-dolist',function(){

varscope=null;

beforeEach(function(){

//...

});

//...

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

});

Assemble,Act,andAssert(3A’s)Nowthatthetemplateisthere,wecanstartfillinginthegapsusingthe3A’smantra:

1. Assemble:Thereisnoinitializationorsetuprequired,asthemoduleandcontrollerscopewillbeinherited.

2. Act:Here,youneedtoactontheaddmethodwithanewitem.Weplacetheactfunctionintothebeforeeachfunction.Thisallowsustorepeatthesamestepif/whenmoretestsareadded:

beforeEach(function(){

scope.add('repeat');

});

3. Assert:Here,anitemshouldbeaddedtothelist,andthenyouneedtoconfirmthatthelastiteminthearrayisasexpected:

it('shouldadditemtolastiteminlist',function(){

varlastIndexOfList=scope.list.length-1;

expect(scope.list[lastIndexOfList]).toEqual('repeat');

});

www.it-ebooks.info

Page 84: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitrunThenextstepintheTDDlifecycleistomakeitrun.Remember,thinkaboutthesmallestcomponentsthatcanbeaddedtomakethetestpass,asfollows:

1. EnsureKarmaisrunninginyourconsolebytypinginthefollowingcommand:

$karmastart

2. ThefirsterrorwillstateTypeError:undefinedisnotafunction:

Theerrorreferstothefollowinglineofcode:

scope.add('repeat');

Theerroristellingyouthattheaddmethodhasn’tbeendefined.Theaddfunctionwillneedtobeaddedtotheapp/todo.jscode.Thecontrollerhasalreadybeendefined,sotheaddfunctionneedstobeplacedonthecontroller’sscope:

angular.module('to-do',[])

.controller('TodoController',['$scope',function($scope){

//...

$scope.add=function(){};

}]);

Noticehowtheaddfunctiondoesn’tcontainanylogic.Thesmallestcomponenthasbeenaddedtogetthetesttosatisfytheerrormessage.Reviewtheconsolewindowforthenexterror.

3. Error:Expected'refactor'toequal'repeat':

Havealookatthefollowingexpectation:

it('shouldadditemtolastiteminlist',function(){

varlastIndexOfList=scope.list.length-1;

expect(scope.list[lastIndexOfList]).toEqual('repeat');

});

Thefailedassertioninstep2istellingusthatbasedontheprecedingexpectation,theexpectedresultofrepeatisnotwhatthelastiteminthelisthas.Thesmallestpossiblethingthatcanbeaddedtomakethisassertionpassistopushrepeattotheendofthelistintheaddfunction.Hereishowtodothis:

//...

$scope.add=function(){

$scope.list.push('repeat');

};

//...

Reviewtheconsoletoseewhatthenextoutputsays.

4. Success!Allfivetestshavenowpassed.

Theresultingcodeaddedtogettheteststopassisasfollows:

www.it-ebooks.info

Page 85: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

//Amodulefortheapplication

angular.module('todo',[])

//Acontrollertomanagetheto-doitems

.controller('TodoController',['$scope',function($scope){

//theinitializationofitemsonthecontrollerscope

$scope.list=['test','execute','refactor'];

$scope.add=function(){

$scope.list.push('repeat');

};

}]);

MakeitbetterThemainthingthatweneedtorefactoristhattheaddfunctionstillhasn’tbeenfullyimplemented.Itcontainsahardcodedvalue,andtheminutewesendinadifferentitemintotheaddfunction,thetestwillfail.

KeepKarmarunningsowecankeeppassingthetestsaschangesaremade.Themainissuewiththecurrentaddmethodisasfollows:

Itdoesn’tacceptanyparameterItdoesn’tpushaparameterontothelistbutusesahardcodedvalue

Theresultantaddfunctionshouldnowlookasfollows:

$scope.add=function(item){

$scope.list.push(item);

};

ConfirmthattheKarmaoutputstilldisplayssuccess:

$Chrome35.0.1916(Windows7):Executed5of5SUCCESS(0.165secs/0.153

secs)

www.it-ebooks.info

Page 86: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsSelf-testquestionswillhelpyoufurthertestyourknowledgeofusingTDDwithAngularJSandKarma.

Q1.HowdoyouuseKarmatocreateaconfigurationfile?

1. karmaconfig2. karmainit3. karma–configkarma.conf.js

Q2.TheJasminetestmethodnamedbeforegetsexecutedbeforeeverytest.

1. True2. False

Q3.BowerisusedtoinstallKarma.

1. True2. False

Q4.The3A’sstandforwhichoneofthese?

1. Agroupofsuperheroes2. Assemble,Act,andAssert3. Accept,approve,andact

www.it-ebooks.info

Page 87: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryInthischapter,wereviewedJavaScripttestingframeworksandtoolsanddiscussedhowVojtechJínacreatedKarma.Wesawhowtoinstall,configure,andrunKarma.Finally,youhavewalkedthroughanexampleofusingKarmawithTDD.Inthenextchapter,youwilllearnaboutend-to-endtestingwithProtractor.

www.it-ebooks.info

Page 88: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter3.End-to-endTestingwithProtractorUnittestingisonlyoneaspectoftesting.Inthischapter,wewilllookatend-to-endtestingapplications,throughalllayersofanapplication.YouwillbeintroducedtoProtractor,theend-to-endtestingtoolfromtheAngularJSteam.Wewilllookintowhyitwascreatedandtheproblemsitsolves.Finally,wewillseehowtoinstall,configure,anduseProtractorwithTDD.

www.it-ebooks.info

Page 89: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AnoverviewofProtractorProtractorisanend-to-endtestingtoolthatrunsusingNode.jsandisavailableasannpmpackage.BeforetalkingaboutProtractorspecifically,youneedtounderstandwhatend-to-endtestingis.End-to-endtestingistestinganapplicationagainstalltheinterconnectedmovingpartsandlayersofanapplication.Thisdiffersfromunittests,wherethefocusisonindividualcomponentssuchascontrollers,services,directives,andsoon.Withend-to-endtesting,thefocusisonhowtheapplicationoramodule,asawhole,works,suchasconfirmingtheclickofabuttondoesx,y,andz.

Protractorallowstheend-to-endtestingofanapplication.Thisincludestheabilitytosimulatetheclickofabuttonandinteractwithanapplicationinthesamewayauserwould.Itthenallowsexpectationstobesetbasedonwhattheuserwouldexpect.Toputthisintocontext,thinkaboutthefollowinguserspecification:

AssumingIinputabcintothesearchbox,thefollowingshouldoccur:

ThesearchbuttonishitAtleastoneresultshouldbereceived

Theprecedingspecificationdescribesabasicsearchfeature.Nothingintheprecedingspecificationdescribesacontroller,directive,orservice;itonlydescribestheexpectedapplicationbehavior.Ifauserweretotestthespecification,theymayperformthefollowingsteps:

1. Pointthebrowsertothewebsite2. Selecttheinputfield3. Typeabcintheinputfield4. ClickontheSearchbutton5. Confirmthatthesearchoutputdisplaysatleastoneresult.

ThestructureandsyntaxofProtractormirrorsthatofJasmineandthetestsyouwroteinChapter2,TheKarmaWay.YoucanthinkofProtractorasawrapperaroundJasmine,withaddedfeaturestosupportend-to-endtesting.Towriteanend-to-endtestwithProtractor,wecanfollowthesamestepsasdescribedintheprecedingsteps,butwithcode.Herearethestepsincode:

1. Pointthebrowsertothewebsite:

browser.get('/');

2. Selecttheinputfield:

varinputField=element.all(by.css('input'));

3. Typeabcintheinputfield:

inputField.setText('abc');

4. ClickontheSearchbutton:

www.it-ebooks.info

Page 90: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

inputField.click();

5. Findthesearchresultdetailsonthepage:

varsearchResults=element.all(by.css('#searchResult');

6. Finally,theassertionneedstobemadethatatleastoneormoresearchresultsareavailableonthescreen:

expect(searchResults).count()>=1);

Asacompletetest,thecodewillbeasfollows:

describe('GivenIinput'abc'intothesearchbox',function(){

//1–Pointbrowsertowebsite

browser.get('/');

//2–Selectinputfield

varinputField=element.all(by.css('input'));

//3-Typeabcintoinputfield

inputField.setText('abc');

//4-Pushsearchbutton

inputField.click();

it('shoulddisplaysearchresults',function(){

//5-Findthesearchresultdetails

varsearchResults=element.all(by.css('#searchResult');

//6-Assert

expect(searchResults).count()>=1);

});

});

That’sit!WhenProtractorruns,itwillopenabrowser,gotothewebsite,followtheinstructions,andfinallychecktheexpectations.Thetrickwithend-to-endtestingishavingaclearvisiononwhattheuserspecificationis,andthentranslatingthatspecificationtocode.

Thepreviousexampleisahigh-levelviewofwhatwillbedescribedthroughoutthischapter.NowthatyouhavebeenintroducedtoProtractor,therestofthechapterwillshowhowProtractorworksbehindthescenes,howtoinstallit,andfinally,walkyouthroughacompleteexampleusingTDD.

www.it-ebooks.info

Page 91: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

OriginsofProtractorProtractorisnotthefirstend-to-endtestingtoolthattheAngularJSteambuilt.ThefirsttoolwascalledScenarioRunner.InordertounderstandwhyProtractorwasbuilt,weneedtofirstlookatitspredecessor:ScenarioRunner.

www.it-ebooks.info

Page 92: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

EndoflifeScenarioRunnerisinmaintenancemodeandhasreacheditsendoflife.IthasbeendeprecatedinplaceofProtractor.Inthissection,wewilllookatwhatScenarioRunnerwasandwhatgapsthetoolhad.

www.it-ebooks.info

Page 93: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThebirthofProtractorJulieRalphistheprimarycontributortoProtractor.AccordingtoJulieRalph,themotivationforProtractorwasbasedonthefollowingexperiencewithAngularScenarioRunner,onanotherprojectwithinGoogle(http://javascriptjabber.com/106-jsj-protractor-with-julie-ralph/):

WetriedusingtheScenarioRunner.Andwefoundthatitreallyjustcouldn’tdothethingsthatweneededtotest.Weneededtotestthingslikeloggingin.Andyourloginpageisn’tanAngularpage.AndtheScenarioRunnercouldn’tdealwiththat.Anditcouldn’tdealwiththingslikepopupsandmultiplewindows,navigatingthebrowserhistory,stufflikethat.

BasedonherexperiencewithScenarioRunner,JulieRalphdecidedtocreateProtractortofillthegaps.

ProtractortakesadvantageofthematurityoftheSeleniumproject,andwrapsupitsmethodssothatitcanbeeasilyusedforAngularJSprojects.Remember,Protractorisabouttestingthroughtheeyesoftheuser.Itwasdesignedtotestalllayersofanapplication:WebUI,backendservices,persistencelayer,andsoon.

www.it-ebooks.info

Page 94: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

LifewithoutProtractorUnittestingisnottheonlytestingthatneedstobewrittenandmaintained.Unittestsfocusonsmallindividualcomponentsofanapplication.Bytestingsmallcomponents,theconfidenceinthecodeandlogicgrows.Unittestsdon’tfocusonhowthecompletesystemworkswheninterconnected.

End-to-endtestingwithProtractorallowsthedevelopertofocusonthecompletebehaviorofafeatureormodule.Goingbacktothesearchexample,thetestshouldonlypassifthewholeuserspecificationpasses;enterdataintothesearchbox,clickontheSearchbutton,andseetheresults.

Protractorisnottheonlyend-to-endtestingframeworkoutthere,butitisthebestchoiceforAngularJSapplications.HereareafewreasonswhyyoushouldchooseProtractor:

ItisdocumentedthroughouttheAngularJStutorialsandexamples.ItcanbewrittenusingmultipleJavaScripttestingframeworks,includingJasmineandMocha.ItprovidesconveniencemethodsforAngularJScomponents,includingwaitingforapagetoload,expectationsonpromises,andsoon.ItwrapsSeleniummethodsthatautomaticallywaitforpromisestobefulfilled.ItissupportedbySaaS(SoftwareasaService)providerssuchasSauceLabs,whichisavailableathttps://saucelabs.com/.ItissupportedandmaintainedbythesamecompanythatmaintainsAngularJSandGoogle.

www.it-ebooks.info

Page 95: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ProtractorinstallationIt’stimetostartgettingourhandsdirty,andinstallandconfigureProtractor.Installationsandapplicationsareconstantlychanging.Themainfocuswillbeonthespecificconfigurationusedinthisbook,andnotanin-depthinstallationguide.Thereareseveralvaryingdifferentconfigurations,sopleasereviewtheProtractorsiteforadditionaldetails.Pleasevisitthefollowingwebsitetofindthelatestinstallationandconfigurationguide:

http://angular.github.io/protractor/

Forthisbook,wewillonlybeusingthechromeOnlyconfiguration.ThechromeOnlyconfigurationdoesn’trequireseveralmovingparts,andallowsyoutogetuptospeedquickly.Asyourtestsgrowandyouarerequiredtosupportmultiplebrowsers,runningtestswithaSeleniumserverorusingsomethinglikeSauceLabsshouldbereviewed.AppendixA,IntegratingSeleniumServerwithProtractordescribeshowtosetupastandaloneSeleniumserver.

www.it-ebooks.info

Page 96: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InstallationprerequisitesProtractorhasthefollowingprerequisites:

Node.js:ProtractorisaNode.jsmoduleavailableusingnpm.ThebestwaytoinstallNode.jsistofollowtheinstructionsontheofficialsiteathttp://nodejs.org/download/.Chrome:ThisisawebbrowserbuiltbyGoogle.Itwillbeusedtorunend-to-endtestsinProtractorwithouttheneedforaSeleniumserver.Followtheinstallationinstructionsontheofficialsiteathttp://www.google.com/chrome/browser/.SeleniumWebDriverforChrome:Thisisatoolthatallowsyoutointeractwithwebapplications.SeleniumWebDriverisprovidedwiththeProtractornpmmodule.WewillwalkthroughtheinstructionsasweinstallProtractor.

www.it-ebooks.info

Page 97: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InstallingProtractorHerearethestepstoinstallProtractor:

1. OnceNode.jsisinstalledandavailableinthecommandprompt,typethefollowingcommandtoinstallProtractorinthecurrentdirectory:

$npminstallprotractor

ThepreviouscommandusesNode’snpmcommandtoinstallProtractorinthecurrentlocaldirectory.

2. Confirmthecurrentdirectorystructure:

TouseProtractorinthecommandprompt,usetherelativepathtotheProtractorbindirectory.

3. TestthattheProtractorversioncanbedeterminedasfollows:

$./node_modules/protractor/bin/protractor--version

InstallingWebDriverforChromeHerearethestepstoinstallWebDriverforChrome:

1. ToinstallSeleniumWebDriverforChrome,gotothewebdriver-managerexecutableintheProtractorbindirectorythatcanbefoundat./node_modules/protractor/bin/andtypethefollowing:

$./node_modules/protractor/bin/webdriver-managerupdate

2. Confirmthedirectorystructure.

ThepreviouscommandwillcreateaSeleniumdirectorycontainingtherequiredChromedriverusedintheproject.Thenode_modulesdirectoryshouldnowlooklikethefollowing:

www.it-ebooks.info

Page 98: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Theinstallationisnowcomplete.BothProtractorandSeleniumWebDriverforChromehavebeeninstalled.Wecannowmoveontotheconfiguration.

www.it-ebooks.info

Page 99: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CustomizingconfigurationInthissection,wewillbeconfiguringProtractorusingthefollowingsteps:

1. Startwithastandardtemplateconfiguration.

Fortunately,theProtractorinstallationcomeswithsomebaseconfigurationsinitsinstallationdirectory.Goingbacktothelocalnode_modulesdirectory,youshouldfindtheexampleChromeconfigurationintheexamplefolder:

Theexampledirectorycontainsexampleconfigurations.TheonethatwewilluseiscalledchromeOnlyConf.js.ThechromeOnlyconfigurationwillallowustorunend-to-endtestsinChromewithouttheneedforaSeleniumserver.Asdiscussedearlier,runningaSeleniumserverisanotheroptionthatwillnotbediscussedinthisbook.

2. Reviewtheexampleconfigurationfile:

ThechromeOnlyparametershouldbesettotrue,asfollows:

exports.config={

//...

chromeOnly:true,

//...

};

ThechromeDriverparameterwillhavetobemodifiedtopointtothedriverweinstalled,asfollows:

exports.config={

//...

chromeDriver:'../selenium/chromedriver',

//...

};

Thecapabilitiesparametershouldonlyspecifythenameofthebrowser:

exports.config={

//...

capabilities:{

'browserName':'chrome'

},

//...

www.it-ebooks.info

Page 100: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

};

Thefinalimportantconfigurationisthesourcefiledeclaration:

exports.config={

//...

specs:['example_spec.js'],

//...

};

Excellent!NowwehaveProtractorinstalledandconfigured.

ConfirminginstallationandconfigurationToconfirminstallation,Protractorrequiresatleastonefiledefinedinthespecsconfigurationsection.Beforeaddingarealtestandcomplicatingthings,createanemptyfileintherootdirectorycalledconfirmConfigTest.js.Then,addthetesttothespecssectionsoitlookslikethis:

specs:['confirmConfigTest.js'],

ToconfirmthatProtractorhasbeeninstalled,runProtractorbygoingtotherootofyourprojectdirectoryandtype:

$./node_modules/protractor/bin/protractorchromeOnlyConf.js

Ifeverythingwassetupcorrectlyandinstalled,youshouldseesomethingsimilartothisinyourcommandprompt:

Finishedin0.0002seconds

0tests,0assertions,0failures

Commoninstallation/configurationissuesThefollowingaresomecommonissuesthatyoumightcomeacrosswhileinstallingWebDriverforChrome:

Seleniumnotinstalledcorrectly:IfthetestshaveerrorsrelatedtotheSeleniumWebDriverlocation,youneedtoensurethatyoufollowedthestepstoupdateWebDriver.TheupdatestepdownloadstheWebDrivercomponentsintothelocalProtractorinstallationfolder.UntilWebDriverhasbeenupdated,youwon’tbeabletoreferenceitintheProtractorconfiguration.AneasywaytoconfirmtheupdateistolookintheProtractordirectoryandensurethataSeleniumfolderexists.Unabletofindtests:WhennotestsareexecutedbyProtractor,itcanbefrustrating.Thebestplacetostartisintheconfigurationfile.Makesuretherelativepathandanyfilenamesorextensionsarecorrect.

Foramorecompletelist,pleaserefertotheofficialProtractorsiteathttp://angular.github.io/protractor/.

www.it-ebooks.info

Page 101: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

HelloProtractorWiththeProtractorinstallationandconfigurationcomplete,youcanlookatwritingarealtest.ThissectionwillwalkyouthroughusingTDDwithProtractor.Attheendofthischapter,youshouldbeableto:

FeelconfidentinusingandconfiguringProtractorUnderstandthebasiccomponentsofaProtractortestStarttounderstandhowtointegrateaTDDapproachtoend-to-endtesting

www.it-ebooks.info

Page 102: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TDDend-to-endTest-drivendevelopmentisnotasilverbullet.Itisafoundationofprinciplesandtechniquesusedtoimproveefficiency,quality,andmuchmore.KnowinghowtoapplyTDDisthefirststep,butknowingwhentoapplyitisjustasimportant.

WhenapplyingTDD,youarecouplingteststoyourlogicandcode.Asadeveloper,youhavetomakedecisionsonwhenthatcouplingmakessenseandwillbeadvantageoustoyourproject.Asyouworkthroughtheexamples,beawarethattheyshowyouhowtoapplyTDDtechniques.Asyouusethesepracticesinyourownprojects,youwillneedtodeterminethedepthandcouplingoftheteststhatyourprojectandspecificationsrequire.

Thepre-setupThecodeinthistestwillleveragetheunittestedcodefromChapter2,TheKarmaWay.Youwillneedtocopythecodetoanewdirectory.

Asareminder,theapplicationwasato-doapplicationthataddsanddeletesitemsfromalist.Ithasasinglecontroller,TodoController,thathasalistofitemsandanaddmethod.Theapplicationdidn’thaveanyHTMLorusercomponents.WewilluseaTDDapproachtoaddtheUIelements.Thecurrentcodedirectoryshouldbestructuredasfollows:

www.it-ebooks.info

Page 103: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThesetupThesetupwillmirrortheinstallationandconfigurationstepsfromearlier:

1. InstallProtractor.2. UpdateSeleniumWebDriver.3. ConfigureProtractorbasedontheexampleconfiguration.

FollowtheProtractorinstallationandconfigurationstepsyoulearnedintheprevioussectioninanewprojectdirectory.TheonlydifferenceisthattheProtractortestsshouldbeplacedinaspec/e2edirectory.Thiswillallowyoutoeasilyidentifythetestsinyourprojectstructure.Aftercreatingaspec/e2edirectoryupdate,theProtractorconfigurationspecsectionshouldbeasfollows:

exports.config={

//...

specs:['spec/e2e/**/*.js'],

//...

};

AfterconfirmingthatProtractorhasbeeninstalledandconfiguredproperly,youcanstartthefirsttest.

www.it-ebooks.info

Page 104: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestfirstNowthatProtractorhasbeensetup,thetestingcanbegin.End-to-endtestsareslowandtouchmultiplelayersoftheapplication.Theyalsorequirethefullapplicationtobesetupandrunninginordertotest.Thereareseveraltechniquesthatwecanleveragetomockalocalenvironment.MockingdataandAPIswillbediscussedinChapter7,GiveMeSomeData.Thisfirstend-to-endtestwillonlyhaveaWebUIlayer.Noadditionalmockingwillberequired.

Asmentionedearlier,Protractorrequiresarunningapplication.Thismeansthewebsiteneedstobeavailableforyoutopointyourbrowsertoit.AsimpleapproachtoservingstaticHTTPcontentistousethehttp-servernpmmodule.Thehttp-servermoduleisperfectforalocaldevelopmentenvironment,butprobablynotsuitedforthefinalapplicationinfrastructure.YourproductionwebsitemightbedevelopedinsomethinglikeExpress,IIS,orApache.

InstallingthetestwebserverToinstallourtestwebserver,wewillusethehttp-servernodemodule.Theadvantageofawebserversuchashttp-serveristhatitrequiresverylittleconfigurationandcanjuststartandrunthewebsite.Herearethestepstoinstallthewebserver:

1. Typethefollowingcommandinthecommandline:

$npminstallhttp-server

2. Nowcreateastubindex.htmlpageattherootoftheprojectwiththebasicHTMLcomponents:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

</body>

</html>

3. NowruntheHTTPserverandensurethepageisloaded:

./node_modules/http-server/bin/http-server-p8080

4. Gotohttp://localhost:8080.Youshouldseeablankpagegetloaded,withnoerrorsinthecommandoronthewebpage.Ifyouseeerrors,ensurethatthedirectoryhastherequiredindex.htmlfile.Nowthatyouhaveaworkingwebsite,itistimetoconfigureProtractortouseit.

ConfiguringProtractorProtractorcanbeconfiguredwithabaseURLforanapplication.Byspecifyingabase

www.it-ebooks.info

Page 105: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

URL,testswilllookcleanerandcanbeeasilyconfiguredtousedifferentURLsforthesameapplication.Imagineadev,qa,andproductionURLthatusethesametests,buthavedifferentURLsthatneedtobetested.

Aswewillberunningthislocally,wewillneedtousehttp://localhost:8000asourbaseURL.UpdatetheProtractorconfigurationfileasfollows:

baseUrl:'http://localhost:8080/'

GettingdowntobusinessEnd-to-endtestingisdifferentthanunittesting.Testswillinteractwithdifferentlayersofanapplicationthroughoutasinglescenario.YoumayhaveanotherteamdesigningtheHTMLelements,CSS,andsoon.ThedevelopmentteamwillthenhavetointegratetheUIHTMLintothepage.TheTDDapproachwillallowyoutocreatetestsforseparatecomponentsindependently.Theideaisyouwanttobeabletestthefeaturesoftheapplicationthatmakesensetotest.Testingeverythingblindlycanbeawasteoftimeandarefactoringnightmare.

Inthiscase,westartwithablankcanvasofapageandwanttotestthebehavioroftheprimarycomponents.WewillfollowtheTDDlifecycle(test,execute,refactor).Intheupcomingsections,wewillcoverthefollowingsteps:

1. Reviewtheuserspecification.2. Writedownthemaintasksthatneedtobedeveloped.3. Writethetestforwhatwillbedeveloped.

Specification

Thepurposeofthisfirsttestistomanageadynamicto-dolist.

Thedevelopmentto-dolist

Wewillneedadevelopmentto-dolisttosetourfocusandorganizeourdevelopmenttasks.Performthefollowingsteps:

1. Viewtheto-dolistitems

Examplelist:test,execute,refactor

2. Addanitemtotheto-dolist

Examplelist:test,execute,refactor,repeat

3. Removeanitemfromtheto-dolist

Examplelist:test,execute,refactor

Ifyourecall,inourpreviousexample,wesetupthebackendmodulefortheto-dolistapplication.Inthiscase,wewillfocusonmanagingthelistfromtheuser’sperspective.

Testfirst

www.it-ebooks.info

Page 106: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

JustaswediscussedwiththeKarmatest,startwiththe3A’s(Assemble,Act,Assert).ProtractortestsarewritteninthesameJasminestyleandsetup,soyoudon’thavetolearnanynewsyntax.StartwiththebasicJasminetemplateformat:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

describe:Thisdefinesthemainfeaturewetest.Thefirstparameterisastringtoexplainthefeatureandthesecondparameteristhefunctionthatcontainstheteststeps.beforeEach:ThisisthetestsetupandAssemblesection.ThefunctiondefinedinbeforeEachwillbeexecutedbeforeeveryAssert.Thisiswhereweperformanysetupmocks,spies,andothercomponentsneededtotest.it:ThisistheActandAssertsection.Inthissection,youwillperformtheactualactionbeingtested,followedbyanassertion.

Assemble,Act,Assert(3A’s)

Followthe3A’smantra:

Assemble:Asthisisanend-to-endtest,wewillinitializebydirectingthetesttogotothepageundertest.Inthiscase,thepageis/.ThisisbecausewesetthebaseURLtobehttp://localhost:8080/intheconfigurationfile.Sothecodewilllooklikethefollowing:

beforeEach(function(){

browser.get('/');

});

Act:Inthefirsttest,toviewalistofto-doitems,thereisnobuttontobeclickedoractiontobedoneinordertogetthelist.Weshouldjustbrowsetothepageandseethelistofto-doitems.Assert:Thisisourfirstfailingtest,whichwewillwriteusingProtractor.Thetestneedstodeterminewhetherthelistofto-doitems,thatistest,execute,andrefactor,isavailableonthepage.InAngularJS,thiswillbedoneusingng-repeat,meaningeachiteminalistwillberepeatedwithsomespecialHTMLtodisplayanindividualitem.

AsProtractoristestingtheactualUI,youwillneedtohavetheabilitytoselectHTMLelements.OneofthebenefitsofProtractoristhatitwrapsupAngularJScomponentssothattheycanbeeasilytested.

Intheprecedingtest,wewillusetheelementselectorwiththeby.repeaterselection.Inourcase,thefirstassertionwilllooklikethis:

it('',function(){

vartodoListItems=element.all(by.repeater('iteminlist'));

expect(todoListItems.count()).toBe(3);

www.it-ebooks.info

Page 107: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

});

Thefirstlinewillselecttheto-dolistitemsavailableonthepage.ThesecondwillAssertthattheitemcountis3.Whenrunningthetest,ensurethewebserverisstillrunningusingthefollowingcommand:

$./node_modules/http-server/bin/http-server-p8080

Thecompletedtestlooksasfollows:

describe('',function(){

//ASSEMBLE

beforeEach(function(){

//ACT

browser.get('/');

});

it('',function(){

vartodoListItems=element.all(by.repeater('iteminlist'));

//ASSERT

expect(todoListItems.count()).toBe(3);

});

});

Runningthetest

Thestepstorunatestareasfollows:

1. RuntheProtractortestinadifferentcommandprompt,usingthefollowingcommand:

$protractorchromeOnlyConf.js

2. TheoutputshouldsaythatAngularJScouldnotbefound:

$Error:Angularcouldnotbefoundonthepagehttp://localhost:8080/

:retrieslookingforangularexceeded

Thiserrorindicatesthattheassertionsfailed.

3. Whenrunningthetest,youshouldseeaChromepop-upwiththepage.Youshouldalsoseethattheoutputfromthewebserversayssomethinglikethefollowing:

GET/”“Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/36.0.1985.125Safari/537.36

Excellent!Nowyou’vegotafailingProtractortest,itistimetomakeitrun.

Makeitrun

ThenextstepintheTDDlifecycleistoexecuteandfixthecodesothatthetestspass.Asyouwalkthroughthetest,remembertousethesmallestcomponentsthatcanbeaddedtomakethetestpass:

1. Asthefirsterrorsays,Angularcan'tbefound.AddAngularJStothepagejustbeforetheclosingtagforthebodyasfollows:

//...

www.it-ebooks.info

Page 108: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

<scriptsrc="bower_components/angular/angular.js"></script>

</body>

//...

2. Rerunthetestusingthefollowingcommand:

$protractorchromeOnlyConf.js

Theoutputshouldnowdisplaythefollowing:

$Error:Angularcouldnotbefoundonthepagehttp://localhost:8080/

:angularneverprovidedresumeBootstrap

3. Sinceyouhaven’tspecifiedtheapplicationoraddedthetodo.jspage,let’saddthesecomponentstoitaftertheAngularJSscript:

//...

<bodyng-app="todo">

<scriptsrc="bower_components/angular/angular.js"></script>

<scriptsrc="app/todo.js"></script>

//...

4. Rerunthetestusingthefollowingcommand:

$protractorchromeOnlyConf.js

Theoutputshouldnowdisplaythatourexpectationsfailed:

$Expected0tobe3.

Great!Nowtherearenomoreexecutionerrorsinourpage,onlythefailedexpectationsonthenumberoflistitems.

5. Inordertoaddtheitemstothepage,wewillneedtoaddareferencetoTodoController,andthenaddng-repeatforeachitem.Thecodeintheindex.htmlpageshouldbeasfollows:

<divng-controller="TodoController">

<ulng-repeat="iteminlist">

<li>{{item}}</li>

</ul>

</div>

6. Rerunthetestasfollows:

$protractorchromeOnlyConf.js

Theoutputshouldnowdisplaythatourassertionandtestpassed:

$1test,1assertion,0failures

Thecompletedpagebodytagwillnowlookasfollows:

<bodyng-app="todo">

<divng-controller="TodoController">

<ulng-repeat="iteminlist">

<li>{{item}}</li>

www.it-ebooks.info

Page 109: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

</ul>

</div>

<scriptsrc="bower_components/angular/angular.js"></script>

<scriptsrc="app/todo.js"></script>

</body>

Makeitbetter

Thereisnothingthatwascalledouttorefactor.Lookingatourto-dolist,wetackledthefirsttwoitemsfromanend-to-endperspective.

1. Viewtheto-do-listitems:

Examplelist:test,execute,refactor

2. Addanitemtoato-do-list:

Examplelist:test,execute,refactor,repeat

3. Removeanitemfromato-do-list:

Examplelist:test,execute,refactor

Iwillleavethesecondandthirditemsasanexercise,sothatyoucanfurtherexploreandpracticeTDDwithProtractor.

www.it-ebooks.info

Page 110: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CleaningupthegapsThereareacoupleofthingsthatwerediscussedinthischapterthatneedsomefurtherclarification.Thisincludesthefollowing:

Whereistheasynchronouslogic?HowtoreallyimplementTDDwithend-to-endtests.

www.it-ebooks.info

Page 111: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AsyncmagicIntheprecedingtests,wesawsomemagicthatyoumightbequestioning.Herearesomeofthemagiccomponentsthatweglancedover:

LoadingapagebeforetestexecutionAssertiononelementsthatgetloadedinpromises

LoadingapagebeforetestexecutionIntheprevioustest,weusedthefollowingcodetospecifythatthebrowsershouldpointtothehomepage:

browser.get('/');

TheprecedingcommandwilllaunchthebrowserandnavigatetothebaseUrllocation.Oncethebrowserreachesthepage,itwillhavetoloadAngularJSandthenimplementtheAngularJS-specificfunctions.Ourtestsdon’thaveanywaitlogic,andthisispartofthebeautyofProtractorwithAngularJS.Thewaitingforpageloadingisalreadybuiltintheframeworkforyou.Yourtestscanthenbewrittenverycleanly.

AssertiononelementsthatgetloadedinpromisesTheassertionsandexpectationsalreadyhavepromisefulfillmentwritteninthem.Inthecaseofourtest,wewrotetheassertionsothatitexpectsthecounttobethree:

expect(todoListItems.count()).toBe(3);

However,inreality,wemayhavethoughtthatweneededtoaddasynchronoustestingtotheassertioninordertowaitforthepromisetobefulfilled,somethingmorecomplicatedlikethefollowing:

it('',function(done){

vartodoListItems=element.all(by.repeater('iteminlist'));

todoListItems.count().then(function(count){

expect(count).toBe(3);

done();

});

})

Theprecedingcodeislonger,moregranular,andhardertoread.Protractorhastheabilityforcertainelementsbuiltintoexpectationstomaketestsmoreconcise.

www.it-ebooks.info

Page 112: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TDDwithProtractorWithourfirsttest,thereisacleardistinctionofend-to-endtestsandunittests.Withtheunittest,wefocusedonstrongcouplingthetesttothecode.Asanexample,ourunittestspiedonthescopeforaspecificcontroller,TodoController.WeusedAngularmockstoinitializethescopewithavariablewecouldthenevaluate:

inject(function($controller){

$controller('TodoController',{$scope:scope});

});

IntheProtractortest,wedon’tcareaboutwhichcontrollerwearetestingandourfocusisontheuserperspectiveofthetest.WefirststartwiththeselectionofaparticularelementwithintheDocumentObjectModel(DOM);inourcase,thatelementistiedtoAngularJS,ng-repeat.TheAssertisthatthenumberofelementsforaspecificrepeaterisequaltotheexpectedcount.

Withtheloosecouplingoftheend-to-endtest,wecanwriteatestthatfocusesontheuserspecification,whichinitiallydisplaysthreeelements,andthenhavethefreedomtowritethatinthepage,controllers,andsoon,inanywaywewant.

www.it-ebooks.info

Page 113: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsUseTDDwithProtractortodevelopthethirddevelopmentto-dolistitem:

Q1.Protractoruseswhichofthefollowingframeworks?

1. Selenium2. Unobtanium3. Karma

Q2.YoucaninstallAngularmocksbyrunningbowerinstallangular-mocks.

1. True2. False

Q3.WhatstepsdoestheTDDlifecycle,discussedinthisbook,consistof?

1. Testfirst,makeitrun,makeitbetter(refactor)2. Test,makeitbetter(refactor),makeitrun3. Makeitrun,test,makeitbetter

Additionally,ifyouwantmorepractice,addafunctionalitytotheapplicationtoremoveanitemfromtheto-dolist.

www.it-ebooks.info

Page 114: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThischapterhasgivenyoutheskillsnecessarytoinstall,configure,andapplyTDDprinciplestoend-to-endtesting.WehaveseenhowwecanleveragetheexistingTDDlifecycle(test,makeitrun,makeitbetter)andtechniqueswithProtractor.ProtractorisanimportantpartoftestinganyAngularJSapplication.Itbridgesthegaptoensuretheuser’sspecificationsworkasexpected.Whenend-to-endtestsarewrittentotheuserspecifications,theconfidenceoftheapplicationandabilitytorefactorgrows.Intheupcomingchapters,wewillseehowtoapplyKarmaandProtractorinmoredepthwithsimplestraightforwardexamples.Thenextchapterwillwalkyouthroughtestingcontrollers,usingAngularmocks,andusingProtractortoenterkeystrokes.

www.it-ebooks.info

Page 115: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter4.TheFirstStepThefirststepisalwaysthehardest.Thischapterprovidesaninitialintroductorywalk-throughofhowtouseTDDtobuildanAngularJSapplicationwithacontroller,model,andscope.YouwillbeabletobegintheTDDjourneyandseethefundamentalsinaction.Uptothispoint,thisbookhasfocusedonafoundationofTDDandthetools.Now,wewillswitchgearsanddiveintoTDDwithAngularJS.ThischapterwillbethefirststepofTDD.WehavealreadyseenhowtoinstallKarmaandProtractor,inadditiontosmallexamplesandawalk-throughonhowtoapplyit.Thischapterwillfocusonthecreationofsocialmediacomments.ItwillalsofocusonthetestingassociatedwithcontrollersandtheuseofAngularmockstoAngularJScomponentsinatest.

www.it-ebooks.info

Page 116: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Preparingtheapplication’sspecificationCreateanapplicationtoentercomments.Thespecificationoftheapplicationisasfollows:

GivenIampostinganewcomment,whenIclickonthesubmitbutton,thecommentshouldbeaddedtotheto-dolistGivenacomment,whenIclickonthelikebutton,thenumberoflikesforthecommentshouldbeincreased

Nowthatwehavethespecificationofapplication,wecancreateourdevelopmentto-dolist.Itwon’tbeeasytocreateanentireto-dolistofthewholeapplication.Basedontheuserspecifications,wehaveanideaofwhatneedstobedeveloped.HereisaroughsketchoftheUI:

Holdyourselfbackfromjumpingintotheimplementationandthinkingabouthowyouwilluseacontrollerwithaservice,ng-repeat,andsoon.Resist,resist,resist!Althoughyoucanthinkofhowthiswillbedevelopedinthefuture,itisneverclearuntilyoudelveintothecode,andthatiswhereyoustartgettingintotrouble.TDDanditsprinciplesareheretohelpyougetyourmindandfocusintherightplace.

www.it-ebooks.info

Page 117: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettinguptheprojectInpreviouschapters,wediscussedindetailhowaprojectshouldbesetup,explainedthedifferentcomponentsinvolved,andwalkedthroughtheentireprocessoftesting.Iwillskipthesedetailsandprovidealistinthefollowingsectionfortheinitialactionstogettheprojectsetup.

www.it-ebooks.info

Page 118: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingupthedirectoryThefollowinginstructionsarespecifictosettinguptheprojectdirectory:

1. Createanewprojectdirectory.2. GetangularintotheprojectusingBower:

bowerinstallangular

3. Getangular-mocksfortestingusingBower:

bowerinstallangular-mocks

4. Initializetheapplication’ssourcedirectory:

mkdirapp

5. Initializethetestdirectory:

mkdirspec

6. Initializetheunittestdirectory:

mkdirspec/unit

7. Initializetheend-to-endtestdirectory:

mkdirspec/e2e

Oncetheinitializationiscomplete,yourfolderstructureshouldlookasfollows:

www.it-ebooks.info

Page 119: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingupProtractorInChapter3,End-to-endTestingwithProtractor,wediscussedthefullinstallationandsetupofProtractor.Inthischapter,wewilljustdiscussthestepsatahigherlevel:

1. InstallProtractorintheproject:

$npminstallprotractor

2. UpdateSeleniumWebDriver:

$./node_modules/protractor/bin/webdriver-managerupdate

MakesurethatSeleniumhasbeeninstalled.

3. CopytheexamplechromeOnlyconfigurationintotherootoftheproject:

$cp./node_modules/protractor/example/chromeOnlyConf.js.

4. ConfiguretheProtractorconfigurationusingthefollowingsteps:

1. OpentheProtractorconfiguration.2. EdittheSeleniumWebDriverlocationtoreflecttherelativedirectoryto

chromeDriver:

chromeDriver:'./node_modules/protractor/selenium/chromedriver',

3. Editthefilessectiontoreflectthetestdirectory:

specs:['spec/e2e/**/*.js'],

5. SetthedefaultbaseURL:

baseUrl:'http://localhost:8080/',

Excellent!Protractorshouldnowbeinstalledandsetup.Hereisthecompleteconfiguration:

exports.config={

chromeOnly:true,

chromeDriver:'./node_modules/protractor/selenium/chromedriver',

capabilities:{

'browserName':'chrome'

},

baseUrl:'http://localhost:8080/',

specs:['spec/e2e/**/*.js'],

};

www.it-ebooks.info

Page 120: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingupKarmaThedetailsforKarmacanbefoundinChapter2,TheKarmaWay.Hereisabriefsummaryofthestepsrequiredtoinstallandgetyournewprojectsetup:

1. InstallKarmausingthefollowingcommand:

npminstallkarma-g

2. InitializetheKarmaconfiguration:

karmainit

3. UpdatetheKarmaconfiguration:

files:[

'bower_components/angular/angular.js',

'bower_components/angular-mocks/angular-mocks.js',

'spec/unit/**/*.js'

],

NowthatwehavesetuptheprojectdirectoryandinitializedProtractorandKarma,wecandiveintothecode.Hereisthecompletekarma.conf.jsfile:

module.exports=function(config){

config.set({

basePath:'',

frameworks:['jasmine'],

files:[

'bower_components/angular/angular.js',

'bower_components/angular-mocks/angular-mocks.js',

'spec/unit/**/*.js'

],

reporters:['progress'],

port:9876,

autoWatch:true,

browsers:['Chrome'],

singleRun:false

});

};

www.it-ebooks.info

Page 121: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Settinguphttp-serverAwebserverwillbeusedtohosttheapplication.Asthiswilljustbeforlocaldevelopmentonly,youcanusehttp-server.Thehttp-servermoduleisasimpleHTTPserverthatservesstaticcontent.Itisavailableasannpmmodule.Toinstallhttp-serverinyourproject,typethefollowingcommand:

$npminstallhttp-server

Oncehttp-serverisinstalled,youcanruntheserverbyprovidingitwiththerootdirectoryofthewebpage.Hereisanexample:

$./node_modules/http-server/bin/http-server

Nowthatyouhavehttp-serverinstalled,youcanmoveontothenextstep.

www.it-ebooks.info

Page 122: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Top-downorbottom-upapproachFromourdevelopmentperspective,wehavetodeterminewheretostart.Theapproachesthatwewilldiscussinthisbookareasfollows:

Thebottom-upapproach:Withthisapproach,wethinkaboutthedifferentcomponentswewillneed(controller,service,module,andsoon)andthenpickthemostlogicaloneandstartcoding.Thetop-downapproach:Withthisapproach,weworkfromtheuserscenarioandUI.Wethencreatetheapplicationaroundthecomponentsintheapplication.

Therearemeritstobothtypesofapproachesandthechoicecanbebasedonyourteam,existingcomponents,requirements,andsoon.Inmostcases,itisbestforyoutomakethechoicebasedontheleastresistance.Inthischapter,theapproachofspecificationistop-down,everythingislaidoutforusfromtheuserscenarioandwillallowyoutoorganicallybuildtheapplicationaroundtheUI.

www.it-ebooks.info

Page 123: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingacontrollerBeforegettingintothespecification,andthemind-setofthefeaturebeingdelivered,itisimportanttoseethefundamentalsoftestingacontroller.AnAngularJScontrollerisakeycomponentusedinmostapplications.

www.it-ebooks.info

Page 124: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AsimplecontrollertestsetupWhentestingacontroller,testsarecenteredonthecontroller’sscope.Thetestsconfirmeithertheobjectsormethodsinthescope.Angularmocksprovideinject,whichfindsaparticularreferenceandreturnsitforyoutouse.Wheninjectisusedforthecontroller,thecontrollersscopecanbeassignedtoanouterreferencefortheentiretesttouse.Hereisanexampleofwhatthiswouldlooklike:

describe('',function(){

varscope={};

beforeEach(function(){

module('anyModule');

inject(function($controller){

$controller('AnyController',{$scope:scope});

});

});

});

Intheprecedingcase,thetest’sscopeobjectisassignedtotheactualscopeofthecontrollerwithintheinjectfunction.Thescopeobjectcannowbeusedthroughoutthetest,andisalsoreinitializedbeforeeachtest.

www.it-ebooks.info

Page 125: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InitializingthescopeIntheprecedingexample,scopeisinitializedtoanobject{}.Thisisnotthebestapproach;justlikeapage,acontrollermightbenestedwithinanothercontroller.Thiswillcauseinheritanceofaparentscopeasfollows:

<bodyng-app='anyModule'>

<divng-controller='ParentController'>

<divng-controller='ChildController'>

</div>

</div>

</body>

Asseenintheprecedingcode,wehavethishierarchyofscopesthattheChildControllerfunctionhasaccessto.Inordertotestthis,wehavetoinitializethescopeobjectproperlyintheinjectfunction.Hereishowtheprecedingscopehierarchycanberecreated:

inject(function($controller,$rootScope){

varparentScope=$rootScope.$new();

$controller('ParentController',{$scope:parentScope});

varchildScope=parentScope.$new();

$controller('AnyController',{$scope:childScope});

});

Therearetwomainthingsthattheprecedingcodedoes:

The$rootScopescopeisinjectedintothetest.The$rootScopescopeisthehighestlevelofscopethatexists.Eachlevelofscopeiscreatedwiththe$new()method.Thismethodcreatesthechildscope.

Inthischapter,wewillusethesimplifiedversionandinitializethescopetoanemptyobject;however,itisimportanttounderstandhowtocreatethescopewhenrequired.

www.it-ebooks.info

Page 126: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

BringonthecommentsNowthatthesetupandapproachhavebeendecided,wecanstartourfirsttest.Fromatestingpointofview,aswewillbeusingatop-downapproach,wewillwriteourProtractortestsfirstandthenbuildtheapplication.WewillfollowthesameTDDlifecyclewehavealreadyreviewed,thatis,testfirst,makeitrun,andmakeitbetter.

www.it-ebooks.info

Page 127: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestfirstThescenariogivenisinawell-specifiedformatalreadyandfitsourProtractortestingtemplate:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

Placingthescenariointhetemplate,wegetthefollowingcode:

describe('GivenIampostinganewcomment',function(){

describe('WhenIpushthesubmitbutton',function(){

beforeEach(function(){

});

it('Shouldthenaddthecomment',function(){

});

});

});

Followingthe3A’s(Assemble,Act,Assert),wewillfittheuserscenariointhetemplate.

AssembleThebrowserwillneedtopointtothefirstpageoftheapplication.AsthebaseURLhasalreadybeendefined,wecanaddthefollowingtothetest:

beforeEach(function(){

browser.get('/');

});

Nowthatthetestisprepared,wecanmoveontothenextstep,Act.

ActThenextthingweneedtodo,basedontheuserspecification,isaddanactualcomment.Theeasiestthingistojustputsometextintoaninputbox.Thetestforthis,againwithoutknowingwhattheelementwillbecalledorwhatitwilldo,istowriteitbasedonwhatitshouldbe.

Hereisthecodetoaddthecommentsectionfortheapplication:

beforeEach(function(){

...

varcommentInput=$('input');

commentInput.sendKeys('acomment');

});

Thelastassemblecomponent,aspartofthetest,istopushtheSubmitbutton.ThiscanbeeasilyachievedinProtractorusingtheclickfunction.Eventhoughwedon’thaveapageyet,oranyattributes,wecanstillnamethebuttonthatwillbecreated:

www.it-ebooks.info

Page 128: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

beforeEach(function(){

...

varsubmitButton=element.all(by.buttonText('Submit')).click();

});

Finally,wewillhitthecruxofthetestandasserttheusers’expectations.

AssertTheuserexpectationisthatoncetheSubmitbuttonisclicked,thecommentisadded.Thisisalittleambiguous,butwecandeterminethatsomehowtheuserneedstogetnotifiedthatthecommentwasadded.Thesimplestapproachistodisplayallcommentsonthepage.InAngularJS,theeasiestwaytodothisistoaddanng-repeatobjectthatdisplaysallcomments.Totestthis,wewilladdthefollowing:

it('Shouldthenaddthecomment',function(){

varcomments=element(by.repeater('commentincomments')).first();

expect(comment.getText()).toBe('acomment');

});

Now,thetesthasbeenconstructedandmeetstheuserspecifications.Itissmallandconcise.Hereisthecompletedtest:

describe('GivenIampostinganewcomment',function(){

describe('WhenIpushthesubmitbutton',function(){

beforeEach(function(){

//Assemble

browser.get('/');

varcommentInput=$('input');

commentInput.sendKeys('acomment');

//Act

//Act

varsubmitButton=element.all(by.buttonText('Submit')).

click();

});

//Assert

it('Shouldthenaddthecomment',function(){

varcomments=element(by.repeater('commentin

comments')).first();

expect(comment.getText()).toBe('acomment');

});

});

});

www.it-ebooks.info

Page 129: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitrunBasedontheerrorsandoutputofthetest,wewillbuildourapplicationaswego.

1. Thefirststeptomakethecoderunistoidentifytheerrors.Beforestartingoffthesite,let’screateabarebonesindex.htmlpage:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

</body>

</html>

Alreadyanticipatingthefirsterror,addAngularJSasadependencyinthepage:

<scripttype='text/javascript'

src='bower_components/angular/angular.js'></script>

</body>

2. Now,startingthewebserverusingthefollowingcommand:

$./node_modules/http-server/bin/http-server-p8080

3. RunProtractortoseethefirsterror:

$./node_modules/.bin/protractorchromeOnlyConf.js

4. OurfirsterrorstatesthatAngularJScouldnotbefound:

Error:Angularcouldnotbefoundonthepagehttp://localhost:8080/:

angularneverprovidedresumeBootstrap

Thisisbecauseweneedtoaddng-apptothepage.Let’screateamoduleandaddittothepage.

ThecompleteHTMLpagenowlooksasfollows:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

<scriptsrc="bower_components/angular/angular.js"></script>

</body>

</html>

AddingthemoduleThefirstcomponentthatyouneedtodefineisanng-appattributeintheindex.htmlpage.

www.it-ebooks.info

Page 130: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Usethefollowingstepstoaddthemodule:

1. Addng-appasanattributetothebodytag:

<bodyng-app='comments'>

2. Now,wecangoaheadandcreateasimplecommentsmoduleandaddittoafilenamedcomments.js:

angular.module('comments',[]);

3. Addthisnewfiletoindex.html:

<scriptsrc='app/commentController.js'></script>

4. ReruntheProtractortesttogetthenexterror:

$Error:Noelementfoundusinglocator:By.cssSelector('input')

Thetestcouldn’tfindourinputlocator.Youneedtoaddtheinputtothepage.

AddingtheinputHerearethestepsyouneedtofollowtoaddtheinputtothepage:

1. Allwehavetodoisaddasimpleinputtagtothepage:

<inputtype='text'/>

2. Runthetestandseewhatthenewoutputis:

$Error:Noelementfoundusinglocator:by.buttonText('Submit')

3. Justlikethepreviouserror,weneedtoaddabuttonwiththeappropriatetext:

<buttontype='button'>Submit</button>

4. Runthetestagainandthenexterrorisasfollows:

$Error:Noelementfoundusinglocator:by.repeater('commentin

comments')

Thisappearstobefromourexpectationthatasubmittedcommentwillbeavailableonthepagethroughng-repeat.Toaddthistothepage,wewilluseacontrollertoprovidethedatafortherepeater.

ControllerAswementionedintheprecedingsection,theerrorisbecausethereisnocommentsobject.Inordertoaddthecommentsobject,wewilluseacontrollerthathasanarrayofcommentsinitsscope.Usethefollowingstepstoaddacommentsobjectinthescope:

1. CreateanewfileintheappdirectorynamedcommentController.js:

angular.module('comments')

.controller('CommentController',['$scope',function($scope){

www.it-ebooks.info

Page 131: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

$scope.comments=[];

}])

2. AddittothewebpageaftertheAngularJSscript:

<scriptsrc='app/commentController.js'></script>

3. Now,wecanaddcommentControllertothepage:

<divng-controller='CommentController'>

4. Then,addarepeaterforthecommentsasfollows:

<ulng-repeat='commentincomments'>

<li>{{comment}}</li>

</ul>

5. RuntheProtractortestandlet’sseewhereweare:

$Error:Noelementfoundusinglocator:by.repeater('commentin

comments')

Hmmm!Wegetthesameerror.

6. Let’slookattheactualpagethatgetsrenderedandseewhat’sgoingon.InChrome,gotohttp://localhost:8080andopentheconsoletoseethepagesource(Ctrl+Shift+J).Youshouldseesomethinglikewhat’sshowninthefollowingscreenshot:

Noticethattherepeaterandcontrollerareboththere;however,therepeateriscommentedout.SinceProtractorisonlylookingatvisibleelements,itwon’tfindtherepeater.

7. Great!Nowweknowwhytherepeaterisn’tvisible,butwehavetofixit.Inorderforacommenttoshowup,ithastoexistonthecontroller’scommentsscope.Thesmallestchangeistoaddsomethingtothearraytoinitializeitasshowninthefollowingcodesnippet:

.controller('CommentController',['$scope',function($scope){

$scope.comments=['anything'];

www.it-ebooks.info

Page 132: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

}]);

8. Nowrunthetestandwegetthefollowing:

$Expected'anything'tobe'acomment'.

Wow!Wefinallytackledalltheerrorsandreachedtheexpectation.HereiswhattheHTMLcodelookslikesofar:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<bodyng-app='comments'>

<divng-controller='CommentController'>

<inputtype='text'/>

<ul>

<ling-repeat='commentincomments'>

{{comment.value}}

</li>

</ul>

</div>

<scriptsrc='bower_components/angular/angular.js'></script>

<scriptsrc='app/comments.js'></script>

<scriptsrc='app/commentController.js'></script>

</body>

</html>

Thecomments.jsmodulelooksasfollows:

angular.module('comments',[]);

HereiscommentController.js:

angular.module('comments')

.controller('CommentController',['$scope',function($scope){

$scope.comments=[];

}])

MakeitpassWithTDD,youwanttoaddthesmallestpossiblecomponenttomakethetestpass.Sincewehavehardcoded,forthemoment,thecommentstobeinitializedtoanything,changeanythingtoacomment;thisshouldmakethetestpass.Hereisthecodetomakethetestpass:

angular.module('comments')

.controller('CommentController',['$scope',function($scope){

$scope.comments=['acomment'];

}]);

Runthetest,andbam!Wegetapassingtest:

www.it-ebooks.info

Page 133: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

$1test,1assertion,0failures

Waitasecond!Westillhavesomeworktodo.Althoughwegotthetesttopass,itisnotdone.Weaddedsomehacksjusttogetthetestpassing.Thetwothingsthatstandoutare:

ClickingontheSubmitbutton,whichreallydoesn’thaveanyfunctionalityHardcodedinitializationoftheexpectedvalueforacomment

Theprecedingchangesarecriticalstepsweneedtoperformbeforewemoveforward.TheywillbetackledinthenextphaseoftheTDDlifecycle,thatis,makeitbetter(refactor).

www.it-ebooks.info

Page 134: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitbetterThetwocomponentsthatneedtobereworkedare:

AddingbehaviortotheSubmitbuttonRemovinghardcodedvalueofthecomments

www.it-ebooks.info

Page 135: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ImplementingtheSubmitbuttonTheSubmitbuttonneedstoactuallydosomething.Wewereabletosidesteptheimplementationbyjusthardcodingthevalue.UsingourtriedandtrustedTDDtechniques,switchtoanapproachfocusedonunittesting.Sofar,thefocushasbeenontheUIandpushingchangestothecode.Wehaven’twrittenasingleunittest.

Forthisnextbitofwork,wewillswitchgearsandfocusondrivingthedevelopmentoftheSubmitbuttonthroughtests.WewillbefollowingtheTDDlifecycle(testfirst,makeitrun,makeitbetter).

ConfiguringKarmaWedidsomethingverysimilarfortheto-dolistapplicationinChapter2,TheKarmaWay.Iwon’tspendasmuchtimedivingintothecode,sopleasereviewthepreviouschaptersforadeeperdiscussiononsomeoftheattributes.HerearethestepsyouneedtofollowtoconfigureKarma:

1. Updatethefilessectionwiththeaddedfiles:

files:[

...

'app/comments.js',

'app/commentController.js',

...

],

2. StartKarma:

$karmastart

3. ConfirmthatKarmaisrunning:

$Chrome36.0.1985(Windows7):Executed1of1SUCCESS(0.018secs/

0.015secs)

TestfirstLet’sfirststartwithanewfileinthespec/unitfoldercalledcomments.js.Wewillusethebasetemplate:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

Accordingtothespecification,whentheSubmitbuttonisclicked,itneedstoaddacomment.Wewillneedtofillintheblanksofthethreecomponentsofatest(Assemble,Act,Assert).

www.it-ebooks.info

Page 136: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Assemble

Thebehaviorwillneedtobepartofacontrollerforthefrontendtouseit.Theobjectundertestinthiscaseisthecontroller’sscopeobject;wewillneedtoaddthistotheassembleofthistest.TowireuptheAngularJScontrollerweneedtoinitializethemoduleandtheninjecttheCommentControllerscopeintothetest.AswedidinChapter2,TheKarmaWay,wewilldothesameinthefollowingcode:

varscope={};

beforeEach(function(){

module('comments');

inject(function($controller){

$controller('CommentController',{$scope:scope});

});

...

})

Now,thecontroller’sscopeobject,whichisundertest,isavailabletothetest.

Act

Thespecificationdeterminesthatweneedtocallaaddmethodinthescopeobject.AddthefollowingcodetothebeforeEachsectionofthetest:

beforeEach(function(){

scope.add('anyComment');

});

Nowfortheassertion.

Assert

Assertthatthecommentitemsinthescopeobjectnowcontainanycommentasthefirstelement.Addthefollowingcodetothetest:

it('',function(){

expect(scope.comments[0]).toBe('anycomment');

});

Savethefileandlet’smoveontothenextstepofthelifecycleandmakeitrun(execute).

MakeitrunNowthatwehavemostofthetestprepared,weneedtomakethetestpass.LookingattheoutputoftheconsolewhereKarmaisrunning,weseethefollowing:

$TypeError:undefinedisnotafunction…unit/comments.js:4:9

Lookingatthelinenumber,thatis4:9,ofourunittest,weseethatthisistheaddfunction.Let’sgoaheadandputinanaddfunctionintothecontroller’sscopeobjectusingthefollowingsteps:

1. Openthecontrollerscopeandcreateafunctionnamedadd:

$scope.add=function(){}

www.it-ebooks.info

Page 137: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

2. CheckKarma’soutputandlet’sseewhereweare:

$Expected'acomment'tobe'anycomment'.

3. Now,wehavehittheexpectation.Remembertothinkofthesmallestchangetogetthistowork.Modifytheaddfunctiontosetthe$scope.commentsarraytoanycommentwhencalled:

$scope.add=function(){

$scope.comments.unshift('anycomment');

};

TipUnshiftisastandardJavaScriptfunctionthataddsanitemtothefrontofanarray.

4. WhenwecheckKarma’soutput,weseethefollowing:

$Chrome36.0.1985(Windows7):Executed1of1SUCCESS

Success!Thetestpasses,butagainneedssomework.Let’smoveontothenextstageandmakeitbetter(refactor).

MakeitbetterThemainpointthatneedstoberefactoredistheaddfunction.Itdoesn’ttakeanyarguments!Thisshouldbestraightforwardtoadd,andsimplyconfirmthattheteststillruns.UpdatetheaddfunctionofCommentController.jstotakeanargumentandusethatargumenttoaddtothecommentsarray:

$scope.add=function(commentToAdd){

$scope.comments.unshift(commentToAdd);

};

ChecktheoutputwindowofKarmaandensurethattheteststillpasses.Thecompleteunittestlooksasfollows:

describe('',function(){

varscope={};

beforeEach(function(){

module('comments');

inject(function($controller){

$controller('CommentController',{$scope:scope});

});

scope.add('anycomment');

});

it('',function(){

expect(scope.comments[0]).toBe('anycomment');

})

});

TheCommentControllerfilenowlooksasfollows:

www.it-ebooks.info

Page 138: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

angular.module('comments')

.controller('CommentController',['$scope',function($scope){

$scope.comments=[];

$scope.add=function(commentToAdd){

$scope.comments.unshift(newComment);

};

}]);

BackupthetestchainWecompletedtheunittestandadditionoftheaddfunction.NowwecanaddthefunctiontospecifythebehavioroftheSubmitbutton.Thewaytolinktheaddmethodtothebuttonistotousetheng-clickattribute.ThestepstoaddbehaviortotheSubmitbuttonareasfollows:

1. Opentheindex.htmlpageandlinkitasfollows:

<buttontype="button"ng-click="add('acomment')">Submit</button>

Warning!Isthevaluehardcoded?Well,again,wewanttodothesmallestchangeandensurethattheteststillpasses.Wewillworkthroughourrefactorsuntilthecodeishowwewantit,butinsteadofabigbangapproach,wewanttomakesmallincrementalchanges.

2. Nowlet’sreruntheProtractortestandensurethatitstillpasses.Theoutputsaysitpasses,andweareokay.Thehardcodedvaluewasn’tremovedfromthecomments.Let’sgoaheadandremovethatnow.TheCommentsControllerfileshouldnowlookasfollows:

$scope.comments=[];

3. Runthetestandseethatwestillgetapassingtest.

Nowthelastthingweneedtomopupisthehardcodedvalueinng-click.Thecommentbeingaddedshouldbedeterminedbytheinputinthecommentinputtext.

BindtheinputHerearethestepsyouneedtofollowtobindtheinput:

1. Tobeabletobindtheinputintosomethingmeaningful,addanng-modelattributetotheinputtag:

<inputtype='text'ng-model='newComment'/>

2. Then,intheng-clickattribute,simplyusethenewCommentmodelastheinput:

<buttontype='button'ng-click='add(newComment)'>Submit</button>

RuntheProtractortestandconfirmthateverythinghaspassedandisgoodtogo.

www.it-ebooks.info

Page 139: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

OnwardsandupwardsNowthatwehavethefirstspecificationworkingend-to-endandunittested,wecanstartthenextspecification.Thenextspecificationstatesthattheuserswanttheabilitytolikeacomment.

Wewillusethesametop-downapproachandstartourtestfromaProtractortest.WewillcontinuetofollowtheTDDlifecycle,thatis,testfirst,makeitrun,makeitbetter.

www.it-ebooks.info

Page 140: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestfirstFollowingthepattern,wewillstartwithabasicProtractortesttemplate:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

Whenwefillinthespecification,wegetthefollowing:

describe('WhenIlikeacomment',function(){

beforeEach(function(){

});

it('shouldthenbeliked',function(){

});

});

Withthetemplateinplace,wearereadytoconstructthetest.

AssembleTheassemblyofthistestwillrequireacommenttoexist.Placethecommentwithintheexistingpostedcommenttest.Itshouldlooksimilartothis:

describe(''GivenIampostinganewcomment',function(){

describe('WhenIlikeacomment',function(){

});

});

ActTheuserspecificationwetestisthatthelikebuttonperformsanactionforaspecificcomment.Herearethestepsthatwillberequiredandthecoderequiredtodothem(notethatthefollowingstepswillbeaddedtothebeforeEachtext):

1. Storethefirstcommentsothatitcanbeusedinthetest:

varfirstComment=null;

beforeEach(function(){

2. Findthefirstcomment’slikebutton:

varfirstComment=element.all(by.repeater('commentin

comments').first();

varlikeButton=firstComment.element(by.buttonText('like'));

3. Thecodeforthelikebuttonwhenitisclickedisasfollows:

likeButton.click();

www.it-ebooks.info

Page 141: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AssertThespecificationexpectationisthatoncethecommenthasbeenliked,itisliked.Thisisbestdonebyputtinganindicatorofthenumberoflikes,andensuringthecountis1.Thecodewillthenbeasfollows:

it('Shouldincreasethenumberoflikestoone',function(){

varcommentLikes=firstComment.element(by.binding('likes'));

expect(commentLikes.getText()).toBe(1);

});

Thecreatedtestnowlooksasfollows:

describe('WhenIlikeacomment',function(){

varfirstComment=null;

beforeEach(function(){

//Assemble

firstComment=element.all(by.repeater('commentincomments').first();

varlikeButton=firstComment.element(by.buttonText('like'));

//Act

likeButton.click();

});

//Assert

it('Shouldincreasethenumberoflikestoone',function(){

varcommentLikes=firstComment.element(by.binding('likes'));

expect(commentLikes.getText()).toBe(1);

});});

www.it-ebooks.info

Page 142: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitrunThetesthasbeenpreparedandisitchingtorun.Wewillnowrunthetestandfixthecodeuntilthetestpasses.Thefollowingstepswilldetailtheerrorandthefixcyclerequiredtomakethetestpath:

1. RunProtractor.2. Viewtheerrormessageinthecommandline:

$Error:Noelementfoundusinglocator:by.buttonText("like")

3. Astheerrorstates,thereisnolikebutton.Goaheadandaddthebutton:

<ling-repeat='commentincomments'>

{{comment}}

<buttontype="button">like</button>

</li>

4. RunProtractor.5. Viewthenexterrormessage:

$Expected'acommentlike'tobe'acomment'.

6. Byaddingthelikebutton,wecausedourothertesttofail.ThereasonisouruseofthegetText()method.Protractor’sgetText()methodgetstheinnertextincludinginnerelements.Tofixthis,wewillneedtoupdatetheprevioustesttoincludelikeaspartofthetest:

it('Shouldthenaddthecomment',function(){

varcomments=element.all(by.repeater('commentincomments')).first();

expect(comments.getText()).toBe('acommentlike');

});

7. RunProtractor.8. Viewthenexterrormessage:

$Error:Noelementfoundusinglocator:by.binding("likes")

9. Timetoaddalikesbinding.Thisoneisalittlemoreinvolved.Likesneedstobeboundtoacomment.Weneedtochangethewaythecommentsareheldinthecontroller.Commentsneedtoholdthecommentvalueandthenumberoflikes.Acommentshouldbeanobjectlikethis:{value:'',likes:0}.Again,thefocusofthisstepisjusttogetthetesttopass.Thenextstepistoupdatethecontroller’saddfunctiontocreatecommentsbasedontheobjectwedescribedintheprecedingsteps.OpencommentController.jsandedittheaddfunctionasfollows:

$scope.add=function(commentToAdd){

varnewComment={value:commentToAdd,likes:0};

$scope.comments.unshift(newComment);

};

10. Updatethepagetousethevalueforthecomment:

www.it-ebooks.info

Page 143: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

<ling-repeat='commentincomments'>

{{comment.value}}

11. BeforererunningtheProtractortest,weneedtoaddthenewcomment.likesbindingtotheHTMLpage:

<ling-repeat='commentincomments'>

{{comment.likes}}

12. NowreruntheProtractortestsandlet’sseewheretheerrorsare:

$Expected'acommentlike0'tobe'acommentlike'

13. Becausetheinnertextofthecommenthaschanged,weneedtochangetheexpectationofthetest:

it('Shouldthenaddthecomment',function(){

expect(comments.getText()).toBe('acommentlike0');

});

14. RunProtractor:

$Expected'0'tobe'1'.

15. Now,wearefinallydowntotheexpectationofthetest.Inordertomakethistestpass,thesmallestchangewillbetomakethelikebuttonupdatethelikesonthecommentarray.Thefirststepistoaddalikemethodonthecontroller,whichwillupdatethenumberoflikes:

$scope.like=function(comment){

comment.likes++;

};

16. LinkthelikemethodtotheHTMLpageusinganng-clickattributeonthebuttonasfollows:

<buttontype="button"ng-click='like(comment)'>like</button>

17. RunProtractorandconfirmthatthetestspass!

Thepagenowlooksasfollows:

Comparedtothedrawingatthebeginningofthischapter,allthefeatureshavebeencreated.NowthatwemadethetestpassinProtractor,weneedtochecktheunitteststo

www.it-ebooks.info

Page 144: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ensurethatourchangesdidn’tbreaktheunittests.

FixingtheunittestsOneoftheprimarychangesrequiredwastomakethecommentanobject,consistingofavalueandnumberoflikes.Beforethinkingtoomuchabouthowtheunittestscouldhavebeenaffected,let’skickthemoff.Executethefollowingcommand:

$karmastart

Asexpected,theerrorisrelatedtothenewcommentobject:

$Expected{value:'anycomment',likes:0}tobe'anycomment'.

Reviewingtheexpectation,itseemsliketheonlythingrequiredisforcomment.valuetobeusedintheexpectationasopposedtothecommentobjectitself.Changetheexpectationasfollows:

it('',function(){

varfirstComment=scope.comments[0];

expect(firstComment.value).toBe('anycomment');

})

SavethefileandchecktheKarmaoutput.Confirmthatthetestpasses.BoththeKarmaandProtractortestspassandwehavecompletedtheprimaryuserbehaviorsofaddingacommentandlikingit.Youarefreenowtomoveontothenextstepandmakethingsbetter.

www.it-ebooks.info

Page 145: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitbetterAllinall,theapproachendedupwiththeresultwewanted.UsersarenowabletolikeacommentintheUIandseethenumberoflikes.Themajorcalloutfromarefactorstandpointisthatwehavenotunittestedthelikemethod.Reviewingourdevelopmentto-dolist,weseethattheto-dolistisanactionwewrotedown.Beforecompletelywrappingupthefeature,let’sdiscusstheoptionofaddingaunittestforthelikefunctionality.

CouplingofthetestAsalreadydiscussedinthisbook,testsaretightlycoupledtotheimplementation.Thisisagoodthingwhenthereisacomplicatedlogicinvolvedoryouneedtoensurethatcertainaspectsoftheapplicationbehaveincertainways.Itisimportanttobeawareofthecouplingandknowwhenitisimportanttobringitintotheapplicationandwhenitisnot.Thelikefunctionwecreatedsimplyincrementsacounteronanobject.Thiscanbeeasilytested;however,thecouplingwewillbringinwithaunittestwillnotgiveustheextravalue.Inthiscase,wewillnotaddanadditionalunittestforthelikemethod.Astheapplicationprogresses,wemayfindtheneedtoaddaunittestinordertodevelopandextendthefunction.HereareacoupleofthingsIconsiderwhenaddingatest:

Doesaddingatestoutweighthecostofmaintainingatest?Isthetestaddingvaluetothecode?

Doesithelpotherdevelopersbetterunderstandthecode?

Isthefunctionalitybeingtestedinsomeotherway?

Basedonourdecision,thereisnomorerefactoringortestingrequired.Inthenextsection,wewilltakeastepbackandreviewthemainpointsofthischapter.

www.it-ebooks.info

Page 146: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsQ1.The$newfunctionisusedtocreateachildscope:$scope.$new.

1. True2. False

Q2.Giventhefollowingcodesegment,howwouldyouselecttheitemsinthelist?

<ul>

<ling-repeat="iteminmyItems">

{{item.value}}

</li

</ul>

1. element.all(by.repeater('iteminitems')).2. element.all(by.repeater('iteminmyItems')).3. element.all('iteminitems').

Q3.TheAngularmocksinjectfunctionisusedto:

1. Resolveapplicationdependencies/references.2. Injectdependenciesintotheapplication.3. Noneoftheabove.

www.it-ebooks.info

Page 147: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryInthischapter,wewalkedthroughtheTDDtechniquesofusingProtractorandKarmatogether.Astheapplicationwasdeveloped,youwereabletoseewhere,why,andhowtoapplytheTDDtestingtoolsandtechniques.Theapproach,top-down,wasdifferentthanthebottom-upapproachdiscussedinChapter2,TheKarmaWayandChapter3,End-to-endTestingwithProtractor.Withthebottom-upapproach,thespecificationsareusedtobuildunittestsandthenbuildtheUIlayerontopofthat.Inthischapter,atop-downapproachwasshowntofocusontheuser’sbehavior.Thetop-downapproachteststheUIandthenfiltersthedevelopmentthroughtheotherlayers.Bothapproacheshavetheirmerit.WhenapplyingTDD,itisessentialtoknowhowtouseboth.InadditiontowalkingthroughadifferentTDDapproach,yousawsomeofthecoretestingcomponentsofAngularJSsuchas:

Testingacontrollerfromend-to-endandunitperspectivesUsingAngularmockstotestthescopeobjectofacontrollerProtractor’sabilityto:

Bindtong-repeaterandng-modelSendkeystrokestoinputcolumnsGetanelement’stextbyitsinnerHTMLcodeandallsubelements

Thenextchapterwillbuildonthetechniquesusedhereandlookintoheadlessbrowsertesting,advancedtechniquesforProtractor,andhowtotestAngularJSroutes.

www.it-ebooks.info

Page 148: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter5.FlipFlopAtthispoint,youshouldbefeelingconfidentintheinitialimplementationofanAngularJSapplicationusingTDD.Youshouldbefamiliarwithusingatest-firstapproach.Inthischapter,youwillcontinuetoexpandyourknowledgeofapplyingTDDwithAngularJSbylookingatthefollowing:

AngularJSroutesPartialviewsProtractorlocationreferenceswithCSS(CascadingStyleSheets)andHTMLelementsHeadlessbrowsertestingwithKarma

www.it-ebooks.info

Page 149: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

FundamentalsThischapterwillwalkyouthroughapplyingTDDtoroutesandpartialviewsforasearchapplication.Beforegettingintothewalk-through,youneedtobeawareofsomeofthetechniques,configurations,andfunctionsthatwillbeusedthroughoutthischapter,whichinclude:

ProtractorlocatorsHeadlessbrowsertesting

Afteryouhavereviewedtheseconcepts,youcanmoveontothewalk-through.

www.it-ebooks.info

Page 150: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ProtractorlocatorsProtractorlocatorsarekeycomponentsthatyoumusttaketimetolearn.Thisbookwillnotbeabletoshowexamplesofallthedifferentlocators,butitwillprovideexamplesofthemostcommonones.

ProtractorlocatorsallowyoutofindelementswithinanHTMLpage.Inthischapter,youwillseethefollowinginaction:CSS,HTML,andAngularJS-specificlocators.Locatorsarepassedtotheelementfunction.Theelementfunctionwillfindandreturnelementsinapage.Thegenericlocatorsyntaxisasfollows:

element(by.<LOCATOR>);

Intheprecedingcode,<LOCATOR>isaplaceholder.Thefollowingsectionsdescribeacoupleoftheselocators.

CSSlocatorsCSSisusedtoaddlayout,color,formatting,andstyletoanHTMLpage.Fromanend-to-endtestingperspective,thelookandstyleofanelementmaybepartofaspecification.AsanexampleconsiderthefollowingHTMLsnippet:

<divclass="anyClass"id="anyId"></div>

//...

vare1=element(by.css('.anyClass'));

vare2=element(by.css('#anyId'));

vare3=element(by.css('div'));

vare4=$('div');

Allfourselectionswillselectthedivelement.

ButtonandlinklocatorsBesidesbeingabletoselectandinterpretthewaysomethinglooks,itisalsoimportanttobeabletofindbuttonsandlinkswithinapage.Thiswillallowatesttointeractwiththesiteeasily.Hereareacoupleofexamples:

Buttontextlocator:

<button>anyButton</button>

//...

varb1=element(by.buttonText('anyButton'));

Linktextlocator:

<ahref="#">anyLink</a>

//...

vara1=element(by.linkText('anyLink'));

AngularlocatorsOneofProtractor’skeystrengthsisthatitprovidestestingfunctionalityspecifictoAngularJS.Therepeaterlocatorwillselecttheelementswithintheapplicationwhereng-

www.it-ebooks.info

Page 151: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

repeatwasused.Thisisespeciallyusefulwhenlookingatthenumberofreturnedresultsandthevaluesofindividualresults.Onekeytousingthislocatoristhatthestringoftherepeaterlocatormustmatchtheng-repeatstringusedintheAngularJSapplication.Hereisanexampleofusingtherepeaterlocator:

//TheListintheapplicationtouseng-repeaton

<ling-repeat="iteminlist">

<div>

<ahref="#">link</a>

</div>

</li>

//...

varfirstItem=element.all(by.repeater('iteminlist')).first();

Theprecedingcodehighlightshowtofindthefirstelementinarepeater.Itshouldbeclearthatinthiscase,theelement.allfunctionfindsalltheelementsmatchingtheselector.Then,thefirst()methodisusedtoreturnthefirstelementfound.

URLlocationreferencesWhentestingAngularJSroutes,youneedtobeabletotesttheURLofyourtest.ByaddingtestsaroundtheURLandlocation,youensurethattheapplicationfollowsspecificroutes.Thisisimportantbecauseroutesprovideaninterfaceintoyourapplication.HereishowtogettheURLreferenceinaProtractortest:

varlocation=browser.getLocationAbsUrl();

Nowthatyouhaveseenhowtousethedifferentlocatorsitistimetoputtheknowledgetouse.

www.it-ebooks.info

Page 152: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatinganewprojectItisimportanttogetaprocessandmethodtosetupyourprojectsquickly.Thelesstimeyou’rethinkingofthestructureofthedirectoryandtherequiredtools,themoretimeyou’redeveloping!

Somepeopleusetheangular-seed(https://github.com/angular/angular-seed)project,Yeoman,orcreateacustomtemplate.Althoughthesetechniquesareusefulandhavetheirmerit,whenstartingoutinAngularJS,itisessentialtounderstandwhatittakestobuildanapplicationfromthegroundup.Bybuildingthedirectorystructureandinstallingtoolsyourself,youwillunderstandAngularJSbetter.Youwillbeabletomakelayoutdecisionsbasedonyourspecificapplicationandneeds,asopposedtofittingintosomeothermold.AsyougrowandbecomeabetterAngularJSdeveloper,thisstepmaynotbeneededandwillbecomesecondnaturetoyou.

Inpreviouschapters,wediscussedhowtogettheprojectsetup,explainedthedifferentcomponentsinvolved,andwalkedthroughtheentireprocess.Iwillskipthesedetailsandexpectthatyoucanrecallhowtoperformthenecessaryinstallation.Toconfirmtheinstallation,hereisascreenshotoftheexpectedoutput:

www.it-ebooks.info

Page 153: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingupheadlessbrowsertestingforKarmaInpreviouschapters,youwererunningKarmausingthedefaultconfiguration.ThedefaultChromeconfigurationlaunchesChromeoneverytest.Testingagainsttheactualcodeandbrowser,whichtheapplicationwillrunin,isapowerfultool.However,whenlaunching,abrowsermaynotbehowyoualwayswantedit.Fromaunittestperspective,youmaynotwantthebrowsertobelaunchedinawindow.Someofthereasonsaretestsmaytakealongtimetorunoryoumaynotalwayshaveabrowserinstalled.

Luckily,KarmacomesequippedwiththeabilitytoeasilyconfigurePhantomJS,aheadlessbrowser.AheadlessbrowserrunsinthebackgroundandwillnotdisplaywebpagesinaUI.ThePhantomJSheadlessbrowserisareallygreattooltousefortesting.Itcanevenbesetuptotakescreenshotsofyourtests!ReadmoreabouthowthisisdoneandtheWebKitusedonthePhantomJSsiteathttp://phantomjs.org/.ThesucceedingsetupconfigurationwillshowyouhowtosetupPhantomJSwithKarmatogetheadlessbrowsertesting.

PreconfigurationWhenKarmaisinstalled,itautomaticallyincludesthePhantomJSbrowserplugin.Foryourreference,thepluginislocatedathttps://github.com/karma-runner/karma-phantomjs-launcher.Thereshouldn’tbeanyadditionalinstallationorconfigurationrequired.However,ifyoursetupstatesthatitismissingkarma-phantomjs-launcher,youcaneasilyinstallitusingnpm:

$npminstallkarma-phantomjs-launcher

ConfigurationPhantomJSisconfiguredinthebrowsersectionoftheKarmaconfiguration.Openthekarma.conffileandupdateitwiththefollowingdetails:

browsers:['PhantomJS'],

Nowthattheprojecthasbeeninitializedandconfiguredwithheadlessbrowsertesting,youcanseeitinactionthroughthefollowingwalk-throughs.

www.it-ebooks.info

Page 154: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Walk-throughofAngularroutesThiswalk-throughwillleverageAngularJSroutes.RoutesareanextremelyusefulfeatureofAngularJS.Theyallowyoutocontrolcertainaspectsoftheapplicationusingdifferentviews.Thiswalk-throughwillflipbetweenviewstoshowyouhowtouseTDDtobuildroutes.Thefollowingarethespecifications:

GivenaviewAthathasasinglebutton;thefollowingactionswilltakeplace:

ThebuttonispushedTheviewisswitchedtoviewB

GivenaviewBthathasasinglebutton;thefollowingactionswilltakeplace:

ThebuttonispushedTheviewisswitchedtoviewA

Essentially,thiswillbeanapplicationthatdoesaflipflopbetweenviews.

www.it-ebooks.info

Page 155: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingupAngularJSroutesBeforeyouuseAngularJSroutes,youneedtoinstalltheAngularJSroutecomponent.YoucaninstallAngularJSroutesusingbowerasfollows:

$bowerinstallangular-route

AngularroutesrequiresAngular,asyoucanimagine.InordertouseitanHTMLpagewouldlookasfollows:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

<scriptsrc="bower_components/angular/angular.js">

</script>

<script

src="bower_components/angular-route/angular-route.js"></script>

</body>

</html>

DefiningdirectionsAroutespecifiesaspecificlocationandexpectsaresult.FromanAngularJSperspective,theroutesmustfirstbespecifiedandthenassociatedtocertainelementswithinthem.

ConfiguringngRoute

InordertouseAngularJSroutes,wefirstneedtobringngRouteinasadependencyintotheapplication.Inapp/flipFlop.js,modifythecodetobringinngRouteasadependencyandreturnthemodule:

varflipFlop=angular.module('flipFlop',['ngRoute']);

Now,thesecondthingrequiredisweneedtoconfiguretheroutesthatweneed.Inourcase,weneedtworoutes:oneforviewAandoneforviewB.Therouteconfigurationwillthenlookasfollows:

flipFlop.config(['$routeProvider',function($routeProvider){

$routeProvider

.when('/view/a',{

templateUrl:'app/viewA.html',

controller:'ViewAController'

})

.when('/view/b',{

templateUrl:'app/viewB.html',

controller:'ViewBController'

})

.otherwise({

redirectTo:'/view/a'

});

www.it-ebooks.info

Page 156: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

}]);

Arouteisdefinedusingwhen,whichhasafirstargumentasastringforthefullroute.Thesecondargumentisanobject,whichtakestheHTMLpagefortheroute(templateURL)andthecontrollerfortheroute(controller).

Definingtheroutecontrollers

Forbothroutes,createanemptycontrollersothatitcanbeaplaceholderforthefuturecontroller.Herearethestepsyouneedtofollowtodefineroutecontrollers:

1. CreateanewfilefortheViewAcontroller(/app/ViewAController.js):

angular.module('flipFlop')

.controller('ViewAController',['$scope',function($scope){

}]);

2. CreateanothernewfilefortheViewBcontroller(/app/ViewBController.js):

angular.module('flipFlop')

.controller('ViewBController',['$scope',function($scope){

}]);

3. Addthetwocontrollerstotheindex.htmlpage:

<scriptsrc="app/viewAController.js"></script>

<scriptsrc="app/viewBController.js"></script>

Definingtherouteviews

RouteviewsarepartialHTMLelementsthatcanbedynamicallyplacedintoanapplication.Forthetwoviewswerequire,wewillputabasicdivtagforeachview,asshowninthefollowingsteps:

1. Createanewfileforapp/viewA.html:

<divid="viewA"></div>

2. Createanewfileforapp/viewB.html:

<divid="viewB"></div>

Thelastthingrequiredistoputaplaceholderwheretherouteviewwillbeplacedintheindex.htmlpage:

<divng-view></div>

Now,theroutesaresetupwiththeinitialviewsandcontrollers.WecancontinuewiththeProtractortest.

AssemblingtheflipfloptestFollowingthefirstofthe3A’s,Assemble,thefollowingstepswillshowyouhowtoassemblethetest.

www.it-ebooks.info

Page 157: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

1. StartwiththeProtractorbasetemplate:

describe('GivenaviewAthathasasinglebutton',function(){

describe('Whenthebuttonispushed',function(){

beforeEach(function(){

})

it(''shouldbeswitchedtoviewB'',function(){

})

})

})

2. Navigatetotherootoftheapplicationusingthefollowingcode:

browser.get('/index.html');

3. ThebeforeEachmethodneedstoconfirmthatthecorrectviewisbeingdisplayed.ThiscanbedoneusingaCSSlocatortolookforthedivtagofviewA.Theexpectationwilllookasfollows:

varviewA=element(by.css('#viewA'));

expect(viewA.isPresent()).toBeTruthy();

4. Then,addanexpectationthatviewBisnotvisible:

varviewB=element(by.css('#viewB'));

expect(viewB.isPresent()).toBeFalsy();

YouwillnoticehowtheselectionofviewAandviewBisdoneoutsideofthebeforeEachmethod,soitcanbeusedforotherexpectations.

Makingtheviewsflip

Theprecedingtestneedstoconfirmthatwhentheflipbuttonispushed,theviewshouldswitch.Inordertotestthis,youcanusetheby.buttonTextlocator.Hereiswhatitwilllooklike:

varbuttonToPush=element(by.linkText('flip'));

buttonToPush.click();

ThebeforeEachfunctionisnowcompleteandlooksasfollows:

varviewA=element(by.css('#viewA'));

varviewB=element(by.css('#viewB'));

beforeEach(function(){

browser.get('/index.htm');

expect(viewA.isPresent()).toBeTruthy();

varbuttonToPush=element(by.linkText('flip'));

buttonToPush.click();

})

Now,youcanaddtheassertion.

Assertingaflip

TheassertionwillagainuseProtractor’sCSSlocatortofindthatviewBisavailable:

www.it-ebooks.info

Page 158: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

it('shouldbeswitchedtoviewB',function(){

expect(viewB.isPresent()).toBeTruthy();

})

YoualsoneedtoconfirmthatviewAisnolongeravailable.AddtheexpectationthatviewAshouldnotexist:

it('shouldnotdisplayviewA',function(){

expect(viewA.isPresent()).toBeFalsy();

})

Thetesthasnowbeenassembled.

MakingflipfloprunNow,youwillseethestepsrequiredtomaketheflipfloprun:

1. Inanewconsolewindow,starthttp-server:

$./node_modules/http-server/bin/http-server-p8080

2. RunProtractor:

$./node_modules/protractor/bin/protractorprotractorConf.js

3. ThefirsterrorstatesError:Angularcouldnotbefoundonthepagehttp://localhost:8080/:angularneverprovidedresumeBootstrap.Whenyougetthiserror,proceedwiththefollowingsteps:

1. ThiserrormeansthatnoAngularJSapplicationhasbeenassociatedwiththeapplication.It’snowtimetocreatetheapplicationmoduleandaddittothepage.

2. Createanewfilenamed/app/flipFlop.js:

angular.module('flipFlop',[]);

3. Addthenewmoduletotheindex.htmlpage:

<scriptsrc="app/flipFlop.js"></script>

4. AddtheAngularJSapplicationidentifiertothepage:

<bodyng-app='flipFlop'>

5. ReruntheProtractortest.

4. TheerrorisError:Noelementfoundusinglocator:by.linkText("flip").Torectifythisperformthefollowingsteps:

1. Openuptheapp/viewA.htmlfileandaddalinktotheViewBroutewiththefliptext:

<divid="viewA">

<ahref="#/view/b">flip</button>

</div>

www.it-ebooks.info

Page 159: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

2. Rerunthetest.

5. TheProtractortestsnowpass.

MakingflipflopbetterForpractice,youshouldaddalinktoswitchbacktoviewAfromviewB.Thereisnothingthathasbeencalledoutthatneedstobechangedorrefactored.Themaintakeawayfromthiswalk-throughishowtouseProtractortotestroutes.Herearesomescreenshotsoftheapplication:

Theinitialindexpageisshowninthefollowingscreenshot:

Thefollowingiswhatyou’llseeaftertheviewhasbeenswitched:

www.it-ebooks.info

Page 160: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SearchingtheTDDwayThiswalk-throughwillshowyouhowtobuildasimplesearchapplication.Thewalk-throughhastwocomponents.Thefirstdiscussesasearchquerycomponent.Thesecondusesroutestodisplaysearchresultdetails.

www.it-ebooks.info

Page 161: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

DecidingontheapproachThiswalk-throughusesthetop-downTDDapproach.Itstartswithwritingfailingtests,fromtheUIpointofviewusingProtractor,andthenworkingthroughtheapplicationwithacombinationofunitandend-to-endtests.

www.it-ebooks.info

Page 162: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Walk-throughofsearchqueryTheapplicationbeingbuiltisasearchapplication.Thefirststepistosetupthesearchareawithsearchresults.ImagineIamperformingasearch.Thefollowingactionswilloccur:

AsearchqueryistypedinResultsaredisplayedontheleftsidebar

Thispieceoftheapplicationisverysimilartothetest,layout,andapproachyousawinChapter4,FirstSteps.Theapplicationwillneedtouseaninput,respondtoaclick,andconfirmtheresultingdata.Sincethetestsandcodeusethesamefunctionalityasthepreviousexample,itisnotworthprovidingacompletewalk-throughofthesearchfunctionality.Instead,thefollowingsectionwillshowtheresultingcodewithafewexplanations.

www.it-ebooks.info

Page 163: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThesearchquerytestThefollowingcoderepresentsthetestforthesearchqueryfunctionality:

describe('',function(){

//StorethesearchResultforuseinthetest

varsearchResult=null;

beforeEach(function(){

//ASSEMBLE

browser.get('/index.html');

varsearchResult=element.all(by.repeater('resultinresults'));

expect(searchResult.count()).toBe(0);

//ACT

varsearchQueryInput=$('input');

searchQueryInput.sendKeys('anyvalue');

varsearchButton=element(by.buttonText('search'));

searchButton.click();

});

//Assert

it('',function(){

expect(searchResult.count()).toBe(1);

});

});

Youshouldnoticeaparalleltoprevioustests.Thefunctionalityiswrittentomirrorthebehaviorofausertypinginthesearchbox.Thetestfindstheinputfield,typesavalue,andthenselectsthebuttonthatsaysSearch.Theassertionconfirmsthattheresultcontainsasinglevalue.ThenextsectionwilllookattheapplicationfromtheHTMLpage.

www.it-ebooks.info

Page 164: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThesearchqueryHTMLpageThefollowingcodeshowstheresultingbodyofthesearchqueryHTMLpage:

<bodyng-app="search">

<divng-controller="SearchController">

<inputtype="text"ng-model="searchQuery"></input>

<buttonng-click="search(searchQuery)">search</button>

<ul>

<ling-repeat="resultinresults">{{result}}</li>

</ul>

</div>

<scriptsrc="bower_components/angular/angular.js"></script>

<scriptsrc="app/search.js"></script>

<scriptsrc="app/searchController.js"></script>

</body>

ThemainhighlightsoftheHTMLpageare:

TheuseofthesearchControllerclass’modeltostorethesearchQueryclassintheinput:

<inputtype="text"ng-model="searchQuery"></input>

AssociatingthebuttonclickeventtothesearchController'ssearchfunction:

<buttonng-click="search(searchQuery)">search</button>

ThenextsectionwillshowtheresultingsearchmoduleandsearchController.

www.it-ebooks.info

Page 165: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThesearchapplicationHereistheresultofthesearchModulecode:

varsearchModule=angular.module('search',[]);

HereistheresultofthesearchControllercode:

angular.module('search')

.controller('SearchController',['$scope',function($scope){

$scope.results=[];

$scope.search=function(){

$scope.results=['AnyValue'];

};

}]);

TheprecedingAngularJScomponentsaresimilartowhathasalreadybeenshowninpreviouschapters.Nowthatyouhavereviewedtheexistingsearchpieceoftheapplication,youcanwalkthroughthestepstodisplaysearchresultdetailviews.Hereiswhatthesearchapplicationlookslikesofar:

www.it-ebooks.info

Page 166: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Showmesomeresults!NowthattheSearchbuttonissetwiththerequiredfeatures,theresultingdetailsneedtobedisplayedwhenasearchresultisselected.Hereistheuserspecification.Giventhefollowingsearchresults:

IselectanitemfromthesearchresultsIwillseethedetailsinthemainpagecomponent

Followingthetop-downapproach,thefirststepwillbetheProtractortestsfollowedbythenecessarystepstogettheapplicationfullyfunctional.

www.it-ebooks.info

Page 167: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatingthesearchresultroutesThisapplicationwilluseroutestoswitchbetweenviews.Asthisstepisprimarilyaboutconfiguration,itdoesn’tmakesensetowaituntilatestfails.Thefollowingstepswillbrieflyrecapthenecessarysteps,asyouhavealreadywalkedthroughthestepswiththeflipflopapplication:

1. Installangular-routesusingBower:

$bowerinstallangular-route

2. Addangularandangular-routetotheindex.htmlpage:

<scriptsrc="bower_components/angular/angular.js"></script>

<scriptsrc="bower_components/angular-route/angular-route.js"></script>

3. CreateangRoutemoduleasadependencyintheapplication(app/search.js):

varsearchModule=angular.module('search',['ngRoute']);

4. Configuretheroutesintheapp/search.jsfile.Addthefollowingrouteconfiguration:

searchModule.config(['$routeProvider',function($routeProvider){

$routeProvider

.when('/splash',{

templateUrl:'app/splash.html',

controller:'SplashController'

})

.when('/detail/:id',{

templateUrl:'app/searchDetail.html',

controller:'SearchDetailController'

})

.otherwise({

redirectTo:'/splash'

});

}]);

Theprecedingconfigurationcontainstworoutes.Oneforasplashscreen/landingpagethatwillbedisplayedwhentheuserfirstcomestothepage.Thesecondistheroutetogetthesearchdetails.

5. Addtheroutestubcontrollers:

1. CreateanewfileforSplashController(app/splashController.js):

angular.module('search')

.controller('SplashController',['$scope',function($scope){

}]);

2. CreateanewfileforSearchDetailController(app/searchDetailController.js):

angular.module('search')

.controller('SearchDetailController',['$scope',function($scope){

www.it-ebooks.info

Page 168: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

}]);

6. Addthedetailcontrollertotheindex.htmlpage:

<scriptsrc="app/searchDetailController.js"></script>

7. CreatethepartialviewHTMLfilesbyfollowingthesesteps:

1. Createanewfileforsplash.html:

<divid="splash"></div>

2. CreateanewfileforsearchDetail.html:

<divid="searchResultDetail"></div>

Theroutesforthetesthavenowbeencreated.Youcancontinuetothenextstepandbeginaddingthefunctionalitytolinksearchresultstotheresultdetails.

www.it-ebooks.info

Page 169: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingthesearchresultsAsthespecificationstates,youwillneedtoleveragetheexistingsearchresults.Insteadofcreatingatestfromscratch,youcanaddtotheexistingsearchquerytest.Startwithabasetestembeddedinthesearchquerytestasfollows:

describe('GivenIamsearching',function(){

describe(''whenItypeinasearchquery'',function(){

...

describe('Givensearchresults',function(){

describe('WhenIselectanitemfromthesearchresults',function(){

beforeEach(function(){

});

it('shouldseethedetailsinthemainpagecomponent',function(){

});

});

});

})

})

Nowmoveontothenextstepandbuildthetest.

AssemblingthesearchresulttestInthiscase,thesearchresultsarealreadyavailablefromthesearchquerytest.Youdon’thavetoaddanymoresetupstepforthetest.

SelectingasearchresultTheobjectundertestistheresult.Thetestiswhentheresultisselectedandthentheapplicationmustdosomething.ThestepstowritethisinProtractorareasfollows:

1. Findaresultitemusingthefollowingcode:

varresultItem=element(by.repeater('resultinresults')).first();

2. Selecttheresultitem.Asyouwillberepresentingthedetailsusingaroute,youwillcreatealinktothedetailspageandclickonthelink.Herearethestepstocreatealink:

1. Selectthelinkwithintheresultitem.Thisusestheelementcurrentlyselectedandthenfindsanysubelementsthatmeetthecriteria.Thecodeforthisisasfollows:

varresultLink=resultItem.element(by.css('a'));

2. Nowtoselectthelinkaddthefollowingcode:

resultLink.click();

Confirmingasearchresult

www.it-ebooks.info

Page 170: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Nowthatthesearchitemhasbeenselected,youwillneedtoverifythattheresultdetailspageisvisible.Thesimplestsolutionatthispointistoensurethatthedetailsviewisvisible.ThiscanbedoneusingProtractor’sCSSlocatortolookforthesearchdetailview.Thefollowingisthecodetobeaddedforconfirmingasearchresult:

it('Shouldseethedetailsinthemainpagecomponent',function(){

varresultDetail=element(by.css('#searchResultDetail'))

expect(resultDetail.isDisplayed()).toBeTruthy();

})

Hereisthecompletetest:

...

describe('WhenIselectanitemfromthesearchresults',function(){

beforeEach(function(){

varresultItem=element.all(by.repeater('resultinresults')).first();

varresultLink=resultItem.element(by.css('a'));

resultLink.click();

});

it('Shouldseethedetailsinthemainpagecomponent',function(){

varresultDetail=element(by.css('#searchResultDetail'))

expect(resultDetail.isDisplayed()).toBeTruthy();

});

});

Nowthatthetestissetup,youcancontinuetothenextphaseofthelifecycleandmakeitrun.

www.it-ebooks.info

Page 171: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakingthesearchresulttestrunForthisstepofthelifecycle,wewillexecuteProtractorandmakefixesintheapplicationinordertomakethetestrunsuccessfully.Herearethestepsyouneedtofollow:

1. Thefirsterror:Error:Noelementfoundusinglocator:by.cssSelector('a')

Weneedtoaddalinktotheresultitemlist,whichwillpointtothedetailsoftheresult.IntermsofAngularroutes,wewilladd#/detail/:resultIdasaprefix:

<ling-repeat="resultinresults"><ahref="#/detail/{{result.id}}">

{{result.name}}</a></li>

2. NowrerunthetestandwegetUnknownError:unknownerror:Elementisnotclickableatpoint(48,57).Otherelementwouldreceivetheclick:....

Thiserrorisnotasclear.Whenthishappens,andtheerrorisnotasspecificasrequired,youcanjumptothesiteitselfandlookattheJavaScriptconsoleforerrors.Gotohttp://localhost:8080.Hereisascreenshotofwhatyoushouldsee:

Themainproblemisthatthelinkisnotonthepage.Lookingbackatthecode,youcanseethatthesearchresultobjectisanarrayofstringsbutitneedstobeanarrayofobjectsthathaveanIDandname.Updatetheapp/searchController.jssearchfunctionasfollows:

$scope.search=function(){

$scope.results=[{id:1,name:'AnyValue'}];

};

Nowrerunthetest.

3. Therouteshavenowbeenconfiguredtothenewroute(#/detail/{{result.id}})andthetestsnowpass.

www.it-ebooks.info

Page 172: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

www.it-ebooks.info

Page 173: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Creatingalocation-awaretestAstheapplicationusesroutes,theroutedetailviewwillneedtobetested.Inthiscase,youwillneedtoensuretheURLhastheIDofthesearchresult.Followthesestepstoaddthetest:

1. InthebeforeEachmethod,retrievetheIDofthesearchresultbasedonhrefofthelinkattribute:

varresultId=null;

beforeEach(function(){

resultId=resultLink.getAttribute('href').then(function(attr){

returnattr.match(/#\/detail\/(\d+)/)[1];

});

});

2. ResolvetheresultIdpromisecontainingtheIDoftheresult:

it('Shouldsettheurltotheselecteddetailview',function(){

resultId.then(function(id){

3. Withinthepromise,createexpectedUrl:

varexpectedUrl='/detail/'+id;

4. GetthelocationoftheURL:

browser.getLocationAbsUrl()

5. UsethepromisetochecktheexpectationontheURL:

.then(function(url){

expect(url.split('#')[1]).toBe(expectedUrl);

});

});

Location-awaretestscanbeveryhelpfulwhendealingwithroutes.Thetestscanbesimpleorcomplex,buthelpaligntherouteinterfacetoclearspecifications.

www.it-ebooks.info

Page 174: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakingthesearchresultbetterNowthatthereisapassingtest,somecleanupandrefactoringisneeded.Therearetwoprimarycallouts:

Nounittests.HowdoyouknowsearchResultDetailisspecifictothesearchresultweselect?

Uptothispoint,therehasn’tbeenaneedtocreateunitteststobuildtheapplication.ThefocushasbeenontheUIintheapplication.Therehasn’tbeenlogicoractionsneededtobuildonthebackend.Mostofthedevelopmenthasbeenfocusedonwiringupthefrontendandmakingsurethecomponentsinthespecificationareavailabletotheuser.

Theotheractionthatyouneedtolookatisthefactthatthereisnotawaytotestthataloadedviewactuallyreflectsdatafromtheselectedresult.Thiscanbetackledintwoparts.ThefirstpartistoensurethattheURLforthewindowpointstothecorrectroute.ThesecondpartwillbetodisplaytheIDnumberofthesearchresultontheview.

ConfirmingtherouteIDTheIDwillnotbedisplayedtotheusers;however,itisstillanintegralpartoftheapplication.Astheapplicationgrowsinthefollowingchapters,youwillbeleveragingtheIDtoextractfurtherdata.Thiswalk-throughwillfollowtheTDDlifecycleanduseKarmatobuildthefeature.

SettinguptherouteIDunittest

Toinjectthescopeintoacontroller,theinitialtestwilllookasfollows:

describe('',function(){

varscope={};

beforeEach(function(){

module('search');

inject(function($controller){

$controller('SearchController',{$scope:scope});

});

});

it('',function(){});

});

Inordertotesttheroutes,thetestwillleveragethe$routeParamsobject.The$routeParamsobjectgivesanobjectaccesstoinformationrelatingtotheroutethatbroughttheapplicationtothelocation.Forexample,the/detail/:idroutedefinitionandthe/detail/123,$routeParamsroutewillgiveyouthe{id:123}object.Forthetest,afake$routeParamsobjectcontainingtheIDofthedetailobjectwillbeused.Updatethetestsothatithasthefollowingfake$routeParamsobject,whichwillreturnanIDof1:

beforeEach(function(){

//...

varrouteParams={id:1};

$controller('SearchDetailController',{$scope:scope,$routeParams:

routeParams});

www.it-ebooks.info

Page 175: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Nowthatthefake$routeParamsobjecthasbeeninjectedintothecontroller,youcancontinuetothenextphaseandmaketheassertion.

ConfirmingtheID

TheassertionisthatthescopehasadetailobjectwiththesameIDthat$routeParamsspecified.ThecodeforconfirmingtheIDisasfollow:

it('Shouldreturnresults',function(){

expect(scope.detail.id).toBe(1);

});

Makingtherouteparameter’stestrun

NowthatKarmaisrunningusingaheadlessbrowser,wecanstartKarmaintheconsoleandletitrunaswewalkthroughtheissues,asshowninthefollowingsteps:

1. StartKarma:

$karmastart

2. ThefirstissuewegetisthatngRoutecan’tbefound.Thisisbecauseweaddedangular-routetotheproject,buthaven’taddedittokarma.conf.Updatethekarma.confupdatethefilessectionwiththefollowingcode:

files:[

//...

'bower_components/angular-route/angular-route.js',

3. Afterrerunningthetest,weareleftwithTypeError:''undefined''isnotanobject(evaluatingscope.detail.id).Torectifythis,performthefollowingsteps:

1. Thiserrorinformsusthatthescope.detail.idobjectdoesn’texistinthecontroller.Wewillnowupdatethecontrollertoincludeit.Thefirststeptofixingthisistoadd$routeParamstosearchDetailController:

.controller('SearchDetailController',

['$scope','$routeParams',function($scope,$routeParams){

2. Now,inthecontroller,createthedetailobjectwiththe$routeParamsID:

$scope.detail={id:$routeParams.id};

3. ThedetailobjecthasnowbeencreatedusingtheIDoftheroute.Goaheadandrerunthetest.

Thetestpasses!

Theapplicationnowlookslikewhatisshowninthefollowingscreenshotwhenyoufirstopenit:

www.it-ebooks.info

Page 176: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Afterasearchquery,theapplicationlookslikewhatisshowninthefollowingscreenshot:

Fordetailsoftheapplicationlooksasshowninthefollowingscreenshot(noticethattheURLcontainsthedetailroute):

www.it-ebooks.info

Page 177: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsQ1.GiventhefollowingHTMLcode,howwouldyouselectthesecondlistitem?

<ul>

<li>item1</li>

<li>item2</li>

</ul>

1. element.all(by.css('li')).second();.2. element(by.repeater('iteminlist'))[1];.3. element.all(by.css('li')).get(1);.

Q2.GiventhefollowingAngularJScomponent,howwouldyouselecttheelementandsimulateaclick?

<ahref="#">SomeLink</a>

1. $('a').click();.2. element(by.css('li)).click();.3. element(by.linkText('SomeLink')).click();.

Q3.WhenusingrouteswithAngularJSyouneedtoinstallangular-route.

1. True.2. False.

www.it-ebooks.info

Page 178: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThischapterhasshownyouhowtouseTDDtobuildanAngularJSapplication.Theapproach,uptothispoint,hasfocusedonthespecificationfromauserperspectiveandusingTDDfromtop-downapproach.Thistechniquehelpsyougetusable,smallcomponentstestedandcompletedfortheusers.Asapplicationsgrow,sodoestheircomplexity.Aswemoveontothenextchapter,wewillexplorethebottom-upapproachandseewhentousethattechniqueoveratop-downapproach.

ThischapterhasshownyouhowTDDcanbeusedtodeveloproute-basedviews.Thisincludesutilizingmultiplecontrollersandviews.Routesallowyoutogetaniceseparationofyourcomponentsandviews.WehaveshowntheusageofseveralProtractorlocators,fromCSS,torepeaters,tolinktext,toinnerlocators.BesidesusingProtractor,wehavealsolearnedhowtoconfigureKarmawithaheadlessbrowser,andwegottoseeitinaction.

www.it-ebooks.info

Page 179: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter6.TellingtheWorldThebuildupofTDDfocusedonfundamentalcomponents,namelylifecycleandprocess,usingstep-by-stepwalk-throughs.Youhavetakenseveralapplicationsfromthegroundup,understandinghowtobuildAngularJSapplicationsandusetoolstotestthem.ItistimetoexpandfurtherintothedepthsofAngularJSandintegrateservices,broadcasting,androutes.

Thischapterwillbeslightlydifferentthantheothersintwoways:

Insteadofbuildingabrandnewapplication,wewillusethesearchapplicationfromChapter5,FlipFlop.Also,abottom-upapproachwillbeused.ThisconsistsofcreatingunittestsfirstandthenmovingtotheUI.

www.it-ebooks.info

Page 180: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

BeforetheplungeBeforethewalk-through,thecoreconceptsofthechapterwillbereviewedfirst.Itisimportantthatyouunderstandtheseconceptsbeforeyoumoveontothewalk-through.

www.it-ebooks.info

Page 181: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

KarmaconfigurationSofar,thedefaultKarmaconfigurationhasbeenused,butnoexplanationonthedefaultconfigurationhasbeengivenyet.Filewatchingisausefuldefaultbehaviorthatwillnowbereviewed.

FilewatchingFilewatchingisenabledbydefaultwhenthekarmainitcommandisused.FilewatchinginKarmaisconfiguredwiththefollowingdefinitioninthekarma.conf.jsfile:

autoWatch:true,

Thefilewatchingfeatureworksasexpectedandwatchesthefilesdefinedintheconfiguration’sfilesarray.Whenafileisupdated,changed,ordeleted,Karmawillrespondbyrerunningthetests.FromaTDDperspective,thisisagreatfeatureastestswillcontinuetorunwithoutanymanualintervention.

Themainpointtowatchoutforistheadditionoffiles.Ifthefilebeingaddeddoesn’tmatchthecriteriainthefilesarray,theautoWatchparameterwon’trespondtothechange.Asanexample,let’sconsiderthatthefilesaredefinedasfollows:

files:['dir1/**/*.js']

Ifthisisthecase,thewatcherwillfindallthefilesandsubdirectoryfilesendingin.js.Ifanewfileisinadifferentdirectory,notindir1,thenthewatcherwillnotbeabletorespondtothenewfilebecauseitisinadifferentdirectorythanwhatitwasconfiguredin.

www.it-ebooks.info

Page 182: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Usingabottom-upapproachThetop-downapproachofTDDcanbeveryuseful.Ithelpsfocusonuser-facingcomponentsfirstandthenfillsupthebackendlayer.Oneofthecaveatstothisapproachisthatthespecificationbeingbuiltismoreuserfacingasopposedtoitbeingbasedonlogic.Thebottom-upapproachbuildsfromtheinnercomponentsouttotheUIandtheuser.Thiskindofapproachisextremelyimportantwhenworkingwithcomplicatedlogicandrequirements.Withthebottom-upapproach,youwillfirstbuildservices,controllers,anddirectiveswithallthecomplexitiesusingunittestsandKarma.Afterthis,youwillexpandtocreateend-to-endtestswithProtractor.

www.it-ebooks.info

Page 183: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ServicesAngularJSservices,factories,andresourcesareallimportantcomponents.Servicesareusedtoabstractapplicationlogic.Theyareusedtoprovidesingleresponsibilityforaparticularaction.Singleresponsibilityallowscomponentstobeeasilytestedandchanged.Thisisbecausethefocusisononecomponentandnotalltheinnerdependencies.

HereisasummaryofsomeoftheotherAngularJScomponentsthathavebeenlookedatsofar:

Attributesanddirectives:ThesedriveactionsandflowfromtheUIControllers:ThisprovidesthegluebetweentheUIandlogicServices:Thisisolatesthelogic

www.it-ebooks.info

Page 184: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

PublishingandsubscribingmessagesOneofthegreatfeaturesofAngularJSisitsabilitytopublishandsubscribemessageswithinapage.Publishingandsubscribingmessagesisapowerfulcomponent,butlikewithanything,whenusedthewrongway,itcanleadtoamess.

Oneareawherethispatternisusefuliswhencommunicatingacrossboundariesinanapplication.ApplicationboundariesareimportantastheyallowtheUItohaveisolatedcode.ComplexityoccurswhenseparateUIcomponentsneedtobeawareofchangesinotherareasoftheUI.Withapublishingandsubscriptionmodel,applicationscancommunicateseamlesslyusingmessages.Thischapterwillfocusonpublishingandsubscribing.Youwillbeabletotakeacloserlookatwhatboundariesareanddeterminegoodplacestoleveragethisfeatureinyourownapplications.

Therearetwowaysinwhichmessagescanbepublished.Youcaneitheremitorbroadcast.Itisimportanttoknowthedifferenceasbothworkslightlydifferently,andtheymayaffecttheperformanceofyourapplication.

EmittingOnewaytopublisheventsistoemitthem.Thedocumentationathttps://docs.angularjs.org/api/ng/type/$rootScope.Scopegivesthefunctionalityofthe$emit()methodasfollows:

Dispatchesaneventnameupwardsthroughthescopehierarchynotifyingtheregistered$rootScope.Scopelisteners.

Theimportantthingtonoteis$emit()notifiesupthroughthescopesallthewaytothetopofthehierarchy.Thisisimportantbecauseifyouhaveanembeddedcontrollerscope,itisgoingtohavetopropagateallthewayuptoeverycontrollerandscope.Thiscancauseaperformanceissue.Hereisanexampleofhowtoemitanevent:

$scope.someAction=function(){

$scope.$emit('ANYEVENT');

};

Thebestwaytoseetheupwardpropagationoftheeventisthroughatest.Thenextsectionwillshowyouhowtounittesttheupwardeffectof$emit().

Testingemit

Thefollowingtestshavethreecontrollers:TopController,MiddleController,andBottomController.MiddleControllerwillemittheevent.Fromthis,anexpectationcanbemadethatTopControllerwillreceivetheeventandBottomControllerwon’t,astheemissionpropagatesinanupwardfashion.Herearethestepstotestthe$emit()method:

1. Createspiestotesttheemissionofevents:

vartopEventSpy=jasmine.createSpy();

varbottomEventSpy=jasmine.createSpy();

www.it-ebooks.info

Page 185: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

2. Thetestsetupfirstsetsthehierarchyofscopes:

inject(function($controller,$rootscope){

vartopScope=$rootscope.$new();

varmiddleScope=topScope.$new();

varbottomScope=middleScope.$new();

3. Thenthecontrollersaresetwiththeirrespectivescopes:

$controller('TopController',{$scope:topScope});

$controller('MiddleController',{$scope:middleScope});

$controller('BottomController',{$scope:bottomScope});

4. Setthespytocapturetheevents:

topScope.$on('MIDDLEEMIT',topEventSpy);

bottomScope.$on('MIDDLEEMIT',bottomEventSpy);

5. Emittheeventfromthemiddlescope:

middleScope.$emit('MIDDLEEMIT');

6. Addtheexpectationthatthetopspywascalledontheevents:

it('Shouldnotifytopcontroller',function(){

expect(topEventSpy.wasCalled).toBe(true);

});

7. Addtheexpectationthatthebottomspywasnotcalled:

it('Shouldnotnotifybottomcontroller',function(){

expect(bottomEventSpy.wasCalled).toBe(false);

});

Hereareacoupleofthingstonotefromtheprecedingtest:

ThisisaunittestthatwewillruninKarma.Theinjectmethodprovidesareferencetothe$controllerand$rootscopescopes.The$rootscopescopeisthetopmostscopeofanAngularJSapplication.Ifyou’reusing$rootscopetoemitevents,theywouldn’tneedtopropagateanymoreas$rootscopeisatthehighestlevel.Inthelaterexamples,$rootscopewillbeinjectedintothecontrollerandusedtolistentoandsendevents.Ascopecancreateanewchildscope.Achildscopeiscreatedusingthe$newmethod.Youcanimaginethistobeequivalenttoapagethathasembeddedcontainers:

<divng-controller="topController"

<divng-controller="middleController">

<divng-controller="bottomController">

</div>

</div>

</div>

Testingbroadcast

www.it-ebooks.info

Page 186: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Thedocumentationathttps://docs.angularjs.org/api/ng/type/$rootScope.Scopestatesgivesthefunctionalityofthe$broadcast()methodasfollows:

Dispatchesaneventnamedownwardstoallchildscopes(andtheirchildren)notifyingtheregistered$rootScope.Scopelisteners.

Asopposedtothe$emitmethod,whichpusheseventsupthroughthescopechain,$broadcastpusheseventsdownthechain.Theotherimportantdistinctiontomakeisthatthe$broadcasteventcan’tbecancelled,but$emitcanbe.Thesearesmallintricaciesthatifnotunderstoodproperlycanhaveanegativeeffectontheapplication.Likewiththe$emitevent,thefollowingexampleshowsthewaybroadcastingworksthroughatest.

Testingbroadcast

Utilizingsimilartechniquesfromtheemissiontest,herearethestepstotestthebroadcastingofevents:

1. Createthespies:

vartopEventSpy=jasmine.createSpy();

varbottomEventSpy=jasmine.createSpy();

2. Initializethescopes:

vartopScope=$rootScope.$new();

varmiddleScope=topScope.$new();

varbottomScope=middleScope.$new();

3. Settherespectivecontrollerscopes:

$controller('TopController',{$scope:topScope});

$controller('MiddleController',{$scope:middleScope});

$controller('BottomController',{$scope:bottomScope});

4. Setthespiestolistenfortheevents:

topScope.$on('MIDDLEEMIT',topEventSpy);

bottomScope.$on('MIDDLEEMIT',bottomEventSpy);

5. BroadcasttheeventfrommiddleScope:

middleScope.$broadcast('MIDDLEEMIT');

6. Havetheexpectationthatthetopscopewasnottouched:

it('Shouldnotnotifytopcontroller',function(){

expect(topEventSpy.wasCalled).toBe(false);

});

7. Havetheexpectationthatthebottomscopereceivedthemessage:

it('Shouldnotifybottomcontroller',function(){

expect(bottomEventSpy.wasCalled).toBe(true);

});

TheprecedingexplanationshaveshowedhowtointegrateandtesttwotypesofAngularJS

www.it-ebooks.info

Page 187: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

events.Asyouprogressthroughtherestoftheeventtests,youwillfindthatthesetupandtechniquesusedherewillbeusedthroughouttherestofthechapter.

www.it-ebooks.info

Page 188: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Publishingandsubscribing–thegoodandbadKnowingwhentousepublishingandsubscribingisonething,butknowingwhennottousethemisthedifficultpart.

ThegoodBeforelookingattheproblemsthatpublishingandsubscribingcanleadto,herearesomeofthebestscenarioswhereyoucanusethistechnique:

CommunicatingimportanteventstodifferentcomponentsoftheapplicationReducingcoupling

Communicatingthroughevents

Whenthinkingabouteventsthatneedtobecoupled,itisimportanttothinkaboutwhatactionsaredrivingtheapplication.Givenabankapplication,eventsmightbeassimpleasDEPOSITEDandWITHDREW.Thesetwosimpleeventsmaybeusedinmanyotherplaces.Thinkaboutyouwantingtosendane-mailtothecustomereverytimetheywithdreworautomaticallyupdatedsomereal-timereport.Insteadofpollingthepersistencelayer,areal-timenotificationmessagecanbeused.InAngularJS,thismeansthattheUIcanbemadeupofdifferentcomponentsthatcanrespondtochangesinonearea,forexample,UInotifications,updatingworkflows,enablingfeatures,oranythingyoucanthinkof.

Communicatingeventssothatothercomponentscanrespondtothemiskey.Whenyouwanttoeasilyrespondtoeventsandchanges,publishingandsubmittingisthewaytogo.Thefollowingisanothertesttoshowhowcommunicationcanbeused:

1. Createscopesforthecontrollers:

recentTransactionScope=$rootScope.$new();

atmScope=recentTransactionScope.$new();

2. Assignthescopestothecontrollers:

$controller('AtmController',{$scope:atmScope});

$controller('RecentTransactionsController',

{$scope:recentTransactionScope});

3. Setthespies:

spyOn(atmScope,'$emit').and.callThrough();

spyOn(recentTransactionScope.recent,'push');

4. Callthemethodbeingtested:

atmScope.withdraw(3.33);

5. Settheexpectationthattheeventwasemitted:

it('shouldemitanevent',function(){

expect(atmScope.$emit).toHaveBeenCalled();

});

www.it-ebooks.info

Page 189: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

6. Settheexpectationthattherecenttransactionsreceivedtheevent:

it('shouldsendeventtorecenttransactions',function(){

expect(recentTransactionScope.recent.push).toHaveBeenCalled();

});

Herearethecontrollerstofurtherclarifythecode:

1. TheAtmControllerproperty(publisher):

bankModule.controller('AtmController',['$scope',function($scope){

$scope.withdraw=function(amount){

$scope.$emit('WITHDREW',amount);

}

}]);

2. TheRecentTransactionsControllerproperty(subscriber):

bankModule.controller('RecentTransactionsController',['$scope',

function($scope){

$scope.recent=[];

$scope.$on('WITHDREW',function(amount){

$scope.recent.push(amount);

})

}]);

Asdiscussedwiththetests,AtmControlleremitstheWITHDREWeventafterawithdrawaloccurs.

Theprecedingstepsarejustasimpleexampleofhowpublishingandsubscribingcanhelpcommunicateimportantactivitiesacrossyourapplication.

Reducingcoupling

Communicationisoneaspectofthebenefitsofpublishingmessages.Messaginggivesyoudecreasedcoupling.Thinkabouttheprecedingbankapplicationthatcommunicateswhenawithdrawaloccurs.Themessagesmaybeusedformanydifferentaspectsoftheapplication,andsinceitisdecoupled,wedon’tneedtoworry.Ifwethinkaboutitanotherway,thewithdrawfunctiondoesn’tcareabouttherestoftheapplication.Itonlyfocusesonthefactthatitwillperformawithdrawalandthensendamessageuponitscompletion.Fromthesubscriptionperspective,therecenttransactionsdon’tcarewherethewithdrawalhappens.Itonlyhastofocusonwhatitneedstodowhenthishappens.

Decouplingtheapplicationcanbeextremelybeneficialfromatestingperspective.Takeanotherlookatthebankapplicationifyouwanttorefactorandseparateoutthetests.YoucouldcreateanewtestthatisspecifictotheRecentTransactionsproperty.Sincetheapplicationisdecoupled,itdoesn’tcareaboutAtmController.Thetestcanbeseparatedoutasfollows:

1. ThebeforeEachfunctioncanbereducedtoonlydealwiththescopeofrecentTransactionsControllerand$rootScope:

www.it-ebooks.info

Page 190: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

varrecentTransactionScope={};

varrootScope={};

beforeEach(function(){

module('bank');

inject(function($controller,$rootScope){

rootScope=$rootScope.$new();

recentTransactionScope=$rootScope.$new();

$controller('RecentTransactionsController',

{$scope:recentTransactionScope});

});

spyOn(recentTransactionScope.recent,'push');

rootScope.$emit('WITHDREW',3);

});

2. InthebeforeEachfunction,addaspytohelpwithtesting:

spyOn(recentTransactionScope.recent,'push');

3. InsteadofcallingtheAtmControllerclass’swithdrawfunction,wecancall$emiton$rootScope:

rootScope.$emit('WITHDREW',3);

4. TheafterEachfunctionandtheexpectationarethesameasshownpreviously:

afterEach(function(){

recentTransactionScope.recent.push.calls.reset();

});

it('shouldsendeventtorecenttransactions',function(){

expect(recentTransactionScope.recent.push).toHaveBeenCalled();

});

Thisexamplehasshownthatusingmessaging,youcandecoupletests.Decouplingapplicationtestsallowstheapplicationtogrowwithouthavingtonegativelyrefactortheentireapplication.Intheprecedingcase,ifAtmControllerischanged,therecentTransactionstestandtherecentTransactionscontrollerwon’tneedtobechanged.AslongastheWITHDREWeventispublished,recentTransactionswillnothavetobeupdated.

www.it-ebooks.info

Page 191: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

HarnessingthepowerofeventsPublishingandsubscribingeventscanleadtosomeuglyandhard-to-understandspaghetticode.Nowthatthefoundationsforthechapterhavebeenreviewed,youcandiveintoimplementingeventsintothesearchapplication.

www.it-ebooks.info

Page 192: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TheplanThesearchapplicationfromChapter5,FlipFlop,isquitebasic.Atthispoint,itwillreturnasetofresults,andthenwhentheuserclicksonaresult,detailswillappear.Theapplicationprovidesafoundationforfuturedevelopment.Inthischapter,thefunctionalitywillbeexpandedtoincludepublishingandsubscribing.Hereistheplantoexpandthesearchapplication:

Thesearchapplicationwillberebrandedasastoreapplication,andthesearchresultswilldisplayalistofproducts.Whenaproductisselected,detailswillbedisplayed.Allselectedproductsfromthesearchwillbeavailableinanewviewfor“recentlyviewed”items.Thedetailedviewoftheproductwillhavetheoptionto“addtocart”,andtheproductwillthenbeavailableinthecartview.

Theplanissomewhatambitious,butwithalltheknowledgewehaveonTDDandAngularJS,thedevelopmentshouldflownicely.

www.it-ebooks.info

Page 193: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

RebrandingThesearchapplicationwillberebrandedintoastoreapplicationinsteadofrewritingthesearchfunctionalitythathasalreadybeenwritten.Inordertoleveragetheexistingsearchproject,itwillbecopiedintoanewprojectfile.Then,thenewprojectwillusetheteststodrivethedevelopmentchangesandrefactoring.Therefactorstepshavebeenleftout,butareviewofthecodewillshowhowthecodeandtestsweremodifiedtocreatetheproductapplication.

Therefactorstepsupdatedtheunittestsandapplicationtosupportthecorrectnamingfortheapplication.Itisimportanttotakeawaytwothingsfromthis:

Refactorsmalltointroducebigchanges.Smallincrementalchangeshelptoprogressivelygettothenextstageoftheapplication.Whenbigchangesoccur,itcanbeconfusingtoknowwhereandwhattochange.Withsmallchanges,eventhoughthesamecodeisrevisitedseveraltimes,youcanensurethetestspassateachstageinsteadofrippingtheapplicationapartcompletelyandthentryingtoputitallbacktogetheragain.TDDappliesduringrefactoringjustasmuchaswhendoingcoredevelopment.TherefactorstepsfollowedwerethesameastheTDDsteps.Startwithchangingthetesttomeetourspecificationandthenmakethecoderuntomeetthespecification.Applyingtheseprincipleshelpskeepproductivityandfocus.

Boththeunittestsandend-to-endtestspassfromtherefactorsteps.Itistimetoturntothefirstfeatureoftheapplication.

www.it-ebooks.info

Page 194: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SeeingrecentlyvieweditemsNowthattheinitialrefactoringiscomplete,thenewfunctionalityoftheproductapplicationcanbeconsidered.Thefirstspecificationthatwillbeconsideredistheabilitytosee“recentlyviewed”items.Thespecificationisbrokendownintotwosteps,asfollows:

TheuserselectsaproducttoviewthedetailsTheywillbeabletoseetheviewedproducts

Thisisanexampleofwherebroadcastingwouldbeagoodcandidate.Intheprecedingcase,thespecificationisconcernedwithwhenaproducthasbeenselected.Inotherwords,whenaneventoccurs,asubsequentactionneedstohappen.UsingAngularJSevents($broadcast()/$emit()),theeventofselectingaproducttoviewcanbepublishedandthenconsumedbytherecentlyviewedcomponent.

ThestandardTDDlifecyclewillbeusedtobuildthiscomponent:testfirst,makeitrun,makeitbetter.Wewillbeusingabottom-upapproach(unittestfirst).Themainreasonforchoosingthisapproachisthattherearemultiplecontrollersinvolved,anditwillbeeasiertostartatthebottomandmakeourwayupthroughtheapplication.

TestfirstThefirsttestwewillbewritingisthattheSearchControllerclasswillpublishaneventwhenaproductisselected.Thefollowingsectionsdetailhowtowritethetest.

AssemblingSearchController

HerearethestepstoassembletheSearchControllerclass:

1. Startwiththeteststubusingthefollowingcode:

describe('',function(){

beforeEach(function(){

});

it(function(){

});

});

2. GetthescopeofSearchControllersothatanactioncanbeperformed:

describe('',function(){

beforeEach(function(){

module('product');

inject(function($controller,$rootScope){

varsearchControllerScope=$rootScope.$new();

$controller('SearchController',{$scope:searchControllerScope});

});

});

it(function(){

});

});

www.it-ebooks.info

Page 195: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

3. PlaceaspyontheSELECTEDPRODUCTevent:

varselectedProductSpy=jasmine.createSpy();

varsearchControllerScope={};

beforeEach(function(){

module('product');

inject(function($controller,$rootScope){

searchControllerScope=$rootScope.$new();

$controller('SearchController',

{$scope:searchControllerScope,$rootscope});

searchControllerScope.$on('SELECTEDPRODUCT',selectedProductSpy);

});

})

4. Addacleanupfunctiontoclearthescopeaftereachtestandclearthespy:

afterEach(function(){

searchControllerScope={};

selectedProductSpy.reset();

});

Selectingaproduct

ThetestrequiresthataSELECTEDPRODUCTeventhasbeenpublished.TheeventwilloccurwhentheselectedproductmethodiscalledwithproductId:

varfakeProduct={productId:1};

searchControllerScope.selectProduct(fakeProduct);

Expectingeventstobepublished

TheexpectationisthatselectedProductSpyhasbeencalled:

it('',function(){

expect(selectedProductSpy).toHaveBeenCalled();

});

MakingthesearchcontrollerrunNowwehavetomakethetestpassandrun.Herearethesteps:

1. StartKarmausingthefollowingcommand:

$karmastart

2. You’llgetanerror,namelyTypeError:'undefined'isnotafunction(evaluating'searchControllerScope.selectProduct(fakeProduct)').Torectifythis,performthefollowingstep:

1. AddthemethodtoSearchController:

$scope.selectProduct=function(){};

3. Thenyou’llgettheerrorExpectedspyunknowntohavebeencalled.Error:Expectedspyunknowntohavebeencalled.Torectifythis,performthe

www.it-ebooks.info

Page 196: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

followingsteps:

1. Theexpectationhasfailed,whichmeansthespywasnevercalled.OpenupSearchControllerandaddfunctionalitytotheselectProductmethodtoemitanevent:

$scope.selectProduct=function(productId){

$rootScope.$broadcast('SELECTEDPRODUCT',productId);

};

2. Rerunthetest.

4. Thetestwillpass.

Nowwhenaproductisselected,theeventisbroadcasted.Anyfunctionwantingtoknowwhensomethinggetsselectedcansimplylistenforthebroadcast.

RecentlyviewedunittestThenextstepistoaddanothertestfromthesubscriptionsideoftheeventtoRecentlyViewedController.

Testfirst

Again,thewalk-throughoftheteststepswillusethe3A’s.

AssemblingRecentlyViewedController

HerearethestepstoassembleRecentlyViewedController:

1. Startwiththeteststubusingthefollowingcode:

describe('',function(){

beforeEach(function(){

});

it(function(){

});

});

2. GetthescopeofRecentlyViewedControllersothatanactioncanbeperformed:

describe('',function(){

beforeEach(function(){

module('product');

inject(function($controller,$rootScope){

varrecentlyViewedScope=$rootScope.$new();

$controller('RecentlyViewedController',

{$scope:recentlyViewedScope});

});

});

it(function(){

});

});

3. Confirmthatthenumberofrecentlyviewedproductsisequalto0:

www.it-ebooks.info

Page 197: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

expect(recentlyViewedScope.recent.length).toBe(0);

Invokingarecentlyvieweditem

TheactionforthistestisthattheSELECTEDPRODUCTeventhasbeenpublished.Nowaddthepublishevent:

varfakeProductEvent={productId:1};

$rootscope.$broadcast('SELECTEDPRODUCT',fakeProductEvent);

ConfirmingRecentlyViewedController

Theassertionisthatthenumberofrecentlyviewedproductsisnowequalto1:

it('',function(){

expect(recentlyViewedScope.recent.length).toBe(1);

});

MakingRecentlyViewedControllerrunHerearethestepstorunRecentlyViewedController:

1. StartKarmausingthefollowingcommand:

$karmastart

2. You’llgetanerror,namelyError:[ng:areq]Argument'RecentlyViewedController'isnotafunction,gotundefined.Torectifythiserror,performthefollowingsteps:

1. CreatetherequiredcontrollerandcreateanewfilenamedRecentlyViewedController.js.

2. Then,addthefollowingdetails:

angular.module('product')

.controller('RecentlyViewedController',['$scope',function($scope){

}]);

3. Rerunthetest.

3. Thenyou’llgettheerrorTypeError:'undefined'isnotanobject(evaluating'recentlyViewedScoperecent.length'),whichmeansthatthefirstexpectation,thatistherecentproduct0,hasbeenhit.Astheobjectisundefined,addittotherecentlyViewedScopescope.

4. Thenyou’llgettheerrorExpected0tobe1.Error:Expected0tobe1.Torectifythis,performthefollowingsteps:

1. Theexpectationhasbeenhit.Nowthebehavioroftheeventneedstobeaddedtothecontroller.

2. Add$rootScopetothecontroller:

.controller('RecentlyViewedController',

['$scope','$rootScope',function($scope,$rootScope){

www.it-ebooks.info

Page 198: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

3. Subscribetotheeventfrom$rootScope:

$rootScope.$on('SELECTEDPRODUCT',function(productEvent){

})

4. NowaddproductEventtotherecentarray:

$rootScope.$scope.recent.push(productEvent)

5. Rerunthetest.

5. Thetestswillnowpass.

End-to-endtestingTheunittestsarecompleteandwillverifythatthepublisherandsubscribercanbothcommunicatewithevents.Nowthewalk-throughwilllookattheapplicationasawholeandwillshowyouhowtocreateanend-to-endtest.Thespecificationforrecentlyvieweditemsisthatinagivensearchresult:

AproductisselectedItwillbeavailableintherecentlyvieweditems

Now,itistimetomoveontoactuallycreatingthetest.

Testfirst

Asalways,startbytranslatingthespecificationinthetestusingthe3A’s,asthetestswillutilizetheexistingtests.Assemblingtherecentlyviewedend-to-endtest

BeforeyourepeatthecodefromChapter5,FlipFlop,youshouldnoticethatthefirsttestalreadysearchesforandretrievesthesearchresults.Therefore,therecentlyviewedtestcanbeembeddedwithintheexistingtestforasearchresultthatisalreadyavailable.Atthebottomoftheexistingfunctionofasearchquery,initializetheteststub:

describe('whenItypeinasearchquery',function(){

//...

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

Thereisnothingelsetoassembleforthetest,andyoucanmoveontothenextstep.Selectingasearchresult

Now,searchResultneedstobeinvokedusingthefollowingsteps:

1. ThefirststepwillbetoselectthefirstsearchResultelement:

varfirstResult=searchResult.first();

www.it-ebooks.info

Page 199: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

2. Findthelinkwithinthefirstitem:

varresultLink=firstResult.element(by.css('a'));

3. Clickontheresult:

resultLink.click();

Confirmingrecentlyvieweditems

Nowthataproducthasbeenselectedandoneproducthasbeenaddedtotherecentlyvieweditemslist,weneedtoviewtherecentlyvieweditems.Herearethestepstodothis:

1. Gettherecentlyvieweditems:

varrecentlyViewedItems=element(by.repeater('itemsinrecent'));

2. Confirmthatthecountofrecentlyvieweditemsisequalto0:

expect(recentlyViewedItems.count()).toBe(1);

MakingtherecentlyViewedItemstestpass

Nowthetestneedstopass.Herearethestepstodothis:

1. Startthewebsite:

./node_modules/http_server/bin/http_server

2. RunProtractor:

./node_modules/protractor/bin/protractorchromeOnlyConf.js

3. You’llgetanerror,namelyExpected0tobe1..4. Theerroristhattheexpectationhasfailed.Itistimetoaddthecontrollerand

repeatertotherecentlyvieweditemslisttoshowtheitems:

<divng-controller="RecentlyViewedController">

<divng-repeat="iteminrecent">

{{item}}

</div>

</div>

5. Rerunthetest6. Theerroristhesameasbefore.Thistime,Protractorerrorsdon’tgiveanycluesto

whattheissueis.ThenextstepistoopenupabrowserandseewhatthewebbrowserJavaScriptconsoleissaying.Pointyourbrowsertohttp://localhost:8080/#/recentlyViewed.Immediately,oneerrorwillbevisible,namely[ng:areq]Argument'RecentlyViewedController'isnotafunction,gotundefined.Torectifythis,performthefollowingsteps:

1. Nowthatthereisanactualerrortofix,progresscanbemade.Theerrorindicatesthatthecontrollerwasnotavailable.Asthecontrollerhasnotbeenadded,itistimetoaddthecontrollertothepage.Openuptheindex.htmlpage

www.it-ebooks.info

Page 200: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

andaddthecontrollerreference:

<scriptsrc="app/recentlyViewedController.js"></script>

2. Rerunthetest.

7. Nowthetestwillbesuccessful.

Makingrecentlyvieweditemsbetter

Therecentlyviewedcontrollerisnowcomplete.Itwouldbenicetobetterorganizetheview,howeverthiscanhappenlater.Thepointofthisexercisewastoestablishcommunicationbetweenseparateviewsandcreateausablefunction.Thishasbeenachieved,andnowyoucanmovetothenextstepofthewalk-through.

www.it-ebooks.info

Page 201: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatingaproductcartAnotherimportantaspectoftheapplicationistheabilitytoaddproductstoacart.Apublishingandsubscriptionmodelwillbeusedtopublishwhenanitemhasbeensavedtoacart.Asubscriptiontotheeventwillthenkeeptrackofitemsinthecartsotheusercaneasilyseewhensaveditemsgetupdatedinrealtime.Hereisthespecificationgiventheproductdetailsofaparticularproduct:

IftheproductissavedtoacartProductwillbedisplayedintheproductcartview

Nowthenecessarythingsareinordertogetdowntothe3A’s.

PublishertestfirstThepublisherwillcomefromsearchDetailController.Thetestwillneedtoensurethatwhenanitemissaved,aneventispublished.

AssemblingsearchDetailController

ThesearchDetailControlleralreadyhassomeunittestswritten.Theexistingtestcanbeleveragedtoconfirmthepublishingfeature.Herearethestepstocreateasubtesttohandlethesavingofacart:

1. Startwithaninnerstub:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

})

2. Inordertotestthataneventhasbeenemitted,aspywillbeneededon$rootScope.Bringin$rootScopeandaddaspytoit:

//...

varsavedToCartEventSpy=jasmine.createSpy();

beforeEach(function(){

inject(function($rootScope){

$rootScope.$on('SAVEDTOCART',savedToCartEventSpy);

});

});

3. AddafterEachtoresetthespy:

afterEach(function(){

savedToCartEventSpy.calls.reset();

});

Invokingthesavingofaproduct

InthebeforeEachsection,selectthemethodandmakethefollowingchanges:

www.it-ebooks.info

Page 202: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

beforeEach(function(){

//...

varfakeProduct={productId:1};

searchDetailScope.saveProduct(fakeProduct);

})

Confirmingthesaveevent

Theexpectationisthatthespyhasbeencalled:

it('',function(){

expect(savedToCartEventSpy).toHaveBeenCalled();

})

MakingthesaveProducttestpassNowweneedtomakethetestpass.HerearethestepstomakethesaveProducttestpass:

1. StartKarma:

$karmastart

2. ThefirsterrorwillbeTypeError:'undefined'isnotafunction(evaluating'searchDetailScope.saveProduct(fakeProduct)').Ifyougetthiserror,thenfollowthesesteps:

1. Thefunctiondoesn’texistonthescope.Additusingthefollowingcode:

$scope.saveProduct=function(product){};

2. Rerunthetest.

3. NowtheerrorhashittheexpectationandsaysExpectedspyunknowntohavebeencalled.Inthiscase,followthegivensteps:

1. Thesmallestthingwecanaddtothetestistheabilitytoemittheeventfromthemethod.Firstadd$rootScopetothecontroller:

.controller('SearchDetailController',

['$scope','$routeParams','productService','$rootScope',function($sc

ope,$routeParams,productService,$rootScope){

2. ThenaddtheSbroadcast()eventtoit:

$rootScope.$broadcast('SAVEDTOCART',product);

3. Rerunthetest.

4. Thetestissuccessful.

TestforthesubscriberfirstThesubscriberunittestwillconfirmthatwhenaSAVEDTOCARTeventisemitted,thentheproductwillbeaddedtothecartobject.ThespecificationisasaSAVEDTOCARTeventis

www.it-ebooks.info

Page 203: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

given,thefollowingactionwillbeperformed:

Itwilladdtheproducttothecart

Assemblingtheproductcarttest

Herearethestepstoassembletheproductcarttest:

1. Createanewfile,spec/unit/cart.js.2. Startwiththebasestub:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

3. Initializethemodule:

module('product');

4. Initializethescopesothatexpectationscanbemade:

varscope={};

beforeEach(function(){

//...

inject(function($controller){

$controller('CartController',{$scope:scope});

});

});

5. Initialize$rootScopesosubscriptionscanbemade:

inject(function($controller,$rootScope){

scope=$rootScope.$new();

$controller('CartController',{$scope:scope,$rootScope:$rootScope});

});

6. Thelastthingtoconfirmisthatthecartisempty.Addthefollowingexpectationtoensurethetestissetupproperly:

expect(scope.cart.length).toBe(0);

Invokingasavedcartevent

ThistestisaroundthefactthatwhentheSAVEDTOCARTeventispublished,theCartControllerpropertywillperformaspecificaction.AddthepublishingoftheeventtothebeforeEachmethod:

beforeEach(function(){

//...

varfakeProduct={productId:1};

$rootScope.$broadcast('SAVEDTOCART',fakeProduct);

});

Confirmingthesavedcart

www.it-ebooks.info

Page 204: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Nowthatthetesthasbeensetupandtheactperformed,youcanassert.Assertthatthenumberofcartitemsisequalto1byaddingthefollowingcode:

it('',function(){

expect(scope.cart.length).toBe(1);

});

MakingthecartcontrollertestrunNowit’stimetowalkthetestthroughthecyclebyfollowingthegivenstepsuntilwegetagreentest:

1. StartKarma:

$karmastart

2. ThefirsterrorisError:[ng:areq]Argument'CartController'isnotafunction,gotundefined.Asseenpreviously,thecontrollerhasn’tbeencreated.Createanewfileandsetupastubcontroller(/app/cart.js):

angular.module('product')

.controller('CartController',['$scope',function($scope){

}]);

3. ThenexterrorwillbeTypeError:'undefined'isnotanobject(evaluating'scope.cart.length').Thisindicatesthatnoobjectwasfoundonthescopenamedcart.Goaheadandcreateitnowinapp/cart.js:

$scope.cart=[];

4. Then,you’llgetanexpectationerror,namelyExpected0tobe1.Error:Expected0tobe1.Torectifythis,performthefollowingsteps:

1. Atthispoint,thecontrollerisnotdoinganythingwiththeeventbeingemitted.Add$rootScopeasadependencytotheapplication:

.controller('CartController',

['$scope','$rootScope',function($scope,$rootScope){

2. Addthehandlinglogictocapturetheeventandaddtheproducttothecart:

$rootScope.$on('SAVEDTOCART',function(productEvent){

$scope.cart.push(productEvent);

});

5. Success!Allthetestshavepassed.

End-to-endtestingTheunittestsarenowcomplete,anditisnowtimetoperformend-to-endtestingforthecart.

Assemblingthecart’send-to-endtest

www.it-ebooks.info

Page 205: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ThetestcomesfromtheperspectiveofbeingonaproductdetailviewandselectingaSavetoCartbutton.Oncetheitemhasbeensaved,itshouldbeavailableinthecartview.Herearethestepstoassemblethecart’send-to-endtest:

1. Createanewfilenamedspec/e2e/cartScenario.js.2. Startwiththebasetemplatetest:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

3. Thenextthingweneedtodoisnavigatetoaproductpage:

browser.get("#/product/1");

4. Selectthebuttonthatwillsavethecart:

varsaveToCartButton=element(by.buttonText('SavetoCart'));

Invokingasavetocartaction

TheactionistoclickontheSavebuttonusingthefollowingcode:

saveToCartButton.click();

Confirmingproductshavebeensaved

Theassertistoconfirmthatthecartviewnowhasatleastoneproduct:

it('',function(){

varproductsInCart=element.all(by.repeater('productincart'));

expect(productsInCart.count()).toBe(1);

})

Makingthecart’send-to-endtestpassHereisthewalk-throughoftheprocessofmakingtheapplicationrun:

1. Startthesite:

$./node_modules/http-server/bin/http-server.

2. RunProtractor:

$./node_modules/protractor/bin/protractorchromeOnlyConf.js

3. ThefirsterrorisNoSuchElementError:Noelementfoundusinglocator:by.buttonText("SavetoCart").Torectifythis,performthefollowingsteps:

1. Goaheadandcreatethebuttonwithintheproductdetail’sapp/searchDetail.htmlpartialview:

<button>SavetoCart</button>

www.it-ebooks.info

Page 206: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

2. Rerunthetest.

4. ThenexterrorisExpected0tobe1.Torectifythis,performthefollowingsteps:

1. Thiserrormeansthatthecountis0forproductsinthecart.Byreviewingtheindexpage,youcanseethatthecartdoesn’tevenexistinthepage.First,addareferencetothecartcontroller:

<scriptsrc="app/cart.js"></script>

2. Next,theitemsinthecartneedtobeaddedtothepage.First,addatagwiththecontroller:

<divng-controller="CartController"></div>

3. Finally,addarepeatertodisplaytheproductinthecart:

<ul>

<ling-repeat="productincart">{{product}}</li>

</ul>

4. Rerunthetest.

5. Thesameerroroccurs,Expected0tobe1.Torectifythis,performthefollowingsteps:

1. Eventhoughtheproductdatahasbeenadded,thetestisstillfailing.Thenextquestioniswhetheranythingisbeingaddedtothecart.Inthiscase,no.Thebuttonisbeingselectedbutnoactionhasbeenassociatedwithit.Updatethebuttoninapp/searchDetail.htmltousethesearchDetailControllerclass’ssaveProductmethod:

<buttonng-click="saveProduct()">SavetoCart</button>

2. Rerunthetest.

6. Allthetestspass.

www.it-ebooks.info

Page 207: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsThefollowingaresomequestionstocheckyourunderstanding:

Q1.Whenbroadcastingamessage,itpropagatesupthescope’shierarchy.

1. True2. False

Q2.ThefollowingcreatesaspyinJasmine:

1. varspy=jasmine.createSpy();2. varspy=jasmine.$new();3. varspy=jasmine.createFake();

Q3.The$rootScopescopeisthehighestlevelscopeinAngularJS.

1. True2. False

Additionally,ifyouwantmorepractice,addtheabilitytoaddlikestothepage.

www.it-ebooks.info

Page 208: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThischapterhasexploredeventswithinAngularJS.YousawtwotypesofAngularJSeventemitters:$broadcast()and$emit().YoualsosawsomeexamplesofapplyingTDDtoeventsandhoweventsgiveaseparationofcontrollersandcode.Inaddition,youexpandedthetypesoftestingtechniquestoincludeservicesandreiteratedthetestingofcontrollersandmodels.YoualsoexploredfurtherconfigurationofKarmatouseitsfeatures.Inthenextchapter,youwilllookattheintegrationandtestingofdataandAPIsintoanAngularJSapplication.

www.it-ebooks.info

Page 209: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter7.GiveMeSomeDataApplicationsneedawaytoconsumetheever-expansiveworldofdata.Mostapplicationswrittentodayconsumedata.LuckilyforAngularJSdevelopers,consumingdataisquiteeasy.Testingdataconsumptionisalsoacorecomponentoftheframework.Inthischapter,wewillcoverthefollowingtopics:

IntegratingaREST-basedserviceCreatingandmockingAngularJS’s$httpHandlingexceptionsImplementingafakeAPIbuilderpattern

www.it-ebooks.info

Page 210: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

REST–thelanguageoftheWebRepresentationalStateTransfer(REST)defineshowtheWebshouldcommunicate.FromanAngularJSapplicationstandpoint,themainconcerniswiththeHTTPmethods.ForHTTPmethods,RESTcanbethoughtofastheverbsoractionsthatanHTTPrequestcanmake.Specifically,anHTTPrequestcanmaketheserequesttypes:GET,POST,PUT,andDELETE.FromanAPIstandpoint,theHTTPmethodscanbeusedtodeterminehowlogicshouldhandlethespecificHTTPrequesttype.HereisafurtherlookatthecommonHTTPmethods:

HTTPMethod Description Example

GET Retrievesdatafromanendpoint curl--requestGET'http://<SOMEURL>'

POST Postsanewdataelementtotheendpoint curl–requestPOST'http://<SOMEURL>'–data'anydata'

PUT Insertsorupdatestheencloseddataelementtotheendpoint curl–requestPOST'http://<SOMEURL>'–data'anydata'

DELETE Deletesarequesttotheendpoint curl--requestDELETE'http://<SOMEURL>'

NoteThecurltoolisacommand-linetoolthatcanbeusedtomakerequests.OnUnixmachines,itisavailableinthecommandlinebysimplytypingcurl.ForWindowsmachines,itisbesttoinstallGitbashandaccessitthroughtheGitbashcommandline.InstallationinstructionsforGitandGitbashcanbefoundathttp://git-scm.com/downloads.

Ascanbeseenfromtheprecedingexplanation,theRESTfulcomponentsofHTTPcandefinethebasicsformostAPIs.TheprecedingRESTapproachisdifferentfromotherwebservicetechniquesorprotocolsandcanbeusedbypracticallyanything.Fortheirsimplicity,REST-basedwebservicesarethebestoptions.Inthischapter,thefocuswillonlybeonhowtouseAngularJSwithaREST-basedAPI.

www.it-ebooks.info

Page 211: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

GettingstartedwithRESTBeforejumpingintohowAngularJScommunicateswithaRESTlayer,itisimportanttoseehowtocommunicateusingstandardtoolswithinabrowser.Asyousawfromthepreviousdefinition,curlcanbeusedtocommunicatetoaRESTAPI.AlthoughmakingamanualHTTPrequestoutsideofabrowserisuseful,youalsoneedtounderstandthebasicsofhowabrowsermakesanAPIrequestwithoutaframework.Inabrowser,requestscanbemadetoRESTlayersthroughasynchronouscalls.Thisallowsrequeststhatwon’taffecttheotherpartsoftheapplicationtobemade;thatis,thepagewon’tfreezeandbecomeunusable.Thewebpageremainsuseablewhiletherequestismade.

BrowsersprovideamechanismtomakeasynchronousRESTcallsusinganXMLHttpRequestmethod.AnXMLHttpRequestmethodcanbeusedtomakeanHTTPGET,POST,PUT,orDELETErequest.HereisanexampleofhowtomakeaGETrequest:

varrequest=newXMLHttpRequest();

request.open('GET','/any/rest/endpoint');

request.send();

Theprecedingexamplecreatesanewrequest,specifiestherequesttypeandlocation,andfinally,sendstherequest.Themissingpieceisthehandlingoftheresponse.Addthefollowingcodejustbeforethesendmethod:

request.onreadstatechange=function(){

if(request.readyState===4){

console.log('receivedresponsewithstatus:'+request.status);

}

};

Theprecedingcodehandleswhentherequesthasreceivedaresponsefromtheserverandiscomplete(readystate===4).Withintheconditiongiveninthecode,youcanhandletheparsingoftheresponse,thedeterminingstatusoftherequest,andsoon.

What’sgreatabouttheprecedingcodeisthatitdoesn’trequireaframework.Theproblemisthatthecodecangrowinsizeandbecomerepetitiveforeveryrequest.AngularJShasabstractedtherequestforyou.

www.it-ebooks.info

Page 212: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingasynchronouscallsNowthatyouunderstandhowtomakeHTTPrequeststhroughthebrowser,weneedtounderstandhowtotestthesecalls.Theprecedingrequestsareasynchronous.Asynchronousmeansthereisnoguaranteeofwhenthefunctionwillcomplete.Foryourreference,hereisanexampleofsynchronoussequentiallogic:

varsynchronousFunc=function(){

console.log('InsynchronousFunc');

};

synchronousFunc();

console.log('AftercalltosynchronousFunc');

Whentheprecedingcodeisrun,theoutputisasfollows:

InsynchronousFunc

AftercalltosynchronousFunc

Eachfunctioncalloccursintheorderofthecall.Withanasynchronousrequest,theorderisnotguaranteed.Acallbackfunctionispassedintoafunctiontoinformyouwhenamethodiscomplete.

TipCallbackfunctionshavetwomainconventions.ThefirstisthejQuery-basedmethod.ThesecondistheNode.jsmethod.ThejQueryconventionusestwocallbacksasthelastargumentstoamethod.Thefirstcallbackisforsuccess,andthesecondisforanerror.TheNode.jsconventionistouseasinglecallbackasthelastargument.Thecallbackhastwoparameters,thefirstbeinganerrorandthesecondbeingthesuccessfulresult.

Itisuptoyoutodecidewhichconventiontousebasedonwhatyou’redevelopingfor.Don’tcreateyourownnewconvention;useoneoftheprecedingconventionssothatotherdeveloperscaneasilyunderstandandreadyourcode.

Hereisanexampleoftheoutputofanasynchronousmethod:

varasynchronousFunc=function(callback){

setTimeout(callback,0);

};

varcallback=function(){

console.log('InasynchronousFunc');

};

asynchronousFunc(callback);

console.log('AftercalltoasynchronousFunc');

Whentheprecedingcodeisrun,theoutputisasfollows:

AftercalltoasynchronousFunc

InasynchronousFunc

ThenextsectionswilllookathowtesttoasynchronousfunctionsinKarmaandProtractor.

www.it-ebooks.info

Page 213: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatingasynchronouscallsinKarmaFromtheprecedingasynchronousexample,itshouldbeclearthatthewayinwhichyoutestneedstobemodifiedtoaccountforasynchronousbehavior.Luckily,thisisfairlystraightforwardwhentestingwithKarma.

HerearethestepstotesttheprecedingasynchronousmethodusingKarma:

1. Createthestubtestusingthefollowingcode:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

2. Createaspytotestwhentheasynchronousmethodgetscalled:

varspy=jasmine.createSpy();

3. CalltheasynchronousmethodinthebeforeEachfunction:

beforeEach(function(){

varasynchronousFunc=function(callback){

setTimeout(callback,0);

};

varcallback=function(){

spy();

};

asynchronousFunc(callback);

});

4. AddacallbacktotheparametersofthebeforeEachfunction.Bydoingthis,youhavemadethefunctionasynchronous:

beforeEach(function(done){

});

5. CallthedonemethodintheasynchronousFunccallback:

varcallback=function(){

spy();

done();

};

6. Addtheassertionfunction:

it('',function(){

expect(spy).toHaveBeenCalled();

});

ThekeytotheprecedingcodeisthatacallbackwaspassedintothebeforeEachfunction.Youcantrytorunthistestwithoutthecallbackandseewhetherthetestwillfail.A

www.it-ebooks.info

Page 214: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

callbackcanbepassedintothebeforeEach,afterEach,describe,anditmethods.

Youwillbeleveragingthisexamplethroughtherestofthechapter,sobesurethatyouunderstandthemainconcepts.NowthatyouhavetestedinKarma,thenextsectionwillshowyouwhatProtractoroffersfromanasynchronousstandpoint.

www.it-ebooks.info

Page 215: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatingasynchronouscallsinProtractorProtractorisdifferentinthewayithandlesasynchronousactions.Ithasbeenoptimizedtohandleasynchronousactions,specifically,promises.Asanexample,whenatestnavigatestoapage,ProtractorwillwaituntilAngularJShasbeenloadeduntilitstartsrunningthetests.JulieRalph,themaincontributorandcreatorofProtractor,sumsitupinthisGitHubissue(https://github.com/angular/protractor/issues/716):

ProtractorpatchesJasminesothatitisautomaticallyasynchronous,andatestcasefinisheswhentheWebDriverqueueofcommandsisfinished.

Whatthismeansisthatyoudon’thavetothinkabouthowthecallsarebeingrenderedandwhenthepromisesarecomplete.Itevenwaitsfor$httprequeststocomplete.HereisanexampleofusingProtractor:

describe('WhenItypeinasearchquery',function(){

varsearchResult=element.all(by.repeater("resultinresults"));

beforeEach(function(){

browser.get("/index.html");

$('input').sendKeys('anyvalue');

element(by.buttonText('search')).searchButton.click();

});

it('Shouldthenaddtheresult',function(){

expect(searchResult.count()).toBe(1);

});

});

TheprecedingcodesnippetistakenfromChapter6,TelltheWorld.IthighlightshowProtractorexecuteseachoneofthecommandsandtakescareoftheasynchronousbehaviorsforyou.Inthenextsection,youwillseehowtomakeRESTrequestsusingAngularJS.

www.it-ebooks.info

Page 216: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakingRESTrequestsusingAngularJSNowthatwehavelookedatwhatRESTrequestsareandseenhowtotestasynchronouslyinKarmaandProtractor,itistimetoseehowtomakearequestinAngularJS.Atthelowestlevel,AngularJSprovidesthe$httpmodule.ThemoduleallowsyoutomakeHTTPrequests.Byvisitingthedocumentation(https://docs.angularjs.org/api/ng/service/$http),wecanseethatitsaysthefollowing:

The$httpserviceisacoreAngularservicethatfacilitatescommunicationwiththeremoteHTTPserversviathebrowser’sXMLHttpRequestobject.

AsyouhavealreadyseenhowtomakeanXMLHttpRequest,youshouldfeelateasethatyouknowwhatisgoingonunderthehood.Hereisasimpleexampleofhowtomakean$http.getrequestinAngularJS:

$http.get('/any/rest/endpoint')

.success(function(data,status,header,config){

});

.error(function(data,status,header,config){

});

Thesuccess/errorfunctioniscalledasynchronouslyoncetherequestiscomplete.

Using$httpisnottheonlywaytomakearequest.IfanAPIiscompletelyREST-based,AngularJSprovidesthe$resourcemodule.Aresourcegetsdefinedandusedasshowninthefollowingsteps:

1. Definearesourceforaspecificendpoint:

varthing=$resource('/any/rest/endpoint/:id',{id:'@id'});

2. MaketheHTTPGETrequest:

thing.get({id:1},function(aThing){

});

TheprecedingexampledefinesaresourcethatretrievesaThingbasedonanID.ItthenretrievesthatdatawithaGETrequest.

BothoftheprecedingexamplesshowyouhowtocreaterequestsinAngularJS.Youwillbelookingatthe$httpmethodintheremainingexamples,butitisgoodtounderstandthedifferentwaysinwhichrequestscanbecreatedinAngularJS.

www.it-ebooks.info

Page 217: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestingwithAngularJSRESTNowthatyouhaveseenhowtomakerequestsinAngularJSandhowtotestasynchronously,youwillneedtolookathowtoputittogether.ThefollowingexamplelooksataspecificserviceandthendiscusseshowtotestusingKarma.

TestingtheproductserviceTheservicethatneedstobetestedisasfollows:

angular.module('anyModule')

.service('productService',['$http',function($http){

return{

search:function(query){

return$http.get('/product/search');

}

};

});

TheprecedingproductServiceparameterprovidesanobjectsearchthattakesinaqueryandreturnsa$httppromise.Theproductservicecanbeusedinacontrollerasfollows:

productService.search(query)

.success(function(data){

$scope.result=data;

})

.error(function(data){

$scope.error=data;

});

angular.module('anyModule')

.controller('productController',['$scope','productService',

function($scope,productService){

$scope.search=function(query){

productService.search(query)

.success(function(data){

$scope.result=data;

})

.error(function(data){

$scope.error=data;

});

}]);

TheprecedinguseoftheproductServiceshowsyouthatbecausean$httppromiseisreturned,youcanusethesuccessanderrorfunctionstodefinewhatneedstooccurafter.Nowthatthereisacontrollerandaservice,thenextsectionwillshowyouhowtotestthecomponents.

Testing$httpwithKarmaTheKarmatestwilllooktoconfirmthebehaviorofproductServiceifthe$httpcallissuccessfulandisonetolookatifanerroroccurs.Themaindifferencebetweenthistestandothersthathavebeenlookedatsofaristhatyouarecreatingarequesttosomething

www.it-ebooks.info

Page 218: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

outsideofAngularJS.Thisisaperfectcaseofusemocking.Youcansetupafakeobjectaround$httptotestthesuccessanderrorpathsoftherequest.AngularJSprovidesamockobjectthatcanbeused,whichisAngularmock’s$httpBackend.

Herearethestepstocreateapositivetest—whentherequestissuccessful:

1. Startwiththeteststub:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

2. Initializethemodule:

beforeEach(function(){

module('anyModule');

});

3. Inject$httpBackendandproductServiceinthebeforeEachfunction:

var$httpBackend=null;

varproductService=null;

beforeEach(function(){

module('anyModule');

inject(function(_$httpBackend_,_productService_){

$httpBackend=_$httpBackend_;

productService=_productService_;

});

});

4. MocktheGETsuccessfulrequestwithanHTTPstatuscodeof200asfollows:

it('',function(){

$httpBackend.when('GET','/product/search').respond(200,'');

});

5. Settheexpectationasfollows:

it('',function(){

$httpBackend.expectGET('/product/search');

});

6. MakethecalltoproductServiceusingthefollowingcode:

productService.search('any');

7. Flushtherequestusingthefollowingcode:

$httpBackend.flush();

Asyoucansee,$httpBackendallowsexpectationsandmockresponsestobecontrolled.Totieuplooseends,herearetheadditionalexpectationsforafailedrequest.Followthestepstoaddexpectationsforafailedrequest:

www.it-ebooks.info

Page 219: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

1. Addtheexpectationstubtoanasynchronousparameter:

it('',function(done){

});

2. MocktheGETunsuccessfulrequestwithanHTTPstatuscodeof500:

$httpBackend.when('GET','/product/search').respond(500,'');

3. CallproductService.Search:

productService.search('any');

4. Confirmthattheerrorfunctiongetscalled:

productService.search('any').error(function(){

expect(true).toBe(true);

done();

});

5. Flushtherequest:

$httpBackend.flush();

Wehavenotaddedanyotherlayerstotheapplicationandareabletoconfirmhowitwillworkduringasuccessfulandunsuccessfulrequest.Inthenextsection,youwillseehowtotestHTTPrequestsinProtractor.

www.it-ebooks.info

Page 220: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MockingrequestswithProtractorNowthatunittestsforthebackendarecomplete,youcanmovetothefrontendandtestanHTTPrequestthroughProtractor.Youmightnotalwayswanttodothis.Protractorissupposedtotestyoursitefromanend-to-endperspective.Thismeansthatalllayersoftheapplicationwillbetouched.Onebenefitofthefollowingexampleisthatitwillhelpincaseswhereyouhaven’tsetupthebackendrestservice.Youcanbeginbylayingoutthepageandinteractionsbeforethebackendiscomplete.Thiscanhelpwhenyou’rejustputtingyoursitetogether.

InordertomockthebackendHTTPlayerforProtractor,wewilluse$httpBackend,whichispartofthengMockE2EmoduleandisusedtomockthebackendHTTPlayerforProtractor.The$httpBackendpropertyusedforProtractorisdifferentfromtheoneusedinthepreviousKarmatest.Touseend-to-end$httpBackendyouwillneedtoinjectngMockE2Easadependencyintotheapplication.Forthisreason,itisnotaviablesolutiontohaveinaproductionsite.

Herearethestepsthataretobemockedusing$httpBackendinProtractor:

1. AddAngularJSandAngularmockstothewebpage:

<scriptsrc="bower_components/angular/angular.js"></script>

<scriptsrc="bower_components/angular-mocks/angular-mocks.js"></script>

2. CreateamoduleandrequirengMockE2E:

angular.module('anyModule',['ngMockE2E'])

3. Addarunfunctionthatuses$httpBackend:

.run(['$httpBackend',function($httpBackend){

4. Createthemockdata:

.run(['$httpBackend',function($httpBackend){

varproducts=[{id:'id1',name:'product1'},{id:

'id2',name:'product2'}];

}]);

5. Setthemockdatarequest:

.run(['$httpBackend',function($httpBackend){

varproducts=[{id:'id1',name:'product1'},{id:

'id2',name:'product2'}];

$httpBackend.whenGET('/product/search').respond(products);

}]);

Nowtherequestto/product/searchwillrespondwiththeproductsdefinedinthemock.Thismeansthattheapplicationwillworkwithouttheneedforabackendserviceandwillbeabletobetestedasanapplicationwithabackendservice.Acompleteexampleusingamockedbackendwillbeshowninthewalk-through.

www.it-ebooks.info

Page 221: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

DisplayingproductswithRESTAllthecorecomponentsofREST,asynchronoustesting,andmockingHTTPrequestshavebeendiscussed.Now,thefollowingwalk-throughwillprovideafullexamplethatwilllookatdisplayingproductsthatareretrievedthroughanexternalservice.Theexamplewillignorethecreationofanexternalserviceandfocusonthedataitprovides:alistofproductsinaJSONformat.Thewalk-throughwilltakeabottom-upapproachsothatthecoredatalayerisworkedoutbeforeaddingtheUIelements.

www.it-ebooks.info

Page 222: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

UnittestingproductrequestsTheapproachfromtheunitlevelistocreateaservicetomanagetheHTTPrequestsforproducts.Thecontrollerwillthenbebuiltupthesameway.

SettinguptheprojectBeforewritingtests,theprojectneedstohaveastructure.Hereiswhattheinitialprojectstructurelookslike:

KarmaconfigurationNowthattheprojecttemplatehasbeensetup,acoupleofadjustmentsneedtobemade.TheKarmaconfigurationneedstouseaheadlessbrowserandsetupthetestfilestothecorrectlocation.Openupkarma.conf.jsandmakethefollowingchanges:

1. UpdatethebrowserssectiontoPhantomJSforheadlessbrowsertesting:

browsers:['PhantomJS'],

2. Updatethefilessectiontoincludetheunittestfolders:

files:[

'bower_components/angular/angular.js',

'bower_components/angular-mocks/angular-mocks.js',

'app/**/*.js',

'spec/unit/**/*.js'

],

Karmahasbeenconfiguredandtheprojecttemplatehasbeencreated.ThenextstepistosetupanAPIbuilderfortheproductdata.Thiswillallowforaconsistentinterfacetobeusedinatestwheremockingdataisrequired.

UsinganAPIbuilderpatternAbuilderisanobjectthatisusedtocreateanotherobject;itwillbeusedtocreatetestdata.AnAPIbuildercanreduceduplicationandthetimetakentocreatetests.Itprovidesacentralwaytohandlemethodsandcreatedata.Ifabuilderisnotused,theneverytestwrittenwillhavetohaveaseparatedistinctwayofcreatingdata.Thisisanespeciallybad

www.it-ebooks.info

Page 223: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

designwhentheAPIbeingusedchanges!

TheproductdataAPIisdefinedbyasingleroute/products.Theexpectedresponseisalistofproducts.HerearethestepstocreateabuilderfortheproductAPI:

1. CreateanewfileinthespecfoldernamedproductDataBuilder.js:

$touchproductDataBuilder.js

2. CreateanewfunctionnamedproductDataBuilder:

module.exports=functionproductDataBuilder(){};

3. ReturnanobjectwithmethodstosetIDs,names,andtoactuallybuildanobject:

module.exports=functionproductDataBuilder(){

return{

withId:function(id){

},

withName:function(name){

},

build:function(){

}

};

};

4. Initializeabasicproduct:

module.exports=functionproductDataBuilder(){

return{

_mockProduct:{id:1,name:'productName'},

withId:function(id){

},

withName:function(name){

},

build:function(){

}

};

};

5. Havethesettercommandsupdatethemockproduct:

return{

...

withId:function(id){

this._mockProduct.id=id;

returnthis;

},

withName:function(name){

this._mockProduct.name=name;

returnthis;

},

};

6. Havethebuildmethodreturnthemockdata:

return{

build:function(){

www.it-ebooks.info

Page 224: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

returnthis._mockProduct;

}

};

Thebuilderallowsyoutouseafluentinterfacetocreateproducts.Thesimplestuseisasfollows:

varproductDataBuilder=require('../productDataBuilder');

varsomeProduct=productDataBuilder.build();

AmorecomplicatedusewillbetosettheIDandnametosomethingsuchasthefollowing:

varproductDataBuilder=require('../productDataBuilder');

varsomeProduct=productDataBuilder.withId(9999)

.withName('Product9999');

TheprecedingproductDataBuilderobjectwillbeusedintheKarmatest.

www.it-ebooks.info

Page 225: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TheproductdataserviceIt’stimetogettotheactualtest.ThesameTDDlifecyclethathasbeenusedthroughoutthebookwillbeused;testfirst,makeitrun,andmakeitbetter.AsthecreationandtestingofaservicethatusesHTTPhasalreadybeendiscussed,thiswalk-throughwillbeskipped.Forreference,thetestsareinthecoderepositoryandtheserviceisdefinedasfollows:

angular.module('product')

.service('productService',['$http',function($http){

return{

getAll:function(){

return$http.get('/products')

}

};

}]);

Withtheservicecomplete,thenextstepistolookatthecontrollerandhowtoactuallymakeuseoftheHTTPdata.

www.it-ebooks.info

Page 226: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TheproductdatacontrollerThenextcomponentneededisacontrollersothattheUIcanuseproductService.Thecontrollerneedstohaveonemethodtomaketherequestforproducts.Inthemethod,itneedstoset$resultwhentherequestissuccessfuland$errorwhentherequestisunsuccessful.

AssemblingtheproductcontrollertestHerearethestepstoassembletheproductcontroller:

1. Createanewtestfilefortheproductcontrollerspec/productController.js:

$touchspec/productController.js

2. Usethestandardteststub:

describe('',function(){

beforeEach(function(){

});

it(function(){

});

});

3. Createvariablesforscopeand$httpBackend:

varscope={};

var$httpBackend=null;

4. Initializetheproductmodule:

beforeEach(function(){

module('product');

});

5. Getthe$controllerand$httpBackend:

beforeEach(function(){

inject(function($controller,_$htttpBackend_){

});

});

6. Set$httpBackendtotheinjectedvariable:

inject(function($controller,_$httpBackend_){

$httpBackend=_$httpBackend_;

7. Initializethecontrollerscope:

inject(function($controller,_$httpBackend_){

$httpBackend=_$httpBackend_;

$controller('ProductController',{$scope:scope});

Gettingproducts

www.it-ebooks.info

Page 227: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Theobjectundertestisthecontroller’sscopegetAllmethod.HerearethestepstocallthemethodforasuccessfulHTTPresponse:

1. ForasuccessfulHTTPresponse,usethebuildertobuildatestproduct:

it('',function(){

vartestProduct=productDataBuilder().build();

});

2. MocktheHTTPrequestresponsetoreturntestProduct:

$httpBackend.when('GET','/products').respond(200,[testProduct]);

3. Calltheobjectundertest:

scope.getAll()

Now,theunsuccessfulHTTPresponserequiresanerrorresponse.HerearethestepsfortheunsuccessfulHTTPrequest:

1. MocktheHTTPrequestresponsetoreturntestProduct:

it('',function(){

$httpBackend.when('GET','/products').respond(200,[testProduct]);

});

2. Calltheobjectundertest:

scope.getAll()

TheHTTPresponsehasbeencovered,andthenextstepwillasserttheexpectation.

AssertingproductdataresultsAnassertioncanbeusedtorequirethatanHTTPrequestreceivesaresponse.Themocked$httpBackendpropertycancalltheflush()methodtoexecutetheHTTPresponsesynchronously,soyoudon’thavetoworryaboutasynchronousissues.HerearethestepsforthesuccessfulHTTPresponseexpectation:

1. Flushtherequest:

$httpBackend.flush();

2. ExpecttheresultvariableonthescopeobjecttohavetestProductData:

expect(scope.results[0]).toEqual(testProductData);

HerearetheassertstepsfortheunsuccessfulHTTPresponseexpectation:

1. FlushtheHTTPrequestusingthefollowingcode:

$httpBackend.flush()

2. Confirmthatthescopes’errorvaluehasbeenset:

www.it-ebooks.info

Page 228: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

expect(scope.error).toEqual('error');

Nowthatthetestshavebeenassembled,thenextstepistomakethemrun.

www.it-ebooks.info

Page 229: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakingtheproductdatatestsrunHerearethestepstogetthecontrollertestrunning:

1. RunKarma:

$karmastart

2. ThefirsterrorisError:[ng:areq]Argument'ProductController'isnotafunction,gotundefined.Torectifythis,performthefollowingsteps:

1. ThiserrormeansthatProductControllerdoesn’texist.Createacontrollerstubinapp/productController.js:

angular.module('product')

.controller('ProductController',['$scope',function($scope){

}]);

2. Rerunthetest.

3. ThisnexterrorisTypeError:'undefined'isnotafunction(evaluating'scope.getAll()').Torectifythis,performthefollowingsteps:

1. ThiserrormeansthatthereisnofunctioncalledgetAllinthecontroller.Addthefunctionnow:

.controller('ProductController',['$scope',function($scope){

$scope.getAll()=function(){

};

}]);

2. Rerunthetest.

4. ThenexterrorisError:Nopendingrequesttoflush!.Torectifythiserror,performthefollowingsteps:

1. ThiserroroccursbecausethetestisexpectinganHTTPrequesttobeflushedbutthereisnorequest.AddproductServicetocontrollersothattherequestwillgetmade.AddproductServiceasadependency:

.controller('ProductController',

['$scope','productService',function($scope,productService){

2. AddproductServicetothegetAllfunction:

scope.getAll=function(){

productService.getAll();

};

3. Rerunthetest.

5. ThenexterrorisExpectedundefinedtoequal{id:1,name:'productName'}.Torectifythiserror,performthefollowingsteps:

www.it-ebooks.info

Page 230: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

1. Thiserroroccursbecausescope.resultshasnotbeensetwhentheproductservicewassuccessful.AddasuccessfulcallbacktoproductServiceandsetthescope’sresultsvariable:

productService.getAll()

.success(function(data){

$scope.results=data;

});

6. Nowwe’redowntoonefailure,whichisExpectedundefinedtoequal.Torectifythis,performthefollowingstep:

1. Thiserroroccursbecausewehaven’thandledtheerrorconditionoftheHTTPrequest.AddtheerrorconditionofproductServicesothatitsetsthescope’serror:

productService.getAll()

.success(function(data){

$scope.results=data;

})

.error(function(error){

$scope.error=error;

})

7. Confirmthatallthetestspassnow.

Theunittestsfortheproductcontrollerhavebeencompletedusingamockedbackendtotestbothpositiveandnegativescenarios.Thenextstepcanbeskipped,astherewerenocalloutsduringdevelopment.

Thenextsectionwilllookathowtotestfromanend-to-endperspective.

www.it-ebooks.info

Page 231: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Testingmiddle-to-endNowthattheunitleveltestingoftheapplicationiscomplete,theuserfacingtestscanbeworkedon.OneofthebenefitsofAngularmocksisthatitprovides$httpBackend,whichcanbeusedtomockdataforend-to-endtests.Asdataisbeingmocked,itisreallyamiddle-to-endtest.ThisisbecauseonlytheUIinteractionsarebeingtested,astherestofthebehaviorhasbeenmocked.ThiswillallowustocreatescaffoldingfortheUIlayer.Oncethedevelopmentiscomplete,thescaffoldingcanberemovedandafullend-to-endtestcanbeputinplace.

HerearetheinitialsetupstepstocreatetheapplicationUIusingamockedbackendwithProtractor:

1. InstallProtractor:

$npminstallprotractor

2. UpdateWebDriver:

$./node_modules/protractor/bin/webdriver-managerupdate

3. Copytheexample’sChrome-onlyconfiguration:

$cp./node_modules/protractor/example/chromeOnlyConf.js.

4. OpenupthechromOnlyConf.jsandupdatethedrivertopointtothenode_modulesdirectory:

chromeDriver:'./node_modules/protractor/selenium/chromedriver',

5. UpdatethebaseURLvariable:

baseUrl:'http://localhost:8080/',

6. Updatethetestdirectory:

specs:['spec/e2e/**/*.js'],

7. AddngMockE2easadependencytotheproductmoduleintheapporproduct.jsfile:

angular.module('product',['ngMockE2e'])

8. Setupthemockrequest:

.run(['$httpBackend',function($httpBackend){

vartestProduct=productDataBuilder().build();

varproducts=[testProduct];

$httpBackend.whenGET('/products').respond(products);

}]);

9. Createtheindex.htmlpageusinganHTMLstub:

<!DOCTYPEhtml>

<html>

<head>

www.it-ebooks.info

Page 232: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

<title></title>

</head>

<body>

</body>

</html>

10. AddtheAngularJSreferences:

<scriptsrc="bower_components/angular/angular.js"></script>

</body>

11. Addtheproductmodule,controller,andservice:

<scriptsrc="app/product.js"></script>

<scriptsrc="app/productService.js"></script>

<scriptsrc="app/productController.js"></script>

12. Formockingpurposes,addAngularmocksandtheproductdatabuilder:

<scriptsrc="bower_components/angular-mocks/angular-mocks.js"></script>

<scriptsrc="spec/productDataBuilder.js"></script>

Theinitial’sindexpageandmockhasbeensetup.ThenextstepwillwalkthroughtheTDDlifecycleandgettheapplicationrocking.

www.it-ebooks.info

Page 233: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestfirstThefirststepinthelifecycleistocreatethetestsusingthe3A’s.Thetestconfirmsthattheproductdatawillbevisibleonthepageonceauserpushesabuttontogettheproductdata.

AssemblingtheproducttestHerearethestepstoassembletheProtractortest:

1. Createanewfileforthetestcalledspec/e2e/productScenario.js:

$touchproductScenario.js

2. Createtheteststub:

describe('',function(){

beforeEach(function(){

});

it('',function(){

});

});

3. Browsetheapplication:

beforeEach(function(){

browser.get('/index.html');

});

4. Findthebuttonthatwewillbeselecting:

beforeEach(function(){

varproductButton=element(by.buttonText('GetProducts'));

});

Nowthatthetesthasbeenassembled,wecanhittheobjectundertest.

GettingproductsTheactionofthistestistoselecttheproductbutton.AswehavealreadyretrievedthebuttonintheAssemblesection,wecannowclickonit:

beforeEach(function(){

varproductButton=element(by.buttonText('GetProducts'));

productButton.click();

});

Finally,itistimetocreatetheassertionsandexpectations.

ExpectingproductdataresultsTheassertionforthistestistoensurethattheproductdataisnowdisplayed.Herearethesteps:

1. Findtheresults:

www.it-ebooks.info

Page 234: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

varresults=element.all(by.repeater('resultinresults'));

2. Assertthatthecountisgreaterthan0:

expect(results.count()).toBeGreaterThan(0);

Thetestsetupiscomplete.Thenextstepistomakeitrun.

www.it-ebooks.info

Page 235: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakingtheproductdatarunAshasbeendonewiththeotherProtractortests,oneprocesswillberunningtheHTTPpageandtheotherwillberunningtheprotractortest:

1. Installhttp-serversothatwecanrunthewebsite:

$npminstallhttp-server

2. Startthewebsite:

$./node_modules/http-server/bin/http-server.

3. Inanothercommandwindow,runtheprotractortests:

$./node_modules/protractor/bin/protractorchromeOnlyConf.js

4. ThefirsterrorisError:Angularcouldnotbefoundonthepagehttp://localhost:8080/index.html:angularneverprovided

resumeBootstrap.Torectifythis,performthefollowingsteps:

1. Theprecedingerrorisduetothefactthatwehaven’treferencedtheapplicationmoduleinthewebpage.Addtheproductmoduletothebodyoftheapplication:

<bodyng-app='product'>

2. Rerunthetests.

5. ThenexterrorisNoSuchElementError:Noelementfoundusinglocator:by.buttonText("GetProducts").Torectifythis,performthefollowingstep:

1. Addthebutton:

<button>GetProducts</button>

6. ThenexterrorhashittheexpectationandstatesExpected0tobegreaterthan0.Tofixthis,weneedtofirstaddproductControllertothepage:

<divng-controller='ProductController'>

<button>GetProducts</button>

</div>

7. Thenextstepistoassociatethebutton-clickwiththeProductControllerclassesscopetogetallproducts:

<buttonng-click='getAll()'>GetProducts</button>

8. Thefinalstepistodisplayallresults:

<divng-repeat="resultinresults">

{{result}}

</div>

Thetestnowshowsasuccessfulresult.

www.it-ebooks.info

Page 236: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Themakeitbetterstepwillbeskippedasthereisnothingimmediatethatneedstoberefactored.Atthispoint,theapplicationistestedandoperatedusingthemockeddata.Youshouldbeabletoseehowpowerfulthistechniquecanbeasyou’rebuildingupanapplication.Thenextsectionwilllookatremovingthescaffoldingandusinganactualbackend.

www.it-ebooks.info

Page 237: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Testingend-to-endRemovetheAngularmocksscaffoldingandsetupthetesttoactuallyconnecttotherealserverandsetup.

ThebackendofAngularmocksallowedustocreatetheapplicationwithouttheneedtoactuallyreturndata.Nowthattheapplicationhasbeensetup,wecanremovethescaffoldingandcreatearealHTTPrequestforthedata.Herearethesteps:

1. RemovengMockE2eandthemockresponsefromtheproductsmoduleinapp/product.js:

angular.module('product',[]);

RemoveAngularmocksandproductDataBuilderfromtheindex.htmlpage

2. ReruntheProtractortest.3. Theerrorstatesthefailedexpectation.

NowthatthemockHTTPresponsehasbeenremoved,weneedtoaddanactualrequest.Luckilyforus,wedon’thavetouseanyothertoolorframeworkandcanusethehttp-servermodulethatwehavebeenusingthewholetime.Inareal-worldexample,theproductroutewouldliveinaseparateservice,butthisexamplewilluseasimplerapproachforbrevity.

www.it-ebooks.info

Page 238: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

GettingtheproductdataThehttp-servermodule,whichisusedtoservestaticcontent,canbeextendedtoservestaticcontentaswell.Thisallowsustosetupastaticfilethatmirrorsarequestroute.Inthiscase,asingleJSONfileofproductswillbeused.Theproductsfilewillhaveanarrayofproductdata.Herearethesteps:

1. Createanewfilenamedproductsintherootoftheproject:

$touchproducts

2. Openthefileandaddthefollowingcontent:

[{

"id":1,

"name":"productName"

}]

Now,the/productsrouteisavailableandwillreturnanarrayofproducts.ReruntheProtractortest,andconfirmthatitispassing.Withthesesimpletests,wehavetestedtheapplicationend-to-endandsuccessfullyremovedthemockscaffolding.

Thisconcludesthewalk-throughofusingTDDtocreateanAngularJSRESTlayer.

www.it-ebooks.info

Page 239: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Self-testquestionsQ1.Acallbackfunctionreferstoafunctionthatiscalledafteranasynchronousfunctioncompletes.

1. True2. False

Q2.AnXMLHttpRequestcannotsendorreceiveJSON.

1. True2. False

Q3.RESTstandsfor:

1. RepresentationalStateTransfer2. Nothing3. RepeatableEndpointStateTransfer

Q4.Asynchronousfunctionsalwayscompleteintheorderinwhichtheywerecalled.

1. True2. False

Q5.Therearetwodifferentimplementationsof$httpBackend:oneforunitandoneforend-to-endtesting.

1. True2. False

www.it-ebooks.info

Page 240: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThischapterexplainedthedetailsbehindRESTrequests,asynchronoustesting,andthemockingofAngularHTTPrequestsinKarmaandProtractor.Ithasbroughttogethermanyofthetechniquesandtoolsusedthroughoutthebook.Specifically,ithasshowedushowtoapplytheTDDlifecycle(testfirst,makeitrun,andmakeitbetter)toincrementallybuildyourapplicationstoaspecificationandhowtousethe3A’s(Assemble,Act,andAssert)toconstructatest.

Asyoucompletethisbookandgoaboutapplyingthetechniquesintherealworld,rememberthatknowingwhattotestisjustasimportantasknowinghowtotest.Thisbookhasshownyouhow;itisuptoyoutopracticeandcontinuetoimproveyourdevelopmentskillsthroughTDD.

www.it-ebooks.info

Page 241: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AppendixA.IntegratingSeleniumServerwithProtractorThroughoutthisbook,weusedSeleniumChromeDrivertotestwithProtractor.WhatthismeantwasthatinordertorunaProtractortest,wesimplyhadtohavethewebsiterunningandthenkickoffProtractor.InChapter3,End-to-endTestingwithProtractor,ChromeDriverwasinstalledandusedtorunthetests.FromtheperspectiveofthebookandTDD,thiswasacceptable.Ourtestsweresmallandcontainedanddidnothavealotofmovingparts.

TheproblemwithonlyusingChromeDriveristhatwecan’ttestonotherbrowsers.Asyourapplicationgrowsandyouwanttosupportmorebrowsers,youneedtothinkaboutrunningastandaloneSeleniumServer.Thissectionofthebookprovidesawalk-throughofhowtogetastandaloneSeleniumServerrunningandintegratedwithProtractor.

www.it-ebooks.info

Page 242: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

InstallationThegoodthingaboutinstallationisthatwehavealreadydoneitbefore.EverytimeweinstalledChromeDriver,thefirstthingwedidwasinstallSelenium.Herearethestandardsteps:

1. InstalltheProtractornpmmodule:

$npminstallprotractor

2. InstallSeleniumWebDriver:

$./node_modules/protractor/bin/webdriver-managerupdate

That’sit.Seleniumisnowinstalledandisreadytobeused.Inthenextsection,wewillseehowtoupdatetheProtractorconfigurationtousetheSeleniumstandaloneserver.

www.it-ebooks.info

Page 243: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ProtractorconfigurationLuckilyforus,wedon’thavetorememberallthebasicconfigurationsforProtractor.Withinnpm_modules,thereareexamplesthatwecanuse.HerearethestepstocopytheSeleniumstandaloneconfiguration:

1. OpenuptheexampleProtractorconfigurationfilethatislocatedinthefollowingdirectory:

./node_modules/protractor/example/conf.js

2. Copythefiletoyourlocaltestfolder:

$cp./node_modules/protractor/example/conf.js

TheconfigurationshouldlookverysimilartothechromeOnlyconfiguration.Hereisasnippetoftheimportantconfigurationitems:

exports.config={

seleniumAddress:'http://localhost:4444/wd/hub',

capabilities:{

'browserName':'chrome'

},

};

ThefirstimportantitemistheseleniumAddressobject.Theaddressisthehostname,port,andlocationwheretheSeleniumServerisrunning.Thenextimportantitemisthecapabilitiesobject.Browser-specificcapabilitiesgiveyoutheabilitytodefinewhichbrowserswillbetestedagainst.AswearenotusingtheChromeOnlyconfiguration,youcannowchooseInternetExplorer(IE),Firefox,andsoon.Formoreinformationonmultiplebrowsersupportandcapabilities,refertotheProtractordocumentationathttps://github.com/angular/protractor/blob/master/docs/browser-setup.md

Inthenextsection,wewilllookathowtorunSelenium.

TipTheseleniumAddressobjectismeanttobeconfigurablesothatyoucanhaveaseparateinstanceinacompletelydifferentlocationthanyourdevelopmentmachine.VisittheSeleniumsiteformoreinformationathttp://www.seleniumhq.org/.

www.it-ebooks.info

Page 244: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

RunningSeleniumSeleniumisquitestraightforwardtostart.Oncerun,itcanjustsitinthebackgroundwhilethetestsarerunning:

1. StarttheSeleniumstandaloneservice:

$./node_modules/protractor/bin/webdriver-managerstart

2. Theconsolewindowwilldisplayseveralinformationmessages.Ensurethefollowingmessagesaredisplayed:

3. Youshouldensurethatthedefaultportused,ascanbeseenintheRemoteWebDrivermessageintheprecedingmessages,isthesameastheonethatisconfiguredintheProtractorconfiguration:

seleniumAddress:'http://localhost:4444/wd/hub',

www.it-ebooks.info

Page 245: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

LetitrunSeleniumisnowrunningonthe4444localhostport.InordertoensurethatProtractorcancommunicatewithSelenium,let’srunasimpletesttoensureeverythingisworking.Aswehavedonethroughoutthebook,wewillfollowtheTDDstepseventhoughthiswillbeanextremelyshortandsimpletest.AsProtractorisinstalled,theonlyotherprerequisiteistoinstallanHTTPserver.Installhttp-serverusingthefollowingcommand:

$npminstallhttp-server

Onceitisinstalled,starttheserver:

$./node_modules/http-server/bin/http-server

www.it-ebooks.info

Page 246: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestfirstThetestwillcheckwhetherthetitleofthepageisequaltoseleniumTestTitle.CreateanewProtractortestfilenamedscenario.js.

AssembleTosetupthetest,weneedtonavigatethebrowsertotherootofthewebapplication:

beforeEach(function(){

browser.get("/");

});

ThereisnoActsectionaswewillsimplybecheckingthattheloadedindexpagehasthetitleweneed.

AssertTheassertneedsgetthetitleandcompareitwiththeexpectedvalue:

it('',function(){

expect(browser.getTitle()).toBe('seleniumTestTitle');

});

www.it-ebooks.info

Page 247: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

MakeitrunNowthatthetestisprepared,wecanstartrunningtheProtractortestthroughthestandaloneSeleniumServer.HerearethestepstoruntheProtractortest:

1. AddthetestfiletotheProtractorconfiguration:

specs:['scenario.js'],

2. CreateanemptyHTMLpagethatwillbeusedtomakethetestrun:

<!DOCTYPEhtml>

<html>

<head>

<title></title>

</head>

<body>

</body>

</html>

3. AddtheindexpagetotheProtractorconfiguration:

specs:['scenario.js','index.html'],

4. Runthetest:

$./node-modules/protractor/bin/protractorconf.js

5. ThefirsterrorisAngularcouldnotbefoundonthepagehttp://localhost:8080/index.html:retrieslookingforangularexceeded.Torectifythis,performthefollowingsteps:

1. AngularJShasnotbeenaddedtothepage.Installangularthroughbower:

$bowerinstallangular

2. AddtheAngularJSreferencetotheindex.htmlpage:

<scripttype="text/javascript"

src="bower_components/angular/angular.js"></script>

3. Rerunthetest.

6. ThenexterrorisAngularcouldnotbefoundonthepagehttp://localhost:8080/index.html:angularneverprovidedresumeBootstrap.ThiserrormeansthatAngularJScouldn’tloadthemainmoduleofyourapplication.Torectifythis,performthefollowingsteps:

1. Addasimplemoduleintothebodytag:

<bodyng-app='test'>

2. Initializethemoduleinthelasttag:

www.it-ebooks.info

Page 248: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

<scripttype="text/javascript"

src="bower_components/angular/angular.js"></script>

<scripttype="text/javascript">

angular.module('test',[]);

</script>

3. Rerunthetest.

7. Thenexterrorhashittheexpectation:Expected‘http://localhost:8080/index.html’tobe‘seleniumTestTitle’.Herearethestepstorectifythiserror:

1. Setthetitleofthewebpagetotheexpectation:

<title>seleniumTestTitle</title>

2. Rerunthetest.

8. TheProtractoroutputnowreports1test,1assertion,0failures.Withthesuccessofthetest,wehavenowsuccessfullyshownyouhowtousetheSeleniumstandaloneserver.

www.it-ebooks.info

Page 249: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SummaryThisappendixhasshownyouhowtosetupandusetheSeleniumstandaloneserver.Therearemanyoptionsandadvantagesofusingthestandaloneserver.TheadvantagesaregearedmoreforadvancedtestingwhenyouwanttouseadedicatedSeleniumServeroraPaaS(PlatformasaService)orifyouwanttotestafunctionalityondifferentbrowsersandasthevolumeofyourProtractortestsgrow.Formoreinformation,visittheSeleniumhomepageathttp://www.seleniumhq.org/.

www.it-ebooks.info

Page 250: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AppendixB.AutomatingKarmaUnitTestingonCommitRunningtestslocallyisonething,buthowdoyouknowwhethertheywillworkonsomeoneelse’scomputer.Settingupcontinuoustestingandintegrationshouldbepartofeveryapplicationyouwrite.Oneofthebestthingsisthatthetoolstosetuparefree,easytouse,andbestofall,theygettoshowcaseyourtests!ThefollowingsectionwillexplorehowtosetupcontinuousintegrationusingGitHubforsourcecontrolandTravisforcontinuousintegration.

www.it-ebooks.info

Page 251: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

GitHubGitHubisasourcecontrol,collaboration,andall-aroundawesometool.Foropensourceprojects,itisfree.Onceyousignup,youcangetstartedandcreateanewrepositoryforyourproject.GitHubprovidesaGitURLforeveryproject;theURLcanthenbesetuptopushchangeslikeanyotherGitrepository.OneofthebenefitsofusingGitHubisthatitautomaticallyprovideshooksintootherapplicationsandservices.WhensettingupcontinuousintegrationandtestingthroughTravisCI,youwillleveragetheTravisCIGitHubhook.

www.it-ebooks.info

Page 252: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestsetupInordertorunKarmaproperly,wewillneedtoaddthefollowingdevelopmentdependencies:

karma:ThebaseKarmainstallationkarma-jasmine:Thetestrunnerkarma-phantomjs-launcher:ThePhantomJSheadlessbrowserpluginwediscussedandsetupinChapter5,FlipFlop

InstallthefollowingKarmadevdependencies:

$npminstallkarma--save-dev

$npminstallkarma-jasmine--save-dev

$npminstallkarma-phantomjs-launcher--save-dev

www.it-ebooks.info

Page 253: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TestscriptsWhenusingTravisCI,ascripttorunthetestsneedstobedefined.Thebestplacetodefineascriptisinthepackage.jsonfile.Thepackage.jsonfileisusedinseveralwaysbynode.js.Herearethestepstorunthetest:

1. Thetestscriptcanthenberunwhenyoutypethefollowingcommandinthecommandprompt:

$npmtest

2. Updatethepackage.jsonscriptssectionasshowninthefollowingcodesnippet:

"scripts":{

"start":"nodeapp.js",

"test":"karmastart--single-run--browsersPhantomJS"

}

3. Confirmthatthetestscriptworks:

$npmtest

PhantomJSallowsteststorunontheTravisCIserverswithouttheneedforaUI.Thefollowingisasampleoutput:

Theapplicationsetupisnowconfiguredtorununittestsviathenpmtestcommand.ThiswillbeusedbyTravisCItorunthetests.

www.it-ebooks.info

Page 254: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SettingthehookGitHubprovidesseveralhooksintootherapplications.Ahookallowsyoutochainactionswhenacommitoccurs.Ahookisanextremelyusefulfeaturefromacontinuousintegrationstandpointbecausewecansetupthecodetobetestedoneverycommit.TravisCIhasaGitHubhookthatcanbeeasilysetuponanyGitHubrepository.Thefollowingisawalk-throughonhowtocreateaTravisCIhookonyouropensourcerepository.

www.it-ebooks.info

Page 255: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

CreatingthehookHerearethestepstocreatethehook:

1. CreateaTravisCIaccountbygoingtotheTravisCIpageathttps://travis-ci.organdclickonSigninwithGitHub.Confirmthequestionsitasksandcontinue.

2. ActivateaGitHubWebhooktoTravisCI.YoucansetuptheWebhookinTravisCIthroughyourprofileURLathttps://travis-ci.org/profile

3. Turntheswitchon.Intheprofile,youshouldseeyourrepository.

HereisabeforeviewofWebhook(Switchoff):

HereisaviewoftheWebhookafteritisenabled(Switchon):

www.it-ebooks.info

Page 256: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AddingaTravisconfigurationfileTravisrequiresaconfigurationfiletobeattherootofyourrepositorynamed.travis.yml.Theconfigurationfilecontainsthesourcecodelanguage,languageversioning,metadata,andotherinformation.Thetemplateconfigurationwilllookasfollows:

language:node_js

node_js:

-"0.10"

Besidesthebasicconfigurationintheprecedingcode,additionalsetupisneededtorunKarmatests.Thebefore_scriptconfigurationwillbeusedtoinstallKarmaandBowerpriortorunninganytests.HereiswhattheconfigurationneedstolooklikeinordertoinstallKarmaandBowerbeforeanytestsrun:

language:node_js

node_js:

-"0.10"

before_script:

-npminstall-gkarma-cli

-npminstall-gbower

-bowerinstall

Nowthetestsarereadytoberun.Addtheprecedingcontentstoanewfilenamedtravis.yml.Bydefault,theNode.jsprojectwillexecutethenpmtestcommandinTravis.Thisiswhyyoudon’tneedtospecifytheactualcommandtotestyourapplication.

NotePleasenotethatTravisCIiscasesensitive.

Thefollowingscreenshotisanexampleofwhattheprecedingcodelookslike:

www.it-ebooks.info

Page 257: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Ifyouhaveanyissues,gototheTravisCIGettingstartedguideathttp://docs.travis-ci.com/user/getting-started/.

www.it-ebooks.info

Page 258: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

ReferencesThefollowingaresomereferencesthatmayhelpyouwiththeconcepts:

ThisformofuserspecificationiswrittenusingtheGerkinsyntax.TheGerkinsyntaxallowsyoutowritethespecificationsinawell-formattedmanner.Seethefollowinglinkformoredetails:http://en.wikipedia.org/wiki/Behavior-driven_development.TheJavaScriptJabberhomepagecanbefoundathttp://javascriptjabber.com/106-jsj-protractor-with-julie-ralph/TheGitHubpageforhttp-servercanbefoundathttps://github.com/nodeapps/http-server

www.it-ebooks.info

Page 259: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

AppendixC.Answers

www.it-ebooks.info

Page 260: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter1,IntroductiontoTest-drivenDevelopmentQ1 2

Q2 1

Q3 1

Q4 1

Q5 2

www.it-ebooks.info

Page 261: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter2,TheKarmaWayQ1 2

Q2 2

Q3 2

Q4 2

www.it-ebooks.info

Page 262: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter3,End-to-endTestingwithProtractorQ1 1

Q2 1

Q3 1

www.it-ebooks.info

Page 263: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter4,TheFirstStepQ1 1

Q2 2

Q3 1

www.it-ebooks.info

Page 264: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter5,FlipFlopQ1 3

Q2 3

Q3 1

www.it-ebooks.info

Page 265: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter6,TellingtheWorldQ1 2

Q2 1

Q3 1

www.it-ebooks.info

Page 266: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Chapter7,GiveMeSomeDataQ1 1

Q2 2

Q3 1

Q4 2

Q5 1

www.it-ebooks.info

Page 267: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

IndexA

3A’sreferencelink/Testingtechniques

3A’sassemble/Assemble,Act,andAssert(3A’s)act/Assemble,Act,andAssert(3A’s),Assemble,Act,Assert(3A’s)assert/Assemble,Act,andAssert(3A’s),Assemble,Act,Assert(3A’s)assemble/Assemble,Act,Assert(3A’s)

3A’s,applicationtoentercommentsassemble/Assembleact/Actassert/Assert

3A’s,commentaddingspecificationassemble/Assembleact/Actassert/Assert

3A’s,commentlikingspecificationassemble/Assembleact/Actassert/Assert

AngularJSinstalling/InstallingAngularJS

AngularJScomponentsattributes/Servicesdirectives/Servicescontrollers/Servicesservices/Services

AngularJSREST,testingwithabout/TestingwithAngularJSRESTproductservice,testing/Testingtheproductservice$http,testingwithKarma/Testing$httpwithKarma

AngularJSroutesabout/Walk-throughofAngularroutessettingup/SettingupAngularJSroutesdirections,defining/Definingdirectionsflipfloptest,assembling/Assemblingtheflipfloptest

AngularJSservicesabout/Services

AngularMocksinstalling/InstallingAngularmocksURL/InstallingAngularmocks

www.it-ebooks.info

Page 268: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

applicationtoentercommentsspecification,preparing/Preparingtheapplication’sspecificationsettingup/Settinguptheprojectdirectory,settingup/SettingupthedirectoryProtractor,installing/SettingupProtractorProtractor,settingup/SettingupProtractorKarma,settingup/SettingupKarmahttp-serversetup/Settinguphttp-serverKarmaconfiguration/ConfiguringKarma

applicationtoentercomments,TDDlifecycleabout/Bringonthecommentstestfirst/Testfirst3A’s/Testfirsttest,running/Makeitrunmodule,adding/Addingthemoduleinput,adding/Addingtheinputcontroller/Controllertest,passing/Makeitpasstest,improving/Makeitbetter

asynchronouscallstesting/Testingasynchronouscallscreating,inKarma/CreatingasynchronouscallsinKarmacreating,inProtractor/CreatingasynchronouscallsinProtractor

asyncmagiccomponents,Protractorabout/Asyncmagicpage,loadingbeforetestexecution/Loadingapagebeforetestexecutionassertiononelements/Assertiononelementsthatgetloadedinpromises

www.it-ebooks.info

Page 269: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

BbeforeEachparameter

about/Testfirst,Testfirstbottom-upapproach

about/Top-downorbottom-upapproachusing/Usingabottom-upapproach

Bowerabout/Bowerinstalling/Bowerinstallation

broadcasttesting/Testingbroadcast,Testingbroadcast

builderobjectabout/Buildingwithabuilder

builderpatternabout/Buildingwithabuilder

www.it-ebooks.info

Page 270: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

C$controllervariable

about/Assemble,Act,andAssert(3A’s)Chrome

about/InstallationprerequisitesURL/Installationprerequisites

commentlikingspecificationabout/Onwardsandupwardstesting,withProtractortesttemplate/Testfirst3A’s/Testfirsttest,running/Makeitrununittests,fixing/Fixingtheunitteststest,improving/Makeitbettertest,coupling/Couplingofthetest

controllertesting/Testingacontrollersimplecontrollertestsetup/Asimplecontrollertestsetupscope,initializing/Initializingthescope

curltoolabout/REST–thelanguageoftheWeb

www.it-ebooks.info

Page 271: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Ddescribeparameter

about/Testfirst,TestfirstDescribeproperty,Karmatest/TestingwithKarmadirections,AngularJSroutes

ngRoute,configuring/ConfiguringngRouteroutecontrollers,defining/Definingtheroutecontrollersrouteviews,defining/Definingtherouteviews

documentation,TDDabout/FundamentalsofTDD

DocumentObjectModel(DOM)/TDDwithProtractor

www.it-ebooks.info

Page 272: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Eemit

about/Emittingtesting/Testingemit

end-to-endtestingabout/Gettingdowntobusiness,Testingend-to-endspecification,reviewing/Specificationdevelopmentto-dolist/Thedevelopmentto-dolistTDDprocess/Testfirstproductdata,obtaining/Gettingtheproductdata

end-to-endtesting,productcartend-to-endtest,assembling/Assemblingthecart’send-to-endtestsavetocartaction,invoking/Invokingasavetocartactionsavedproducts,confirming/Confirmingproductshavebeensavedend-to-endtest,passing/Makingthecart’send-to-endtestpass

end-to-endtesting,recentlyvieweditemsabout/End-to-endtestingtestfirst/Testfirstrecentlyviewedend-to-endtest,assembling/Assemblingtherecentlyviewedend-to-endtestsearchresult,selecting/Selectingasearchresultrecentlyvieweditems,confirming/ConfirmingrecentlyvieweditemsrecentlyViewedItemstest,passing/MakingtherecentlyViewedItemstestpassrecentlyViewedItemstest,improving/Makingrecentlyvieweditemsbetter

end-to-endtests,Protractortestwebserver,installing/Installingthetestwebserver

events,insearchapplicationimplementing/Harnessingthepowerofeventsplan/Theplanrebranding/Rebrandingrecentlyvieweditems,viewing/Seeingrecentlyvieweditemsproductcart,creating/Creatingaproductcart

Expectproperty,Karmatest/TestingwithKarma

www.it-ebooks.info

Page 273: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Fflipfloptest,AngularJSroutes

viewsflip,creating/Makingtheviewsflipflip,asserting/Assertingafliprunning/Makingflipfloprunimproving/Makingflipflopbetter

FunctionUnderTest/Testingtechniquesfundamentals,searchapplication

Protractorlocators/Protractorlocators

www.it-ebooks.info

Page 274: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

GGitHub

about/GitHub

www.it-ebooks.info

Page 275: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

H$httpBackendproperty/Testing$httpwithKarmaheadlessbrowsertesting,forKarma

settingup/SettingupheadlessbrowsertestingforKarmapreconfiguration/Preconfigurationconfiguration/Configuration

http-servermodule/Gettingtheproductdataabout/Gettingtheproductdata

HTTPmethodsabout/REST–thelanguageoftheWebGET/REST–thelanguageoftheWebPOST/REST–thelanguageoftheWebPUT/REST–thelanguageoftheWebDELETE/REST–thelanguageoftheWeb

www.it-ebooks.info

Page 276: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Iinjectvariable

about/Assemble,Act,andAssert(3A’s)installation

Karma/InstallingKarmaProtractor/Protractorinstallation

itparameterabout/Testfirst,Testfirst

Itproperty,Karmatest/TestingwithKarma

www.it-ebooks.info

Page 277: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

JJasmine

about/Jasminepros/Jasminecons/Jasmine

Jasminespyused,forcreatingtestdouble/TestingdoubleswithJasminespies

JavaScripttestingframeworksabout/JavaScripttestingframeworksJasmine/JasmineSelenium/SeleniumMocha/Mocha

JavaScripttestingtoolsabout/JavaScripttestingtoolsKarma/KarmaProtractor/Protractor

www.it-ebooks.info

Page 278: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

KKarma

about/Karmapros/Karmacons/Karmabirth/BirthofKarmafeatures/TheKarmadifferencecombining,withAngularJS/ImportanceofcombiningKarmawithAngularJSinstalling/InstallingKarmaURL/InstallingKarmaprerequisites,forinstallation/Installationprerequisitesconfiguring/ConfiguringKarmaconfiguration,customizing/CustomizingKarma’sconfigurationinstallation,confirming/ConfirmingKarma’sinstallationandconfiguration,ConfirmingtheKarmainstallationconfiguration,confirming/ConfirmingKarma’sinstallationandconfigurationcommoninstallation/configurationissues/Commoninstallation/configurationissuestesting,with/TestingwithKarmainitializing/InitializingKarma

Karma,usingwithAngularJSabout/UsingKarmawithAngularJSAngularJS,obtaining/GettingAngularJStesting,with/TestingwithAngularJSandKarmadevelopmentto-dolist/Adevelopmentto-dolistlistofitems,testing/TestingalistofitemsTDDprocess/Testingalistofitemsfunction,addingtocontroller/Addingafunctiontothecontroller

karma.conffile/InitializingKarmaKarmaconfiguration

about/Karmaconfigurationfilewatching/Filewatching

Karmaconfiguration,applicationtoentercommentstesting/Testfirst3A’s/Testfirsttest,running/Makeitruntest,improving/Makeitbettertestchain,backingup/Backupthetestchaininput,binding/Bindtheinput

Karmadevdependencieskarma/Testsetupkarma-jasmine/Testsetupkarma-phantomjs-launcher/Testsetup

www.it-ebooks.info

Page 279: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

installing/TestsetupKarmaunittesting

testsetup/Testsetuptestscripts/Testscriptshook,setting/Settingthehookhook,creating/CreatingthehookTravisconfigurationfile,adding/AddingaTravisconfigurationfile

www.it-ebooks.info

Page 280: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Mmessages

publishing/Publishingandsubscribingmessagessubscribing/Publishingandsubscribingmessages

middle-to-endtestingabout/Testingmiddle-to-endtestfirst/Testfirstproducttest,assembling/Assemblingtheproducttestproducts,obtaining/Gettingproductsproductdataresults,expecting/Expectingproductdataresultsproductdata,running/Makingtheproductdatarun

Mochaabout/Mochapros/Mochacons/Mocha

www.it-ebooks.info

Page 281: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

NNode.js

URL/Installationprerequisites,Installationprerequisitesabout/Installationprerequisites

NodePackageManager(npm)modules/Mocha

www.it-ebooks.info

Page 282: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

PPhantomJS

URL/SettingupheadlessbrowsertestingforKarmaPhantomJSbrowserplugin

URL/Preconfigurationprerequisites,Protractorinstallation

Node.js/InstallationprerequisitesChrome/InstallationprerequisitesSeleniumWebDriverforChrome/Installationprerequisites

productcartcreating/Creatingaproductcartpublishertestfirst/PublishertestfirstsearchDetailController,assembling/AssemblingsearchDetailControllerproductsaving,invoking/Invokingthesavingofaproductsaveevent,confirming/ConfirmingthesaveeventsaveProducttest,passing/MakingthesaveProducttestpasssubscriberunittest/Testforthesubscriberfirsttest,assembling/Assemblingtheproductcarttestsavedcartevent,invoking/Invokingasavedcarteventsavedcart,confirming/Confirmingthesavedcartcartcontrollertest,running/Makingthecartcontrollertestrunend-to-endtesting/End-to-endtesting

productdatacontrollerabout/Theproductdatacontrollerproductcontrollertest,assembling/Assemblingtheproductcontrollertestproducts,obtaining/Gettingproductsproductdataresults,asserting/Assertingproductdataresults

productdataserviceabout/Theproductdataservice

productrequests,unittestingabout/Unittestingproductrequestsproject,settingup/SettinguptheprojectKarmaconfiguration/KarmaconfigurationAPIbuilderpattern,using/UsinganAPIbuilderpattern

products,displayingwithRESTabout/DisplayingproductswithRESTproductrequests,unittesting/Unittestingproductrequestsproductdataservice/Theproductdataserviceproductdatacontroller/Theproductdatacontrollerproductdatatests,running/Makingtheproductdatatestsrun

Protractorabout/Protractor,AnoverviewofProtractorpros/Protractor

www.it-ebooks.info

Page 283: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

cons/Protractoroverview/AnoverviewofProtractororigins/OriginsofProtractorbirth/ThebirthofProtractorfeatures/LifewithoutProtractorURL/Commoninstallation/configurationissuesrealtest/HelloProtractorTDD,using/TDDend-to-endpre-setup/Thepre-setupsetup/Thesetupend-to-endtests/Testfirstconfiguring/ConfiguringProtractorgaps,cleaningup/Cleaningupthegapsasyncmagiccomponents/AsyncmagicTDD,implementingwith/TDDwithProtractor

Protractorinstallationabout/Protractorinstallationreferencelink,forguide/Protractorinstallationprerequisites/Installationprerequisitesperforming/InstallingProtractorWebDriver,installingforChrome/InstallingWebDriverforChromeconfiguration,customizing/Customizingconfigurationconfirming/Confirminginstallationandconfigurationconfiguration,confirming/Confirminginstallationandconfigurationcommonissues/Commoninstallation/configurationissues

Protractorlocatorsabout/ProtractorlocatorsCSSlocators/CSSlocatorsbuttontextlocator/Buttonandlinklocatorslinktextlocator/ButtonandlinklocatorsAngularlocators/AngularlocatorsURLlocationreferences/URLlocationreferences

publishingandsubscribingmessages/Publishingandsubscribingmessagesissues/Publishingandsubscribing–thegoodandbadscenarios/Thegoodcommunicating,throughevents/Communicatingthrougheventscoupling,reducing/Reducingcoupling

www.it-ebooks.info

Page 284: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

Rrecentlyvieweditems,viewing

about/Seeingrecentlyvieweditemstestfirst/Testfirstend-to-endtesting/End-to-endtesting

recentlyviewedtestwriting/TestfirstSearchController,assembling/AssemblingSearchControllerproduct,selecting/Selectingaproductevents,tobepublished/Expectingeventstobepublishedsearchcontrollerrun,creating/Makingthesearchcontrollerrununittest/Recentlyviewedunittest

recentlyviewedunittestabout/Recentlyviewedunittestwriting/TestfirstRecentlyViewedController,assembling/AssemblingRecentlyViewedControllerrecentlyvieweditem,invoking/InvokingarecentlyvieweditemRecentlyViewedController,confirming/ConfirmingRecentlyViewedControllerRecentlyViewedController,running/MakingRecentlyViewedControllerrun

refactoring,TDDabout/FundamentalsofTDD,Refactoring

RESTabout/REST–thelanguageoftheWebgettingstartedprocess/GettingstartedwithREST

RESTrequestscreating,AngularJSused/MakingRESTrequestsusingAngularJStesting,withAngularJSREST/TestingwithAngularJSRESTmocking,withProtractor/MockingrequestswithProtractor

www.it-ebooks.info

Page 285: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

SSaaS(SoftwareasaService)/LifewithoutProtractorSauceLabs

URL/LifewithoutProtractorScenarioRunner

about/Endoflifescopevariable

about/Assemble,Act,andAssert(3A’s)searchapplication

fundamentals/Fundamentalscreating/Creatinganewprojectheadlessbrowsertesting,settingupforKarma/SettingupheadlessbrowsertestingforKarma

searchapplication,TDDwayabout/SearchingtheTDDway,Thesearchapplicationapproach,decidingon/Decidingontheapproachsearchquery/Walk-throughofsearchquerysearchquerytest/ThesearchquerytestsearchqueryHTMLpage/ThesearchqueryHTMLpage

searchresults,searchapplicationabout/Showmesomeresults!searchresultroutes,creating/Creatingthesearchresultroutestesting/Testingthesearchresultssearchresulttest,assembling/Assemblingthesearchresulttestselecting/Selectingasearchresultconfirming/Confirmingasearchresultsearchresulttest,running/Makingthesearchresulttestruntesting,forlocation/Creatingalocation-awaretestimproving/MakingthesearchresultbetterrouteID,confirming/ConfirmingtherouteIDrouteIDunittest,settingup/SettinguptherouteIDunittestrouteIDunittest,confirming/ConfirmingtheIDrouteparameterstest,running/Makingtherouteparameter’stestrun

SeleniumURL/Seleniumabout/Seleniumpros/Seleniumcons/Seleniuminstalling/InstallationProtractorconfiguration/Protractorconfigurationrunning/RunningSelenium,Letitruntestfirst/Testfirst

SeleniumWebDriver,forChrome

www.it-ebooks.info

Page 286: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

about/Installationprerequisitesinstalling/InstallingWebDriverforChrome

success,measuringinTDDsteps,breakingdown/Breakingdownthestepstestfirstmethodology/Measuretwicecutonce

www.it-ebooks.info

Page 287: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

TTDD

about/AnoverviewofTDD,TDDend-to-endfundamentals/FundamentalsofTDDbenefits/FundamentalsofTDDsuccess,measuring/Measuringsuccesstestingtechniques/Testingtechniquesapplying/TDDend-to-end

TDDlifecycleabout/Divingintest,settingup/Settingupthetestdevelopmentto-dolist,creating/Creatingadevelopmentto-dolisttestfirst/Testfirsttest,running/Makingitruntest,improving/Makingitbetter

TDDprocess,end-to-endtestingtestfirst/Testfirst3A’s/Assemble,Act,Assert(3A’s)test,running/Makeitruntest,improving/Makeitbetter

TDDprocess,foraddingfunctiontocontrollerabout/Addingafunctiontothecontrollertestfirst/Testfirst3A’s/Assemble,Act,andAssert(3A’s)test,running/Makeitruntest,improving/Makeitbetter

TDDprocess,fortestinglistofitemstestfirst/Testfirst3A’s/Assemble,Act,andAssert(3A’s)test,running/Makeitruntest,improving/Makeitbetter

test,Seleniumassemble/Assembleassert/Assertrunning/Makeitrun

testdoubleabout/TestingdoubleswithJasminespiesusing/TestingdoubleswithJasminespiescreating,Jasminespyused/TestingdoubleswithJasminespiesreturnvalue,stubbing/Stubbingareturnvaluearguments,testing/Testingarguments

testingframeworkabout/Testingwithaframework

www.it-ebooks.info

Page 288: 2.droppdf.com2.droppdf.com/files/6uXTX/angularjs-test-driven-development.pdf · Table of Contents AngularJS Test-driven Development Credits About the Author About the Reviewers Support

testingtechniques,TDDabout/Testingtechniquestestingframework/Testingwithaframeworktestdouble/TestingdoubleswithJasminespiestestdouble,usingJasminespy/TestingdoubleswithJasminespiesrefactoring/Refactoringbuilding,withbuilder/Buildingwithabuilder

ToBeTruthyproperty,Karmatest/TestingwithKarmatop-downapproach

about/Top-downorbottom-upapproachTravisCI

configurationfile/AddingaTravisconfigurationfileURL/AddingaTravisconfigurationfile

TravisCIhookcreating/Creatingthehook

www.it-ebooks.info