288
www.it-ebooks.info

AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

www.it-ebooks.info

Page 2: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AngularJSTest-drivenDevelopment

www.it-ebooks.info

Page 3: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter3,End-to-endTestingwithProtractor

Chapter4,TheFirstStep

Chapter5,FlipFlop

Chapter6,TellingtheWorld

Chapter7,GiveMeSomeData

Index

www.it-ebooks.info

Page 14: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AngularJSTest-drivenDevelopment

www.it-ebooks.info

Page 15: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

CreditsAuthor

TimChaplin

Reviewers

Md.ZiaulHaq

NiveJayasekar

TimPei

AndiSmith

CommissioningEditor

PramilaBalan

AcquisitionEditor

ReshmaRaman

ContentDevelopmentEditor

ManasiPandire

TechnicalEditor

MadhunikitaSunilChindarkar

CopyEditors

GladsonMonteiro

AdithiShetty

StutiSrivastava

ProjectCoordinator

LeenaPurkait

Proofreaders

SimranBhogal

MariaGould

AmeeshaGreen

PaulHindle

Indexer

HemanginiBari

ProductionCoordinator

www.it-ebooks.info

Page 17: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AparnaBhagat

CoverWork

AparnaBhagat

www.it-ebooks.info

Page 18: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

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

Iwouldliketothankmywife,Richi,andmynewbornson,Arabi,whoismyinspiration.

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

I’dliketothankthepeopleatPacktPublishing,LeenaPurkaitandKirtiPatil,fortheirhelpinproducingthisbook.

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

I’dliketothankmyparentsfortheirconstantsupportofmypursuits,whileprovidingmegreatadvicealongtheway.

AndiSmith(@andismith)isaseniorarchitectwhospecializesinfrontendsolutionsatideasandinnovationagency,AKQA.

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

Andimaintainsablogfocusedonfrontenddevelopmentathttp://www.andismith.com/.

Iwouldliketothankmywife,Amy,forallherloveandsupport.

www.it-ebooks.info

Page 20: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

www.PacktPub.com

www.it-ebooks.info

Page 21: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

www.it-ebooks.info

Page 23: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.

www.it-ebooks.info

Page 24: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 27: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.

www.it-ebooks.info

Page 30: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 31: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.

Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.

www.it-ebooks.info

Page 33: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

QuestionsYoucancontactusat<[email protected]>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.

www.it-ebooks.info

Page 34: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AnoverviewofTDDTDDisnotusedonlytodevelopsoftware.Thefundamentalprinciplescanbeseeninmanyindustries.ThissectionwillexplorethefundamentalsofTDDandhowtheyareappliedbyatailor.

www.it-ebooks.info

Page 36: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

varcalculator={

multiply:function(){

return9;

}

};

Inthebrowser,theJavaScriptconsolererunsthetest.Theresultshouldbeasfollows:

Yes!Thetestpassed.Timetocrossoutthefirstitemfromtheto-dolist:

Addmultiplicationfunctionality:3*3=9

Nowthatthereisapassingtest,thenextstepwillbetoremovethehardcodedvalueinthemultiplyfunction.

MakingitbetterTherefactoringstepneedstoremovethehardcodedreturnvalueofthemultiplyfunction.Therequiredlogicisasfollows:

varcalculator={

multiply:function(amount1,amount2){

returnamount1*amount2;

}

};

Rerunthetestsandconfirmthetestpasses.Excellent!Nowthemultiplyfunctioniscomplete.Hereisthefullcodeforthecalculatorandtest:

varcalculator={

multiply:function(amount1,amount2){

returnamount1*amount2;

}

};

varmultipleTest1=function(){

varresult=calculator.multiply(3,3);

if(result===9){

console.log('TestPassed');

}

else{

console.log('TestFailed');

}

};

www.it-ebooks.info

Page 42: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

multipleTest1();

www.it-ebooks.info

Page 43: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

};

//beforethereturnvalueisstubbed

Console.log(objectUnderTest.someFunction());

//displays'stubme'

jasmine.spyOn(objectUnderTest,'someFunction')

.and

.returnValue('stubbedvalue');

