AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul...
Transcript of AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul...
![Page 3: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/3.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/4.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/5.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/6.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/7.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/8.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/9.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/10.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/11.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/12.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/13.jpg)
Chapter3,End-to-endTestingwithProtractor
Chapter4,TheFirstStep
Chapter5,FlipFlop
Chapter6,TellingtheWorld
Chapter7,GiveMeSomeData
Index
www.it-ebooks.info
![Page 15: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/15.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/16.jpg)
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 18: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/18.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/19.jpg)
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 21: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/21.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/22.jpg)
Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser
www.it-ebooks.info
![Page 23: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/23.jpg)
FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.
www.it-ebooks.info
![Page 24: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/24.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/25.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/26.jpg)
WhothisbookisforThisbookisforthedeveloperwhowantstogobeyondthebasictutorials,andwantstotaketheplungeintoAngularJSdevelopment.ThisbookisforthedeveloperwhohasexperiencewithAngularJSandhaswalkedthroughthebasictutorialsbutwantstounderstandthewidercontextofwhen,why,andhowtoapplytestingtechniquesandbestpracticestocreatequality-cleancode.Togetthemostoutofthisbook,itispreferredthatthereaderhasbasicunderstandingofHTML,JavaScript,andAngularJS.
www.it-ebooks.info
![Page 27: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/27.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/28.jpg)
ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.
Tosendusgeneralfeedback,simplye-mail<[email protected]>,andmentionthebook’stitleinthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.
www.it-ebooks.info
![Page 29: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/29.jpg)
CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.
www.it-ebooks.info
![Page 30: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/30.jpg)
DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
www.it-ebooks.info
![Page 31: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/31.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/32.jpg)
PiracyPiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucomeacrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.
www.it-ebooks.info
![Page 33: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/33.jpg)
QuestionsYoucancontactusat<[email protected]>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.
www.it-ebooks.info
![Page 34: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/34.jpg)
Chapter1.IntroductiontoTest-drivenDevelopmentAngularJSisattheforefrontofclient-sideJavaScripttesting.EveryAngularJStutorialincludesanaccompanyingtest,andeventtestmodulesarepartofthecoreAngularJSpackage.TheAngularteamisfocusedonmakingtestingfundamentaltowebdevelopment.
Thischapterintroducesyoutothefundamentalsoftest-drivendevelopmentwithAngularJSincluding:
Anoverviewoftest-drivendevelopment(TDD)TheTDDlifecycle:testfirst,makeitrun,makeitbetterCommontestingtechniques
www.it-ebooks.info
![Page 35: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/35.jpg)
AnoverviewofTDDTDDisnotusedonlytodevelopsoftware.Thefundamentalprinciplescanbeseeninmanyindustries.ThissectionwillexplorethefundamentalsofTDDandhowtheyareappliedbyatailor.
www.it-ebooks.info
![Page 36: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/36.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/37.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/38.jpg)
startingdeveloping.Onecommonapproachistoworkoffaspecification.Adocumentedapproachmayhelpindefiningwhatneedstobebuilt;however,withouttangiblecriteriaforhowtomeetaspecification,theactualapplicationthatgetsdevelopedmaybecompletelydifferentthanthespecification.WithaTDDapproach(testfirst,makeitrun,andmakeitbetter),everystageoftheprocessverifiesthattheresultmeetsthespecification.Thinkabouthowatailorcontinuestouseameasuringtapetoverifythesuitthroughouttheprocess.
TDDembodiesatest-firstmethodology.TDDgivesdeveloperstheabilitytostartwithacleargoalandwritecodethatwilldirectlymeetaspecification.Developlikeaprofessionalandfollowthepracticesthatwillhelpyouwritequalitysoftware.
www.it-ebooks.info
![Page 39: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/39.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/40.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/41.jpg)
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 43: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/43.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/44.jpg)
TestingwithaframeworkAlthoughasimplewebpagecanbeusedtoperformtests,asseenearlierinthischapter,itismucheasiertouseatestingframework.Atestingframeworkprovidesmethodsandstructurestotest.Thisincludesastandardstructuretocreateandruntests,theabilitytocreateassertions/expectations,theabilitytousetestdoubles,andmore.ThisbookusesJasmineasthetestframework.Jasmineisabehavior-driventestingframework.ItishighlycompatiblewithtestingAngularJSapplications.InChapter2,TheKarmaWay,wewilltakeamorein-depthlookatJasmine.
www.it-ebooks.info
![Page 45: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/45.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/46.jpg)
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 48: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/48.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/49.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/50.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/51.jpg)
};
TipDownloadingtheexamplecode
Youcandownloadtheexamplecodefilesfromyouraccountathttp://www.packtpub.comforallthePacktPublishingbooksyouhavepurchased.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
www.it-ebooks.info
![Page 52: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/52.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/53.jpg)
SummaryThischapterprovidedanintroductiontoTDD.ItdiscussedtheTDDlifecycle(testfirst,makeitrun,makeitbetter)andshowedhowthesamestepsareusedbyatailor.Finally,itlookedoversomeofthetestingtechniquesthatwillbediscussedthroughoutthisbookincluding:
TestdoublesRefactoringBuildingpatterns
AlthoughTDDisahugetopic,thisbookissolelyfocusedontheTDDprinciplesandpracticestobeusedwithAngularJS.Inthenextchapter,youwillstartthejourneyandseehowtosetuptheKarmatestrunner.
www.it-ebooks.info
![Page 54: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/54.jpg)
Chapter2.TheKarmaWayJavaScripttestinghashitthemainstream,thankstoKarma.KarmamakesitseamlesstotestJavaScript.AngularJSwascreatedaroundtesting.ThischapterexplorestheoriginsofKarmaandwhyithastobeusedinanyAngularJSproject.Bytheendofthischapter,youwillnotonlyunderstandtheproblemthatKarmasolves,butalsowalkthroughacompleteexampleusingit.
www.it-ebooks.info
![Page 55: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/55.jpg)
JavaScripttestingtoolsKnowingwhatthedifferenttestingtoolsareishalfthebattle.Inthissection,youwilllearnaboutthetwoprimarytoolsthatwillbediscussedandusedthroughoutthebook.Theyare:
Karma:ThisisatestrunnerProtractor:Thisisanend-to-endtestingframework
www.it-ebooks.info
![Page 56: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/56.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/57.jpg)
ProtractorProtractorisanend-to-endtestingtool.Itallowsdeveloperstomimicuserinteractions.Itautomatesthetestingoffunctionalityandfeaturesthroughtheinteractionofawebbrowser.ProtractorhasspecificmethodstoassistwithtestingAngularJS,buttheyarenotexclusivetoAngularJS.SomeoftheprosandconsofusingProtractorareasfollows:
Pros Cons
Configurabletotestmultipleenvironments Documentationandexamplesarelimited
EasyintegrationwithAngularJS
Syntaxandtestingcanbesimilartothetestingframeworkchosenforunittesting
www.it-ebooks.info
![Page 58: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/58.jpg)
JavaScripttestingframeworksInthissection,youwilllearnaboutthetestingframeworksthatwillsupportyouinyourTDDpractices.Theseinclude:
JasmineSeleniumMocha
www.it-ebooks.info
![Page 59: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/59.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/60.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/61.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/62.jpg)
BirthofKarmaWhenpickingupanewtool,itisimportanttounderstandwhereitcamefromandwhyitwasbuilt.ThissectiongivesyousomebackgroundoftheoriginsofKarma.
www.it-ebooks.info
![Page 63: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/63.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/64.jpg)
ImportanceofcombiningKarmawithAngularJSKarmawasbuiltforAngularJS.PriortoKarma,therewasalackofautomatedtestingtoolsforweb-basedJavaScriptdevelopers.
Remember,Karmaisatestrunner,notatestframework.Itsjobistoruntestsandreportwhichtestswillpassorfail.Whyisthishelpful?Atestframeworkiswhereyouwillwriteyourtests.Apartfromdoingthis,youwillneedtobefocusedonrunningthetestseasilyandseeingresults.Karmaeasilyrunstestsacrossseveraldifferentbrowsers.Karmaalsohassomeotherfeatures,suchasfilewatching,whichwillbediscussedfurtherindetaillaterinthebook.
www.it-ebooks.info
![Page 65: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/65.jpg)
InstallingKarmaTimetostartusingKarma.Installationsandapplicationsareconstantlychanging.ThefollowingguideisintendedtobebriefinthehopethatyouwillgototheKarmawebsite,http://karma-runner.github.io/,andfindthelatestinstructions.
Themainfocusofthissectionwillbeonthespecificconfigurationusedinthisbookandnotanin-depthinstallationguide.
www.it-ebooks.info
![Page 66: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/66.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/67.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/68.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/69.jpg)
$./node_modules/karma/bin/karma--version
NowthatKarmaisinstalledandrunning,it’stimetoputittouse.
www.it-ebooks.info
![Page 70: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/70.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/71.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/72.jpg)
UsingKarmawithAngularJSHere,youwillwalkthroughaTDDapproachtoanAngularJScomponent.Bytheendofthischapter,youshouldbeableto:
FeelconfidentaboutusingKarmaanditsconfigurationUnderstandthebasiccomponentsofaJasminetestStarttounderstandhowtointegrateaTDDapproachinanAngularJSapplication
www.it-ebooks.info
![Page 73: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/73.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/74.jpg)
$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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/75.jpg)
$Chrome35.0.1916(Windows7):Executed0of0ERROR(0.01secs/0secs)
Thatisit.KarmaisnowrunningforthefirstAngularJSapplication.
www.it-ebooks.info
![Page 76: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/76.jpg)
TestingwithAngularJSandKarmaThepurposeofthisfirsttestusingKarmaistocreateadynamicto-dolist.ThiswalkthroughwillfollowtheTDDstepswediscussedinChapter1,IntroductiontoTest-drivenDevelopment:testfirst,makeitrun,andmakeitbetter.ThiswillallowyoutogainmoreexperienceinusingTDDwithAngularJS.
www.it-ebooks.info
![Page 77: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/77.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/78.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/79.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/80.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/81.jpg)
.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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/82.jpg)
Nextupistherequirementtoaddanewitemtothelist.TheTDDrhythmwillbefollowedagain:testfirst,makeitrun,andmakeitbetter.
www.it-ebooks.info
![Page 83: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/83.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/84.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/85.jpg)
//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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/86.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/87.jpg)
SummaryInthischapter,wereviewedJavaScripttestingframeworksandtoolsanddiscussedhowVojtechJínacreatedKarma.Wesawhowtoinstall,configure,andrunKarma.Finally,youhavewalkedthroughanexampleofusingKarmawithTDD.Inthenextchapter,youwilllearnaboutend-to-endtestingwithProtractor.
www.it-ebooks.info
![Page 88: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/88.jpg)
Chapter3.End-to-endTestingwithProtractorUnittestingisonlyoneaspectoftesting.Inthischapter,wewilllookatend-to-endtestingapplications,throughalllayersofanapplication.YouwillbeintroducedtoProtractor,theend-to-endtestingtoolfromtheAngularJSteam.Wewilllookintowhyitwascreatedandtheproblemsitsolves.Finally,wewillseehowtoinstall,configure,anduseProtractorwithTDD.
www.it-ebooks.info
![Page 89: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/89.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/90.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/91.jpg)
OriginsofProtractorProtractorisnotthefirstend-to-endtestingtoolthattheAngularJSteambuilt.ThefirsttoolwascalledScenarioRunner.InordertounderstandwhyProtractorwasbuilt,weneedtofirstlookatitspredecessor:ScenarioRunner.
www.it-ebooks.info
![Page 92: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/92.jpg)
EndoflifeScenarioRunnerisinmaintenancemodeandhasreacheditsendoflife.IthasbeendeprecatedinplaceofProtractor.Inthissection,wewilllookatwhatScenarioRunnerwasandwhatgapsthetoolhad.
www.it-ebooks.info
![Page 93: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/93.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/94.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/95.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/96.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/97.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/98.jpg)
Theinstallationisnowcomplete.BothProtractorandSeleniumWebDriverforChromehavebeeninstalled.Wecannowmoveontotheconfiguration.
www.it-ebooks.info
![Page 99: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/99.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/100.jpg)
};
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/101.jpg)
HelloProtractorWiththeProtractorinstallationandconfigurationcomplete,youcanlookatwritingarealtest.ThissectionwillwalkyouthroughusingTDDwithProtractor.Attheendofthischapter,youshouldbeableto:
FeelconfidentinusingandconfiguringProtractorUnderstandthebasiccomponentsofaProtractortestStarttounderstandhowtointegrateaTDDapproachtoend-to-endtesting
www.it-ebooks.info
![Page 102: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/102.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/103.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/104.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/105.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/106.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/107.jpg)
});
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/108.jpg)
<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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/109.jpg)
</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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/110.jpg)
CleaningupthegapsThereareacoupleofthingsthatwerediscussedinthischapterthatneedsomefurtherclarification.Thisincludesthefollowing:
Whereistheasynchronouslogic?HowtoreallyimplementTDDwithend-to-endtests.
www.it-ebooks.info
![Page 111: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/111.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/112.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/113.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/114.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/115.jpg)
Chapter4.TheFirstStepThefirststepisalwaysthehardest.Thischapterprovidesaninitialintroductorywalk-throughofhowtouseTDDtobuildanAngularJSapplicationwithacontroller,model,andscope.YouwillbeabletobegintheTDDjourneyandseethefundamentalsinaction.Uptothispoint,thisbookhasfocusedonafoundationofTDDandthetools.Now,wewillswitchgearsanddiveintoTDDwithAngularJS.ThischapterwillbethefirststepofTDD.WehavealreadyseenhowtoinstallKarmaandProtractor,inadditiontosmallexamplesandawalk-throughonhowtoapplyit.Thischapterwillfocusonthecreationofsocialmediacomments.ItwillalsofocusonthetestingassociatedwithcontrollersandtheuseofAngularmockstoAngularJScomponentsinatest.
www.it-ebooks.info
![Page 116: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/116.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/117.jpg)
SettinguptheprojectInpreviouschapters,wediscussedindetailhowaprojectshouldbesetup,explainedthedifferentcomponentsinvolved,andwalkedthroughtheentireprocessoftesting.Iwillskipthesedetailsandprovidealistinthefollowingsectionfortheinitialactionstogettheprojectsetup.
www.it-ebooks.info
![Page 118: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/118.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/119.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/120.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/121.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/122.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/123.jpg)
TestingacontrollerBeforegettingintothespecification,andthemind-setofthefeaturebeingdelivered,itisimportanttoseethefundamentalsoftestingacontroller.AnAngularJScontrollerisakeycomponentusedinmostapplications.
www.it-ebooks.info
![Page 124: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/124.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/125.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/126.jpg)
BringonthecommentsNowthatthesetupandapproachhavebeendecided,wecanstartourfirsttest.Fromatestingpointofview,aswewillbeusingatop-downapproach,wewillwriteourProtractortestsfirstandthenbuildtheapplication.WewillfollowthesameTDDlifecyclewehavealreadyreviewed,thatis,testfirst,makeitrun,andmakeitbetter.
www.it-ebooks.info
![Page 127: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/127.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/128.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/129.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/130.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/131.jpg)
$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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/132.jpg)
}]);
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/133.jpg)
$1test,1assertion,0failures
Waitasecond!Westillhavesomeworktodo.Althoughwegotthetesttopass,itisnotdone.Weaddedsomehacksjusttogetthetestpassing.Thetwothingsthatstandoutare:
ClickingontheSubmitbutton,whichreallydoesn’thaveanyfunctionalityHardcodedinitializationoftheexpectedvalueforacomment
Theprecedingchangesarecriticalstepsweneedtoperformbeforewemoveforward.TheywillbetackledinthenextphaseoftheTDDlifecycle,thatis,makeitbetter(refactor).
www.it-ebooks.info
![Page 134: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/134.jpg)
MakeitbetterThetwocomponentsthatneedtobereworkedare:
AddingbehaviortotheSubmitbuttonRemovinghardcodedvalueofthecomments
www.it-ebooks.info
![Page 135: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/135.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/136.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/137.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/138.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/139.jpg)
OnwardsandupwardsNowthatwehavethefirstspecificationworkingend-to-endandunittested,wecanstartthenextspecification.Thenextspecificationstatesthattheuserswanttheabilitytolikeacomment.
Wewillusethesametop-downapproachandstartourtestfromaProtractortest.WewillcontinuetofollowtheTDDlifecycle,thatis,testfirst,makeitrun,makeitbetter.
www.it-ebooks.info
![Page 140: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/140.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/141.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/142.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/143.jpg)
<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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/144.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/145.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/146.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/147.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/148.jpg)
Chapter5.FlipFlopAtthispoint,youshouldbefeelingconfidentintheinitialimplementationofanAngularJSapplicationusingTDD.Youshouldbefamiliarwithusingatest-firstapproach.Inthischapter,youwillcontinuetoexpandyourknowledgeofapplyingTDDwithAngularJSbylookingatthefollowing:
AngularJSroutesPartialviewsProtractorlocationreferenceswithCSS(CascadingStyleSheets)andHTMLelementsHeadlessbrowsertestingwithKarma
www.it-ebooks.info
![Page 149: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/149.jpg)
FundamentalsThischapterwillwalkyouthroughapplyingTDDtoroutesandpartialviewsforasearchapplication.Beforegettingintothewalk-through,youneedtobeawareofsomeofthetechniques,configurations,andfunctionsthatwillbeusedthroughoutthischapter,whichinclude:
ProtractorlocatorsHeadlessbrowsertesting
Afteryouhavereviewedtheseconcepts,youcanmoveontothewalk-through.
www.it-ebooks.info
![Page 150: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/150.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/151.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/152.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/153.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/154.jpg)
Walk-throughofAngularroutesThiswalk-throughwillleverageAngularJSroutes.RoutesareanextremelyusefulfeatureofAngularJS.Theyallowyoutocontrolcertainaspectsoftheapplicationusingdifferentviews.Thiswalk-throughwillflipbetweenviewstoshowyouhowtouseTDDtobuildroutes.Thefollowingarethespecifications:
GivenaviewAthathasasinglebutton;thefollowingactionswilltakeplace:
ThebuttonispushedTheviewisswitchedtoviewB
GivenaviewBthathasasinglebutton;thefollowingactionswilltakeplace:
ThebuttonispushedTheviewisswitchedtoviewA
Essentially,thiswillbeanapplicationthatdoesaflipflopbetweenviews.
www.it-ebooks.info
![Page 155: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/155.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/156.jpg)
}]);
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/157.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/158.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/159.jpg)
2. Rerunthetest.
5. TheProtractortestsnowpass.
MakingflipflopbetterForpractice,youshouldaddalinktoswitchbacktoviewAfromviewB.Thereisnothingthathasbeencalledoutthatneedstobechangedorrefactored.Themaintakeawayfromthiswalk-throughishowtouseProtractortotestroutes.Herearesomescreenshotsoftheapplication:
Theinitialindexpageisshowninthefollowingscreenshot:
Thefollowingiswhatyou’llseeaftertheviewhasbeenswitched:
www.it-ebooks.info
![Page 160: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/160.jpg)
SearchingtheTDDwayThiswalk-throughwillshowyouhowtobuildasimplesearchapplication.Thewalk-throughhastwocomponents.Thefirstdiscussesasearchquerycomponent.Thesecondusesroutestodisplaysearchresultdetails.
www.it-ebooks.info
![Page 161: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/161.jpg)
DecidingontheapproachThiswalk-throughusesthetop-downTDDapproach.Itstartswithwritingfailingtests,fromtheUIpointofviewusingProtractor,andthenworkingthroughtheapplicationwithacombinationofunitandend-to-endtests.
www.it-ebooks.info
![Page 162: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/162.jpg)
Walk-throughofsearchqueryTheapplicationbeingbuiltisasearchapplication.Thefirststepistosetupthesearchareawithsearchresults.ImagineIamperformingasearch.Thefollowingactionswilloccur:
AsearchqueryistypedinResultsaredisplayedontheleftsidebar
Thispieceoftheapplicationisverysimilartothetest,layout,andapproachyousawinChapter4,FirstSteps.Theapplicationwillneedtouseaninput,respondtoaclick,andconfirmtheresultingdata.Sincethetestsandcodeusethesamefunctionalityasthepreviousexample,itisnotworthprovidingacompletewalk-throughofthesearchfunctionality.Instead,thefollowingsectionwillshowtheresultingcodewithafewexplanations.
www.it-ebooks.info
![Page 163: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/163.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/164.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/165.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/166.jpg)
Showmesomeresults!NowthattheSearchbuttonissetwiththerequiredfeatures,theresultingdetailsneedtobedisplayedwhenasearchresultisselected.Hereistheuserspecification.Giventhefollowingsearchresults:
IselectanitemfromthesearchresultsIwillseethedetailsinthemainpagecomponent
Followingthetop-downapproach,thefirststepwillbetheProtractortestsfollowedbythenecessarystepstogettheapplicationfullyfunctional.
www.it-ebooks.info
![Page 167: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/167.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/168.jpg)
}]);
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/169.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/170.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/171.jpg)
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 173: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/173.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/174.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/175.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/176.jpg)
Afterasearchquery,theapplicationlookslikewhatisshowninthefollowingscreenshot:
Fordetailsoftheapplicationlooksasshowninthefollowingscreenshot(noticethattheURLcontainsthedetailroute):
www.it-ebooks.info
![Page 177: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/177.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/178.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/179.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/180.jpg)
BeforetheplungeBeforethewalk-through,thecoreconceptsofthechapterwillbereviewedfirst.Itisimportantthatyouunderstandtheseconceptsbeforeyoumoveontothewalk-through.
www.it-ebooks.info
![Page 181: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/181.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/182.jpg)
Usingabottom-upapproachThetop-downapproachofTDDcanbeveryuseful.Ithelpsfocusonuser-facingcomponentsfirstandthenfillsupthebackendlayer.Oneofthecaveatstothisapproachisthatthespecificationbeingbuiltismoreuserfacingasopposedtoitbeingbasedonlogic.Thebottom-upapproachbuildsfromtheinnercomponentsouttotheUIandtheuser.Thiskindofapproachisextremelyimportantwhenworkingwithcomplicatedlogicandrequirements.Withthebottom-upapproach,youwillfirstbuildservices,controllers,anddirectiveswithallthecomplexitiesusingunittestsandKarma.Afterthis,youwillexpandtocreateend-to-endtestswithProtractor.
www.it-ebooks.info
![Page 183: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/183.jpg)
ServicesAngularJSservices,factories,andresourcesareallimportantcomponents.Servicesareusedtoabstractapplicationlogic.Theyareusedtoprovidesingleresponsibilityforaparticularaction.Singleresponsibilityallowscomponentstobeeasilytestedandchanged.Thisisbecausethefocusisononecomponentandnotalltheinnerdependencies.
HereisasummaryofsomeoftheotherAngularJScomponentsthathavebeenlookedatsofar:
Attributesanddirectives:ThesedriveactionsandflowfromtheUIControllers:ThisprovidesthegluebetweentheUIandlogicServices:Thisisolatesthelogic
www.it-ebooks.info
![Page 184: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/184.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/185.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/186.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/187.jpg)
events.Asyouprogressthroughtherestoftheeventtests,youwillfindthatthesetupandtechniquesusedherewillbeusedthroughouttherestofthechapter.
www.it-ebooks.info
![Page 188: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/188.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/189.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/190.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/191.jpg)
HarnessingthepowerofeventsPublishingandsubscribingeventscanleadtosomeuglyandhard-to-understandspaghetticode.Nowthatthefoundationsforthechapterhavebeenreviewed,youcandiveintoimplementingeventsintothesearchapplication.
www.it-ebooks.info
![Page 192: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/192.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/193.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/194.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/195.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/196.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/197.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/198.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/199.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/200.jpg)
andaddthecontrollerreference:
<scriptsrc="app/recentlyViewedController.js"></script>
2. Rerunthetest.
7. Nowthetestwillbesuccessful.
Makingrecentlyvieweditemsbetter
Therecentlyviewedcontrollerisnowcomplete.Itwouldbenicetobetterorganizetheview,howeverthiscanhappenlater.Thepointofthisexercisewastoestablishcommunicationbetweenseparateviewsandcreateausablefunction.Thishasbeenachieved,andnowyoucanmovetothenextstepofthewalk-through.
www.it-ebooks.info
![Page 201: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/201.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/202.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/203.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/204.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/205.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/206.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/207.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/208.jpg)
SummaryThischapterhasexploredeventswithinAngularJS.YousawtwotypesofAngularJSeventemitters:$broadcast()and$emit().YoualsosawsomeexamplesofapplyingTDDtoeventsandhoweventsgiveaseparationofcontrollersandcode.Inaddition,youexpandedthetypesoftestingtechniquestoincludeservicesandreiteratedthetestingofcontrollersandmodels.YoualsoexploredfurtherconfigurationofKarmatouseitsfeatures.Inthenextchapter,youwilllookattheintegrationandtestingofdataandAPIsintoanAngularJSapplication.
www.it-ebooks.info
![Page 209: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/209.jpg)
Chapter7.GiveMeSomeDataApplicationsneedawaytoconsumetheever-expansiveworldofdata.Mostapplicationswrittentodayconsumedata.LuckilyforAngularJSdevelopers,consumingdataisquiteeasy.Testingdataconsumptionisalsoacorecomponentoftheframework.Inthischapter,wewillcoverthefollowingtopics:
IntegratingaREST-basedserviceCreatingandmockingAngularJS’s$httpHandlingexceptionsImplementingafakeAPIbuilderpattern
www.it-ebooks.info
![Page 210: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/210.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/211.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/212.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/213.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/214.jpg)
callbackcanbepassedintothebeforeEach,afterEach,describe,anditmethods.
Youwillbeleveragingthisexamplethroughtherestofthechapter,sobesurethatyouunderstandthemainconcepts.NowthatyouhavetestedinKarma,thenextsectionwillshowyouwhatProtractoroffersfromanasynchronousstandpoint.
www.it-ebooks.info
![Page 215: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/215.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/216.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/217.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/218.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/219.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/220.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/221.jpg)
DisplayingproductswithRESTAllthecorecomponentsofREST,asynchronoustesting,andmockingHTTPrequestshavebeendiscussed.Now,thefollowingwalk-throughwillprovideafullexamplethatwilllookatdisplayingproductsthatareretrievedthroughanexternalservice.Theexamplewillignorethecreationofanexternalserviceandfocusonthedataitprovides:alistofproductsinaJSONformat.Thewalk-throughwilltakeabottom-upapproachsothatthecoredatalayerisworkedoutbeforeaddingtheUIelements.
www.it-ebooks.info
![Page 222: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/222.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/223.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/224.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/225.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/226.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/227.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/228.jpg)
expect(scope.error).toEqual('error');
Nowthatthetestshavebeenassembled,thenextstepistomakethemrun.
www.it-ebooks.info
![Page 229: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/229.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/230.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/231.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/232.jpg)
<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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/233.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/234.jpg)
varresults=element.all(by.repeater('resultinresults'));
2. Assertthatthecountisgreaterthan0:
expect(results.count()).toBeGreaterThan(0);
Thetestsetupiscomplete.Thenextstepistomakeitrun.
www.it-ebooks.info
![Page 235: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/235.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/236.jpg)
Themakeitbetterstepwillbeskippedasthereisnothingimmediatethatneedstoberefactored.Atthispoint,theapplicationistestedandoperatedusingthemockeddata.Youshouldbeabletoseehowpowerfulthistechniquecanbeasyou’rebuildingupanapplication.Thenextsectionwilllookatremovingthescaffoldingandusinganactualbackend.
www.it-ebooks.info
![Page 237: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/237.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/238.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/239.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/240.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/241.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/242.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/243.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/244.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/245.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/246.jpg)
TestfirstThetestwillcheckwhetherthetitleofthepageisequaltoseleniumTestTitle.CreateanewProtractortestfilenamedscenario.js.
AssembleTosetupthetest,weneedtonavigatethebrowsertotherootofthewebapplication:
beforeEach(function(){
browser.get("/");
});
ThereisnoActsectionaswewillsimplybecheckingthattheloadedindexpagehasthetitleweneed.
AssertTheassertneedsgetthetitleandcompareitwiththeexpectedvalue:
it('',function(){
expect(browser.getTitle()).toBe('seleniumTestTitle');
});
www.it-ebooks.info
![Page 247: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/247.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/248.jpg)
<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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/249.jpg)
SummaryThisappendixhasshownyouhowtosetupandusetheSeleniumstandaloneserver.Therearemanyoptionsandadvantagesofusingthestandaloneserver.TheadvantagesaregearedmoreforadvancedtestingwhenyouwanttouseadedicatedSeleniumServeroraPaaS(PlatformasaService)orifyouwanttotestafunctionalityondifferentbrowsersandasthevolumeofyourProtractortestsgrow.Formoreinformation,visittheSeleniumhomepageathttp://www.seleniumhq.org/.
www.it-ebooks.info
![Page 250: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/250.jpg)
AppendixB.AutomatingKarmaUnitTestingonCommitRunningtestslocallyisonething,buthowdoyouknowwhethertheywillworkonsomeoneelse’scomputer.Settingupcontinuoustestingandintegrationshouldbepartofeveryapplicationyouwrite.Oneofthebestthingsisthatthetoolstosetuparefree,easytouse,andbestofall,theygettoshowcaseyourtests!ThefollowingsectionwillexplorehowtosetupcontinuousintegrationusingGitHubforsourcecontrolandTravisforcontinuousintegration.
www.it-ebooks.info
![Page 251: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/251.jpg)
GitHubGitHubisasourcecontrol,collaboration,andall-aroundawesometool.Foropensourceprojects,itisfree.Onceyousignup,youcangetstartedandcreateanewrepositoryforyourproject.GitHubprovidesaGitURLforeveryproject;theURLcanthenbesetuptopushchangeslikeanyotherGitrepository.OneofthebenefitsofusingGitHubisthatitautomaticallyprovideshooksintootherapplicationsandservices.WhensettingupcontinuousintegrationandtestingthroughTravisCI,youwillleveragetheTravisCIGitHubhook.
www.it-ebooks.info
![Page 252: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/252.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/253.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/254.jpg)
SettingthehookGitHubprovidesseveralhooksintootherapplications.Ahookallowsyoutochainactionswhenacommitoccurs.Ahookisanextremelyusefulfeaturefromacontinuousintegrationstandpointbecausewecansetupthecodetobetestedoneverycommit.TravisCIhasaGitHubhookthatcanbeeasilysetuponanyGitHubrepository.Thefollowingisawalk-throughonhowtocreateaTravisCIhookonyouropensourcerepository.
www.it-ebooks.info
![Page 255: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/255.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/256.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/257.jpg)
Ifyouhaveanyissues,gototheTravisCIGettingstartedguideathttp://docs.travis-ci.com/user/getting-started/.
www.it-ebooks.info
![Page 258: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/258.jpg)
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 260: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/260.jpg)
Chapter1,IntroductiontoTest-drivenDevelopmentQ1 2
Q2 1
Q3 1
Q4 1
Q5 2
www.it-ebooks.info
![Page 262: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/262.jpg)
Chapter3,End-to-endTestingwithProtractorQ1 1
Q2 1
Q3 1
www.it-ebooks.info
![Page 267: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/267.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/268.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/269.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/270.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/271.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/272.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/273.jpg)
Fflipfloptest,AngularJSroutes
viewsflip,creating/Makingtheviewsflipflip,asserting/Assertingafliprunning/Makingflipfloprunimproving/Makingflipflopbetter
FunctionUnderTest/Testingtechniquesfundamentals,searchapplication
Protractorlocators/Protractorlocators
www.it-ebooks.info
![Page 275: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/275.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/276.jpg)
Iinjectvariable
about/Assemble,Act,andAssert(3A’s)installation
Karma/InstallingKarmaProtractor/Protractorinstallation
itparameterabout/Testfirst,Testfirst
Itproperty,Karmatest/TestingwithKarma
www.it-ebooks.info
![Page 277: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/277.jpg)
JJasmine
about/Jasminepros/Jasminecons/Jasmine
Jasminespyused,forcreatingtestdouble/TestingdoubleswithJasminespies
JavaScripttestingframeworksabout/JavaScripttestingframeworksJasmine/JasmineSelenium/SeleniumMocha/Mocha
JavaScripttestingtoolsabout/JavaScripttestingtoolsKarma/KarmaProtractor/Protractor
www.it-ebooks.info
![Page 278: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/278.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/279.jpg)
installing/TestsetupKarmaunittesting
testsetup/Testsetuptestscripts/Testscriptshook,setting/Settingthehookhook,creating/CreatingthehookTravisconfigurationfile,adding/AddingaTravisconfigurationfile
www.it-ebooks.info
![Page 280: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/280.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/281.jpg)
NNode.js
URL/Installationprerequisites,Installationprerequisitesabout/Installationprerequisites
NodePackageManager(npm)modules/Mocha
www.it-ebooks.info
![Page 282: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/282.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/283.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/284.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/285.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/286.jpg)
about/Installationprerequisitesinstalling/InstallingWebDriverforChrome
success,measuringinTDDsteps,breakingdown/Breakingdownthestepstestfirstmethodology/Measuretwicecutonce
www.it-ebooks.info
![Page 287: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/287.jpg)
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: AngularJS Test-driven Development · 2015. 12. 1. · Simran Bhogal Maria Gould Ameesha Green Paul Hindle Indexer Hemangini Bari Production Coordinator . Aparna Bhagat Cover Work](https://reader035.fdocuments.us/reader035/viewer/2022071423/611e38c9d1de2b31544f2aa5/html5/thumbnails/288.jpg)
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