//Afterthereturnvalueisstubbed

Console.log(objectUnderTest.someFunction());

//displays'stubbedvalue'

TestingargumentsAtestdoubleprovidesinsightsintohowamethodisusedinanapplication.Asanexample,atestmightwanttoassertwhatargumentsamethodwascalledwithorthenumberoftimesamethodwascalled.Hereisanexamplefunction:

varobjectUnderTest={

someFunction:function(arg1,arg2){}

};

Herearethestepstotesttheargumentstheprecedingfunctioniscalledwith:

1. Createaspysothattheargumentscalledcanbecaptured:

jasmine.spyOn(objectUnderTest,'someFunction');

2. Thentoaccessthearguments,dothefollowing:

//Gettheargumentsforthefirstcallofthefunction

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

console.log(callArgs);

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

3. Hereishowtheargumentscanbedisplayedusingconsole.log:

varobjectUnderTest={

someFunction:function(arg1,arg2){}

};

//createthespy

jasmine.spyOn(objectUnderTest,'someFunction');

//Callthemethodwithspecificarguments

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

//Gettheargumentsforthefirstcallofthefunction

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

console.log(callArgs);

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

www.it-ebooks.info

Page 47: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

www.it-ebooks.info

Page 48: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

};

TipDownloadingtheexamplecode

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

www.it-ebooks.info

Page 52: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

TestdoublesRefactoringBuildingpatterns

AlthoughTDDisahugetopic,thisbookissolelyfocusedontheTDDprinciplesandpracticestobeusedwithAngularJS.Inthenextchapter,youwillstartthejourneyandseehowtosetuptheKarmatestrunner.

www.it-ebooks.info

Page 54: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 55: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

JavaScripttestingtoolsKnowingwhatthedifferenttestingtoolsareishalfthebattle.Inthissection,youwilllearnaboutthetwoprimarytoolsthatwillbediscussedandusedthroughoutthebook.Theyare:

Karma:ThisisatestrunnerProtractor:Thisisanend-to-endtestingframework

www.it-ebooks.info

Page 56: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

Pros Cons

Configurabletotestmultipleenvironments Documentationandexamplesarelimited

EasyintegrationwithAngularJS

Syntaxandtestingcanbesimilartothetestingframeworkchosenforunittesting

www.it-ebooks.info

Page 58: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

JavaScripttestingframeworksInthissection,youwilllearnaboutthetestingframeworksthatwillsupportyouinyourTDDpractices.Theseinclude:

JasmineSeleniumMocha

www.it-ebooks.info

Page 59: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

BirthofKarmaWhenpickingupanewtool,itisimportanttounderstandwhereitcamefromandwhyitwasbuilt.ThissectiongivesyousomebackgroundoftheoriginsofKarma.

www.it-ebooks.info

Page 63: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

Themainfocusofthissectionwillbeonthespecificconfigurationusedinthisbookandnotanin-depthinstallationguide.

www.it-ebooks.info

Page 66: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

NowthatKarmaisinstalledandrunning,it’stimetoputittouse.

www.it-ebooks.info

Page 70: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

UsingKarmawithAngularJSHere,youwillwalkthroughaTDDapproachtoanAngularJScomponent.Bytheendofthischapter,youshouldbeableto:

FeelconfidentaboutusingKarmaanditsconfigurationUnderstandthebasiccomponentsofaJasminetestStarttounderstandhowtointegrateaTDDapproachinanAngularJSapplication

www.it-ebooks.info

Page 73: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

$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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

Thatisit.KarmaisnowrunningforthefirstAngularJSapplication.

www.it-ebooks.info

Page 76: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 77: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

.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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Nextupistherequirementtoaddanewitemtothelist.TheTDDrhythmwillbefollowedagain:testfirst,makeitrun,andmakeitbetter.

www.it-ebooks.info

Page 83: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

//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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 88: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 92: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

EndoflifeScenarioRunnerisinmaintenancemodeandhasreacheditsendoflife.IthasbeendeprecatedinplaceofProtractor.Inthissection,wewilllookatwhatScenarioRunnerwasandwhatgapsthetoolhad.

www.it-ebooks.info

Page 93: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Theinstallationisnowcomplete.BothProtractorandSeleniumWebDriverforChromehavebeeninstalled.Wecannowmoveontotheconfiguration.

www.it-ebooks.info

Page 99: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

};

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

HelloProtractorWiththeProtractorinstallationandconfigurationcomplete,youcanlookatwritingarealtest.ThissectionwillwalkyouthroughusingTDDwithProtractor.Attheendofthischapter,youshouldbeableto:

FeelconfidentinusingandconfiguringProtractorUnderstandthebasiccomponentsofaProtractortestStarttounderstandhowtointegrateaTDDapproachtoend-to-endtesting

www.it-ebooks.info

Page 102: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

});

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

<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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

</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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

CleaningupthegapsThereareacoupleofthingsthatwerediscussedinthischapterthatneedsomefurtherclarification.Thisincludesthefollowing:

Whereistheasynchronouslogic?HowtoreallyimplementTDDwithend-to-endtests.

www.it-ebooks.info

Page 111: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

SettinguptheprojectInpreviouschapters,wediscussedindetailhowaprojectshouldbesetup,explainedthedifferentcomponentsinvolved,andwalkedthroughtheentireprocessoftesting.Iwillskipthesedetailsandprovidealistinthefollowingsectionfortheinitialactionstogettheprojectsetup.

www.it-ebooks.info

Page 118: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

TestingacontrollerBeforegettingintothespecification,andthemind-setofthefeaturebeingdelivered,itisimportanttoseethefundamentalsoftestingacontroller.AnAngularJScontrollerisakeycomponentusedinmostapplications.

www.it-ebooks.info

Page 124: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 127: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

$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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

}]);

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

$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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

MakeitbetterThetwocomponentsthatneedtobereworkedare:

AddingbehaviortotheSubmitbuttonRemovinghardcodedvalueofthecomments

www.it-ebooks.info

Page 135: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

OnwardsandupwardsNowthatwehavethefirstspecificationworkingend-to-endandunittested,wecanstartthenextspecification.Thenextspecificationstatesthattheuserswanttheabilitytolikeacomment.

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

www.it-ebooks.info

Page 140: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

<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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

AngularJSroutesPartialviewsProtractorlocationreferenceswithCSS(CascadingStyleSheets)andHTMLelementsHeadlessbrowsertestingwithKarma

www.it-ebooks.info

Page 149: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

ProtractorlocatorsHeadlessbrowsertesting

Afteryouhavereviewedtheseconcepts,youcanmoveontothewalk-through.

www.it-ebooks.info

Page 150: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

}]);

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

2. Rerunthetest.

5. TheProtractortestsnowpass.

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

Theinitialindexpageisshowninthefollowingscreenshot:

Thefollowingiswhatyou’llseeaftertheviewhasbeenswitched:

www.it-ebooks.info

Page 160: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 161: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 162: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Showmesomeresults!NowthattheSearchbuttonissetwiththerequiredfeatures,theresultingdetailsneedtobedisplayedwhenasearchresultisselected.Hereistheuserspecification.Giventhefollowingsearchresults:

IselectanitemfromthesearchresultsIwillseethedetailsinthemainpagecomponent

Followingthetop-downapproach,thefirststepwillbetheProtractortestsfollowedbythenecessarystepstogettheapplicationfullyfunctional.

www.it-ebooks.info

Page 167: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

}]);

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

MakingthesearchresulttestrunForthisstepofthelifecycle,wewillexecuteProtractorandmakefixesintheapplicationinordertomakethetestrunsuccessfully.Herearethestepsyouneedtofollow:

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

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

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

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

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

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

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

$scope.search=function(){

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

};

Nowrerunthetest.

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

www.it-ebooks.info

Page 172: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

www.it-ebooks.info

Page 173: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Afterasearchquery,theapplicationlookslikewhatisshowninthefollowingscreenshot:

Fordetailsoftheapplicationlooksasshowninthefollowingscreenshot(noticethattheURLcontainsthedetailroute):

www.it-ebooks.info

Page 177: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

BeforetheplungeBeforethewalk-through,thecoreconceptsofthechapterwillbereviewedfirst.Itisimportantthatyouunderstandtheseconceptsbeforeyoumoveontothewalk-through.

www.it-ebooks.info

Page 181: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

HereisasummaryofsomeoftheotherAngularJScomponentsthathavebeenlookedatsofar:

Attributesanddirectives:ThesedriveactionsandflowfromtheUIControllers:ThisprovidesthegluebetweentheUIandlogicServices:Thisisolatesthelogic

www.it-ebooks.info

Page 184: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

events.Asyouprogressthroughtherestoftheeventtests,youwillfindthatthesetupandtechniquesusedherewillbeusedthroughouttherestofthechapter.

www.it-ebooks.info

Page 188: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

HarnessingthepowerofeventsPublishingandsubscribingeventscanleadtosomeuglyandhard-to-understandspaghetticode.Nowthatthefoundationsforthechapterhavebeenreviewed,youcandiveintoimplementingeventsintothesearchapplication.

www.it-ebooks.info

Page 192: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

www.it-ebooks.info

Page 209: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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

IntegratingaREST-basedserviceCreatingandmockingAngularJS’s$httpHandlingexceptionsImplementingafakeAPIbuilderpattern

www.it-ebooks.info

Page 210: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

callbackcanbepassedintothebeforeEach,afterEach,describe,anditmethods.

Youwillbeleveragingthisexamplethroughtherestofthechapter,sobesurethatyouunderstandthemainconcepts.NowthatyouhavetestedinKarma,thenextsectionwillshowyouwhatProtractoroffersfromanasynchronousstandpoint.

www.it-ebooks.info

Page 215: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

DisplayingproductswithRESTAllthecorecomponentsofREST,asynchronoustesting,andmockingHTTPrequestshavebeendiscussed.Now,thefollowingwalk-throughwillprovideafullexamplethatwilllookatdisplayingproductsthatareretrievedthroughanexternalservice.Theexamplewillignorethecreationofanexternalserviceandfocusonthedataitprovides:alistofproductsinaJSONformat.Thewalk-throughwilltakeabottom-upapproachsothatthecoredatalayerisworkedoutbeforeaddingtheUIelements.

www.it-ebooks.info

Page 222: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

expect(scope.error).toEqual('error');

Nowthatthetestshavebeenassembled,thenextstepistomakethemrun.

www.it-ebooks.info

Page 229: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

<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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Themakeitbetterstepwillbeskippedasthereisnothingimmediatethatneedstoberefactored.Atthispoint,theapplicationistestedandoperatedusingthemockeddata.Youshouldbeabletoseehowpowerfulthistechniquecanbeasyou’rebuildingupanapplication.Thenextsectionwilllookatremovingthescaffoldingandusinganactualbackend.

www.it-ebooks.info

Page 237: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

<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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

SummaryThisappendixhasshownyouhowtosetupandusetheSeleniumstandaloneserver.Therearemanyoptionsandadvantagesofusingthestandaloneserver.TheadvantagesaregearedmoreforadvancedtestingwhenyouwanttouseadedicatedSeleniumServeroraPaaS(PlatformasaService)orifyouwanttotestafunctionalityondifferentbrowsersandasthevolumeofyourProtractortestsgrow.Formoreinformation,visittheSeleniumhomepageathttp://www.seleniumhq.org/.

www.it-ebooks.info

Page 250: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AppendixB.AutomatingKarmaUnitTestingonCommitRunningtestslocallyisonething,buthowdoyouknowwhethertheywillworkonsomeoneelse’scomputer.Settingupcontinuoustestingandintegrationshouldbepartofeveryapplicationyouwrite.Oneofthebestthingsisthatthetoolstosetuparefree,easytouse,andbestofall,theygettoshowcaseyourtests!ThefollowingsectionwillexplorehowtosetupcontinuousintegrationusingGitHubforsourcecontrolandTravisforcontinuousintegration.

www.it-ebooks.info

Page 251: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

GitHubGitHubisasourcecontrol,collaboration,andall-aroundawesometool.Foropensourceprojects,itisfree.Onceyousignup,youcangetstartedandcreateanewrepositoryforyourproject.GitHubprovidesaGitURLforeveryproject;theURLcanthenbesetuptopushchangeslikeanyotherGitrepository.OneofthebenefitsofusingGitHubisthatitautomaticallyprovideshooksintootherapplicationsandservices.WhensettingupcontinuousintegrationandtestingthroughTravisCI,youwillleveragetheTravisCIGitHubhook.

www.it-ebooks.info

Page 252: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

SettingthehookGitHubprovidesseveralhooksintootherapplications.Ahookallowsyoutochainactionswhenacommitoccurs.Ahookisanextremelyusefulfeaturefromacontinuousintegrationstandpointbecausewecansetupthecodetobetestedoneverycommit.TravisCIhasaGitHubhookthatcanbeeasilysetuponanyGitHubrepository.Thefollowingisawalk-throughonhowtocreateaTravisCIhookonyouropensourcerepository.

www.it-ebooks.info

Page 255: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Ifyouhaveanyissues,gototheTravisCIGettingstartedguideathttp://docs.travis-ci.com/user/getting-started/.

www.it-ebooks.info

Page 258: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

ReferencesThefollowingaresomereferencesthatmayhelpyouwiththeconcepts:

ThisformofuserspecificationiswrittenusingtheGerkinsyntax.TheGerkinsyntaxallowsyoutowritethespecificationsinawell-formattedmanner.Seethefollowinglinkformoredetails:http://en.wikipedia.org/wiki/Behavior-driven_development.TheJavaScriptJabberhomepagecanbefoundathttp://javascriptjabber.com/106-jsj-protractor-with-julie-ralph/TheGitHubpageforhttp-servercanbefoundathttps://github.com/nodeapps/http-server

www.it-ebooks.info

Page 259: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

AppendixC.Answers

www.it-ebooks.info

Page 260: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter1,IntroductiontoTest-drivenDevelopmentQ1 2

Q2 1

Q3 1

Q4 1

Q5 2

www.it-ebooks.info

Page 261: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter2,TheKarmaWayQ1 2

Q2 2

Q3 2

Q4 2

www.it-ebooks.info

Page 262: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter3,End-to-endTestingwithProtractorQ1 1

Q2 1

Q3 1

www.it-ebooks.info

Page 263: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter4,TheFirstStepQ1 1

Q2 2

Q3 1

www.it-ebooks.info

Page 264: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter5,FlipFlopQ1 3

Q2 3

Q3 1

www.it-ebooks.info

Page 265: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter6,TellingtheWorldQ1 2

Q2 1

Q3 1

www.it-ebooks.info

Page 266: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Chapter7,GiveMeSomeDataQ1 1

Q2 2

Q3 1

Q4 2

Q5 1

www.it-ebooks.info

Page 267: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

Fflipfloptest,AngularJSroutes

viewsflip,creating/Makingtheviewsflipflip,asserting/Assertingafliprunning/Makingflipfloprunimproving/Makingflipflopbetter

FunctionUnderTest/Testingtechniquesfundamentals,searchapplication

Protractorlocators/Protractorlocators

www.it-ebooks.info

Page 274: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

GGitHub

about/GitHub

www.it-ebooks.info

Page 275: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

installing/TestsetupKarmaunittesting

testsetup/Testsetuptestscripts/Testscriptshook,setting/Settingthehookhook,creating/CreatingthehookTravisconfigurationfile,adding/AddingaTravisconfigurationfile

www.it-ebooks.info

Page 280: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

NNode.js

URL/Installationprerequisites,Installationprerequisitesabout/Installationprerequisites

NodePackageManager(npm)modules/Mocha

www.it-ebooks.info

Page 282: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

about/Installationprerequisitesinstalling/InstallingWebDriverforChrome

success,measuringinTDDsteps,breakingdown/Breakingdownthestepstestfirstmethodology/Measuretwicecutonce

www.it-ebooks.info

Page 287: AngularJS Test-driven Development - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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 - DropPDF1.droppdf.com/files/BwnWc/angularjs-test-driven-development.pdfAngularJS Test-driven Development Credits About the Author About the Reviewers

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