Nessuna descrizione

qunit.js 184KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605
  1. /*!
  2. * QUnit 2.9.2
  3. * https://qunitjs.com/
  4. *
  5. * Copyright jQuery Foundation and other contributors
  6. * Released under the MIT license
  7. * https://jquery.org/license
  8. *
  9. * Date: 2019-02-21T22:49Z
  10. */
  11. (function (global$1) {
  12. 'use strict';
  13. global$1 = global$1 && global$1.hasOwnProperty('default') ? global$1['default'] : global$1;
  14. var window$1 = global$1.window;
  15. var self$1 = global$1.self;
  16. var console = global$1.console;
  17. var setTimeout$1 = global$1.setTimeout;
  18. var clearTimeout = global$1.clearTimeout;
  19. var document$1 = window$1 && window$1.document;
  20. var navigator = window$1 && window$1.navigator;
  21. var localSessionStorage = function () {
  22. var x = "qunit-test-string";
  23. try {
  24. global$1.sessionStorage.setItem(x, x);
  25. global$1.sessionStorage.removeItem(x);
  26. return global$1.sessionStorage;
  27. } catch (e) {
  28. return undefined;
  29. }
  30. }();
  31. /**
  32. * Returns a function that proxies to the given method name on the globals
  33. * console object. The proxy will also detect if the console doesn't exist and
  34. * will appropriately no-op. This allows support for IE9, which doesn't have a
  35. * console if the developer tools are not open.
  36. */
  37. function consoleProxy(method) {
  38. return function () {
  39. if (console) {
  40. console[method].apply(console, arguments);
  41. }
  42. };
  43. }
  44. var Logger = {
  45. warn: consoleProxy("warn")
  46. };
  47. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  48. return typeof obj;
  49. } : function (obj) {
  50. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  51. };
  52. var classCallCheck = function (instance, Constructor) {
  53. if (!(instance instanceof Constructor)) {
  54. throw new TypeError("Cannot call a class as a function");
  55. }
  56. };
  57. var createClass = function () {
  58. function defineProperties(target, props) {
  59. for (var i = 0; i < props.length; i++) {
  60. var descriptor = props[i];
  61. descriptor.enumerable = descriptor.enumerable || false;
  62. descriptor.configurable = true;
  63. if ("value" in descriptor) descriptor.writable = true;
  64. Object.defineProperty(target, descriptor.key, descriptor);
  65. }
  66. }
  67. return function (Constructor, protoProps, staticProps) {
  68. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  69. if (staticProps) defineProperties(Constructor, staticProps);
  70. return Constructor;
  71. };
  72. }();
  73. var toConsumableArray = function (arr) {
  74. if (Array.isArray(arr)) {
  75. for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
  76. return arr2;
  77. } else {
  78. return Array.from(arr);
  79. }
  80. };
  81. var toString = Object.prototype.toString;
  82. var hasOwn = Object.prototype.hasOwnProperty;
  83. var now = Date.now || function () {
  84. return new Date().getTime();
  85. };
  86. var hasPerformanceApi = detectPerformanceApi();
  87. var performance = hasPerformanceApi ? window$1.performance : undefined;
  88. var performanceNow = hasPerformanceApi ? performance.now.bind(performance) : now;
  89. function detectPerformanceApi() {
  90. return window$1 && typeof window$1.performance !== "undefined" && typeof window$1.performance.mark === "function" && typeof window$1.performance.measure === "function";
  91. }
  92. function measure(comment, startMark, endMark) {
  93. // `performance.measure` may fail if the mark could not be found.
  94. // reasons a specific mark could not be found include: outside code invoking `performance.clearMarks()`
  95. try {
  96. performance.measure(comment, startMark, endMark);
  97. } catch (ex) {
  98. Logger.warn("performance.measure could not be executed because of ", ex.message);
  99. }
  100. }
  101. var defined = {
  102. document: window$1 && window$1.document !== undefined,
  103. setTimeout: setTimeout$1 !== undefined
  104. };
  105. // Returns a new Array with the elements that are in a but not in b
  106. function diff(a, b) {
  107. var i,
  108. j,
  109. result = a.slice();
  110. for (i = 0; i < result.length; i++) {
  111. for (j = 0; j < b.length; j++) {
  112. if (result[i] === b[j]) {
  113. result.splice(i, 1);
  114. i--;
  115. break;
  116. }
  117. }
  118. }
  119. return result;
  120. }
  121. /**
  122. * Determines whether an element exists in a given array or not.
  123. *
  124. * @method inArray
  125. * @param {Any} elem
  126. * @param {Array} array
  127. * @return {Boolean}
  128. */
  129. function inArray(elem, array) {
  130. return array.indexOf(elem) !== -1;
  131. }
  132. /**
  133. * Makes a clone of an object using only Array or Object as base,
  134. * and copies over the own enumerable properties.
  135. *
  136. * @param {Object} obj
  137. * @return {Object} New object with only the own properties (recursively).
  138. */
  139. function objectValues(obj) {
  140. var key,
  141. val,
  142. vals = is("array", obj) ? [] : {};
  143. for (key in obj) {
  144. if (hasOwn.call(obj, key)) {
  145. val = obj[key];
  146. vals[key] = val === Object(val) ? objectValues(val) : val;
  147. }
  148. }
  149. return vals;
  150. }
  151. function extend(a, b, undefOnly) {
  152. for (var prop in b) {
  153. if (hasOwn.call(b, prop)) {
  154. if (b[prop] === undefined) {
  155. delete a[prop];
  156. } else if (!(undefOnly && typeof a[prop] !== "undefined")) {
  157. a[prop] = b[prop];
  158. }
  159. }
  160. }
  161. return a;
  162. }
  163. function objectType(obj) {
  164. if (typeof obj === "undefined") {
  165. return "undefined";
  166. }
  167. // Consider: typeof null === object
  168. if (obj === null) {
  169. return "null";
  170. }
  171. var match = toString.call(obj).match(/^\[object\s(.*)\]$/),
  172. type = match && match[1];
  173. switch (type) {
  174. case "Number":
  175. if (isNaN(obj)) {
  176. return "nan";
  177. }
  178. return "number";
  179. case "String":
  180. case "Boolean":
  181. case "Array":
  182. case "Set":
  183. case "Map":
  184. case "Date":
  185. case "RegExp":
  186. case "Function":
  187. case "Symbol":
  188. return type.toLowerCase();
  189. default:
  190. return typeof obj === "undefined" ? "undefined" : _typeof(obj);
  191. }
  192. }
  193. // Safe object type checking
  194. function is(type, obj) {
  195. return objectType(obj) === type;
  196. }
  197. // Based on Java's String.hashCode, a simple but not
  198. // rigorously collision resistant hashing function
  199. function generateHash(module, testName) {
  200. var str = module + "\x1C" + testName;
  201. var hash = 0;
  202. for (var i = 0; i < str.length; i++) {
  203. hash = (hash << 5) - hash + str.charCodeAt(i);
  204. hash |= 0;
  205. }
  206. // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
  207. // strictly necessary but increases user understanding that the id is a SHA-like hash
  208. var hex = (0x100000000 + hash).toString(16);
  209. if (hex.length < 8) {
  210. hex = "0000000" + hex;
  211. }
  212. return hex.slice(-8);
  213. }
  214. // Test for equality any JavaScript type.
  215. // Authors: Philippe Rathé <prathe@gmail.com>, David Chan <david@troi.org>
  216. var equiv = (function () {
  217. // Value pairs queued for comparison. Used for breadth-first processing order, recursion
  218. // detection and avoiding repeated comparison (see below for details).
  219. // Elements are { a: val, b: val }.
  220. var pairs = [];
  221. var getProto = Object.getPrototypeOf || function (obj) {
  222. return obj.__proto__;
  223. };
  224. function useStrictEquality(a, b) {
  225. // This only gets called if a and b are not strict equal, and is used to compare on
  226. // the primitive values inside object wrappers. For example:
  227. // `var i = 1;`
  228. // `var j = new Number(1);`
  229. // Neither a nor b can be null, as a !== b and they have the same type.
  230. if ((typeof a === "undefined" ? "undefined" : _typeof(a)) === "object") {
  231. a = a.valueOf();
  232. }
  233. if ((typeof b === "undefined" ? "undefined" : _typeof(b)) === "object") {
  234. b = b.valueOf();
  235. }
  236. return a === b;
  237. }
  238. function compareConstructors(a, b) {
  239. var protoA = getProto(a);
  240. var protoB = getProto(b);
  241. // Comparing constructors is more strict than using `instanceof`
  242. if (a.constructor === b.constructor) {
  243. return true;
  244. }
  245. // Ref #851
  246. // If the obj prototype descends from a null constructor, treat it
  247. // as a null prototype.
  248. if (protoA && protoA.constructor === null) {
  249. protoA = null;
  250. }
  251. if (protoB && protoB.constructor === null) {
  252. protoB = null;
  253. }
  254. // Allow objects with no prototype to be equivalent to
  255. // objects with Object as their constructor.
  256. if (protoA === null && protoB === Object.prototype || protoB === null && protoA === Object.prototype) {
  257. return true;
  258. }
  259. return false;
  260. }
  261. function getRegExpFlags(regexp) {
  262. return "flags" in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0];
  263. }
  264. function isContainer(val) {
  265. return ["object", "array", "map", "set"].indexOf(objectType(val)) !== -1;
  266. }
  267. function breadthFirstCompareChild(a, b) {
  268. // If a is a container not reference-equal to b, postpone the comparison to the
  269. // end of the pairs queue -- unless (a, b) has been seen before, in which case skip
  270. // over the pair.
  271. if (a === b) {
  272. return true;
  273. }
  274. if (!isContainer(a)) {
  275. return typeEquiv(a, b);
  276. }
  277. if (pairs.every(function (pair) {
  278. return pair.a !== a || pair.b !== b;
  279. })) {
  280. // Not yet started comparing this pair
  281. pairs.push({ a: a, b: b });
  282. }
  283. return true;
  284. }
  285. var callbacks = {
  286. "string": useStrictEquality,
  287. "boolean": useStrictEquality,
  288. "number": useStrictEquality,
  289. "null": useStrictEquality,
  290. "undefined": useStrictEquality,
  291. "symbol": useStrictEquality,
  292. "date": useStrictEquality,
  293. "nan": function nan() {
  294. return true;
  295. },
  296. "regexp": function regexp(a, b) {
  297. return a.source === b.source &&
  298. // Include flags in the comparison
  299. getRegExpFlags(a) === getRegExpFlags(b);
  300. },
  301. // abort (identical references / instance methods were skipped earlier)
  302. "function": function _function() {
  303. return false;
  304. },
  305. "array": function array(a, b) {
  306. var i, len;
  307. len = a.length;
  308. if (len !== b.length) {
  309. // Safe and faster
  310. return false;
  311. }
  312. for (i = 0; i < len; i++) {
  313. // Compare non-containers; queue non-reference-equal containers
  314. if (!breadthFirstCompareChild(a[i], b[i])) {
  315. return false;
  316. }
  317. }
  318. return true;
  319. },
  320. // Define sets a and b to be equivalent if for each element aVal in a, there
  321. // is some element bVal in b such that aVal and bVal are equivalent. Element
  322. // repetitions are not counted, so these are equivalent:
  323. // a = new Set( [ {}, [], [] ] );
  324. // b = new Set( [ {}, {}, [] ] );
  325. "set": function set$$1(a, b) {
  326. var innerEq,
  327. outerEq = true;
  328. if (a.size !== b.size) {
  329. // This optimization has certain quirks because of the lack of
  330. // repetition counting. For instance, adding the same
  331. // (reference-identical) element to two equivalent sets can
  332. // make them non-equivalent.
  333. return false;
  334. }
  335. a.forEach(function (aVal) {
  336. // Short-circuit if the result is already known. (Using for...of
  337. // with a break clause would be cleaner here, but it would cause
  338. // a syntax error on older Javascript implementations even if
  339. // Set is unused)
  340. if (!outerEq) {
  341. return;
  342. }
  343. innerEq = false;
  344. b.forEach(function (bVal) {
  345. var parentPairs;
  346. // Likewise, short-circuit if the result is already known
  347. if (innerEq) {
  348. return;
  349. }
  350. // Swap out the global pairs list, as the nested call to
  351. // innerEquiv will clobber its contents
  352. parentPairs = pairs;
  353. if (innerEquiv(bVal, aVal)) {
  354. innerEq = true;
  355. }
  356. // Replace the global pairs list
  357. pairs = parentPairs;
  358. });
  359. if (!innerEq) {
  360. outerEq = false;
  361. }
  362. });
  363. return outerEq;
  364. },
  365. // Define maps a and b to be equivalent if for each key-value pair (aKey, aVal)
  366. // in a, there is some key-value pair (bKey, bVal) in b such that
  367. // [ aKey, aVal ] and [ bKey, bVal ] are equivalent. Key repetitions are not
  368. // counted, so these are equivalent:
  369. // a = new Map( [ [ {}, 1 ], [ {}, 1 ], [ [], 1 ] ] );
  370. // b = new Map( [ [ {}, 1 ], [ [], 1 ], [ [], 1 ] ] );
  371. "map": function map(a, b) {
  372. var innerEq,
  373. outerEq = true;
  374. if (a.size !== b.size) {
  375. // This optimization has certain quirks because of the lack of
  376. // repetition counting. For instance, adding the same
  377. // (reference-identical) key-value pair to two equivalent maps
  378. // can make them non-equivalent.
  379. return false;
  380. }
  381. a.forEach(function (aVal, aKey) {
  382. // Short-circuit if the result is already known. (Using for...of
  383. // with a break clause would be cleaner here, but it would cause
  384. // a syntax error on older Javascript implementations even if
  385. // Map is unused)
  386. if (!outerEq) {
  387. return;
  388. }
  389. innerEq = false;
  390. b.forEach(function (bVal, bKey) {
  391. var parentPairs;
  392. // Likewise, short-circuit if the result is already known
  393. if (innerEq) {
  394. return;
  395. }
  396. // Swap out the global pairs list, as the nested call to
  397. // innerEquiv will clobber its contents
  398. parentPairs = pairs;
  399. if (innerEquiv([bVal, bKey], [aVal, aKey])) {
  400. innerEq = true;
  401. }
  402. // Replace the global pairs list
  403. pairs = parentPairs;
  404. });
  405. if (!innerEq) {
  406. outerEq = false;
  407. }
  408. });
  409. return outerEq;
  410. },
  411. "object": function object(a, b) {
  412. var i,
  413. aProperties = [],
  414. bProperties = [];
  415. if (compareConstructors(a, b) === false) {
  416. return false;
  417. }
  418. // Be strict: don't ensure hasOwnProperty and go deep
  419. for (i in a) {
  420. // Collect a's properties
  421. aProperties.push(i);
  422. // Skip OOP methods that look the same
  423. if (a.constructor !== Object && typeof a.constructor !== "undefined" && typeof a[i] === "function" && typeof b[i] === "function" && a[i].toString() === b[i].toString()) {
  424. continue;
  425. }
  426. // Compare non-containers; queue non-reference-equal containers
  427. if (!breadthFirstCompareChild(a[i], b[i])) {
  428. return false;
  429. }
  430. }
  431. for (i in b) {
  432. // Collect b's properties
  433. bProperties.push(i);
  434. }
  435. // Ensures identical properties name
  436. return typeEquiv(aProperties.sort(), bProperties.sort());
  437. }
  438. };
  439. function typeEquiv(a, b) {
  440. var type = objectType(a);
  441. // Callbacks for containers will append to the pairs queue to achieve breadth-first
  442. // search order. The pairs queue is also used to avoid reprocessing any pair of
  443. // containers that are reference-equal to a previously visited pair (a special case
  444. // this being recursion detection).
  445. //
  446. // Because of this approach, once typeEquiv returns a false value, it should not be
  447. // called again without clearing the pair queue else it may wrongly report a visited
  448. // pair as being equivalent.
  449. return objectType(b) === type && callbacks[type](a, b);
  450. }
  451. function innerEquiv(a, b) {
  452. var i, pair;
  453. // We're done when there's nothing more to compare
  454. if (arguments.length < 2) {
  455. return true;
  456. }
  457. // Clear the global pair queue and add the top-level values being compared
  458. pairs = [{ a: a, b: b }];
  459. for (i = 0; i < pairs.length; i++) {
  460. pair = pairs[i];
  461. // Perform type-specific comparison on any pairs that are not strictly
  462. // equal. For container types, that comparison will postpone comparison
  463. // of any sub-container pair to the end of the pair queue. This gives
  464. // breadth-first search order. It also avoids the reprocessing of
  465. // reference-equal siblings, cousins etc, which can have a significant speed
  466. // impact when comparing a container of small objects each of which has a
  467. // reference to the same (singleton) large object.
  468. if (pair.a !== pair.b && !typeEquiv(pair.a, pair.b)) {
  469. return false;
  470. }
  471. }
  472. // ...across all consecutive argument pairs
  473. return arguments.length === 2 || innerEquiv.apply(this, [].slice.call(arguments, 1));
  474. }
  475. return function () {
  476. var result = innerEquiv.apply(undefined, arguments);
  477. // Release any retained objects
  478. pairs.length = 0;
  479. return result;
  480. };
  481. })();
  482. /**
  483. * Config object: Maintain internal state
  484. * Later exposed as QUnit.config
  485. * `config` initialized at top of scope
  486. */
  487. var config = {
  488. // The queue of tests to run
  489. queue: [],
  490. // Block until document ready
  491. blocking: true,
  492. // By default, run previously failed tests first
  493. // very useful in combination with "Hide passed tests" checked
  494. reorder: true,
  495. // By default, modify document.title when suite is done
  496. altertitle: true,
  497. // HTML Reporter: collapse every test except the first failing test
  498. // If false, all failing tests will be expanded
  499. collapse: true,
  500. // By default, scroll to top of the page when suite is done
  501. scrolltop: true,
  502. // Depth up-to which object will be dumped
  503. maxDepth: 5,
  504. // When enabled, all tests must call expect()
  505. requireExpects: false,
  506. // Placeholder for user-configurable form-exposed URL parameters
  507. urlConfig: [],
  508. // Set of all modules.
  509. modules: [],
  510. // The first unnamed module
  511. currentModule: {
  512. name: "",
  513. tests: [],
  514. childModules: [],
  515. testsRun: 0,
  516. unskippedTestsRun: 0,
  517. hooks: {
  518. before: [],
  519. beforeEach: [],
  520. afterEach: [],
  521. after: []
  522. }
  523. },
  524. callbacks: {},
  525. // The storage module to use for reordering tests
  526. storage: localSessionStorage
  527. };
  528. // take a predefined QUnit.config and extend the defaults
  529. var globalConfig = window$1 && window$1.QUnit && window$1.QUnit.config;
  530. // only extend the global config if there is no QUnit overload
  531. if (window$1 && window$1.QUnit && !window$1.QUnit.version) {
  532. extend(config, globalConfig);
  533. }
  534. // Push a loose unnamed module to the modules collection
  535. config.modules.push(config.currentModule);
  536. // Based on jsDump by Ariel Flesler
  537. // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
  538. var dump = (function () {
  539. function quote(str) {
  540. return "\"" + str.toString().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\"";
  541. }
  542. function literal(o) {
  543. return o + "";
  544. }
  545. function join(pre, arr, post) {
  546. var s = dump.separator(),
  547. base = dump.indent(),
  548. inner = dump.indent(1);
  549. if (arr.join) {
  550. arr = arr.join("," + s + inner);
  551. }
  552. if (!arr) {
  553. return pre + post;
  554. }
  555. return [pre, inner + arr, base + post].join(s);
  556. }
  557. function array(arr, stack) {
  558. var i = arr.length,
  559. ret = new Array(i);
  560. if (dump.maxDepth && dump.depth > dump.maxDepth) {
  561. return "[object Array]";
  562. }
  563. this.up();
  564. while (i--) {
  565. ret[i] = this.parse(arr[i], undefined, stack);
  566. }
  567. this.down();
  568. return join("[", ret, "]");
  569. }
  570. function isArray(obj) {
  571. return (
  572. //Native Arrays
  573. toString.call(obj) === "[object Array]" ||
  574. // NodeList objects
  575. typeof obj.length === "number" && obj.item !== undefined && (obj.length ? obj.item(0) === obj[0] : obj.item(0) === null && obj[0] === undefined)
  576. );
  577. }
  578. var reName = /^function (\w+)/,
  579. dump = {
  580. // The objType is used mostly internally, you can fix a (custom) type in advance
  581. parse: function parse(obj, objType, stack) {
  582. stack = stack || [];
  583. var res,
  584. parser,
  585. parserType,
  586. objIndex = stack.indexOf(obj);
  587. if (objIndex !== -1) {
  588. return "recursion(" + (objIndex - stack.length) + ")";
  589. }
  590. objType = objType || this.typeOf(obj);
  591. parser = this.parsers[objType];
  592. parserType = typeof parser === "undefined" ? "undefined" : _typeof(parser);
  593. if (parserType === "function") {
  594. stack.push(obj);
  595. res = parser.call(this, obj, stack);
  596. stack.pop();
  597. return res;
  598. }
  599. return parserType === "string" ? parser : this.parsers.error;
  600. },
  601. typeOf: function typeOf(obj) {
  602. var type;
  603. if (obj === null) {
  604. type = "null";
  605. } else if (typeof obj === "undefined") {
  606. type = "undefined";
  607. } else if (is("regexp", obj)) {
  608. type = "regexp";
  609. } else if (is("date", obj)) {
  610. type = "date";
  611. } else if (is("function", obj)) {
  612. type = "function";
  613. } else if (obj.setInterval !== undefined && obj.document !== undefined && obj.nodeType === undefined) {
  614. type = "window";
  615. } else if (obj.nodeType === 9) {
  616. type = "document";
  617. } else if (obj.nodeType) {
  618. type = "node";
  619. } else if (isArray(obj)) {
  620. type = "array";
  621. } else if (obj.constructor === Error.prototype.constructor) {
  622. type = "error";
  623. } else {
  624. type = typeof obj === "undefined" ? "undefined" : _typeof(obj);
  625. }
  626. return type;
  627. },
  628. separator: function separator() {
  629. if (this.multiline) {
  630. return this.HTML ? "<br />" : "\n";
  631. } else {
  632. return this.HTML ? "&#160;" : " ";
  633. }
  634. },
  635. // Extra can be a number, shortcut for increasing-calling-decreasing
  636. indent: function indent(extra) {
  637. if (!this.multiline) {
  638. return "";
  639. }
  640. var chr = this.indentChar;
  641. if (this.HTML) {
  642. chr = chr.replace(/\t/g, " ").replace(/ /g, "&#160;");
  643. }
  644. return new Array(this.depth + (extra || 0)).join(chr);
  645. },
  646. up: function up(a) {
  647. this.depth += a || 1;
  648. },
  649. down: function down(a) {
  650. this.depth -= a || 1;
  651. },
  652. setParser: function setParser(name, parser) {
  653. this.parsers[name] = parser;
  654. },
  655. // The next 3 are exposed so you can use them
  656. quote: quote,
  657. literal: literal,
  658. join: join,
  659. depth: 1,
  660. maxDepth: config.maxDepth,
  661. // This is the list of parsers, to modify them, use dump.setParser
  662. parsers: {
  663. window: "[Window]",
  664. document: "[Document]",
  665. error: function error(_error) {
  666. return "Error(\"" + _error.message + "\")";
  667. },
  668. unknown: "[Unknown]",
  669. "null": "null",
  670. "undefined": "undefined",
  671. "function": function _function(fn) {
  672. var ret = "function",
  673. // Functions never have name in IE
  674. name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
  675. if (name) {
  676. ret += " " + name;
  677. }
  678. ret += "(";
  679. ret = [ret, dump.parse(fn, "functionArgs"), "){"].join("");
  680. return join(ret, dump.parse(fn, "functionCode"), "}");
  681. },
  682. array: array,
  683. nodelist: array,
  684. "arguments": array,
  685. object: function object(map, stack) {
  686. var keys,
  687. key,
  688. val,
  689. i,
  690. nonEnumerableProperties,
  691. ret = [];
  692. if (dump.maxDepth && dump.depth > dump.maxDepth) {
  693. return "[object Object]";
  694. }
  695. dump.up();
  696. keys = [];
  697. for (key in map) {
  698. keys.push(key);
  699. }
  700. // Some properties are not always enumerable on Error objects.
  701. nonEnumerableProperties = ["message", "name"];
  702. for (i in nonEnumerableProperties) {
  703. key = nonEnumerableProperties[i];
  704. if (key in map && !inArray(key, keys)) {
  705. keys.push(key);
  706. }
  707. }
  708. keys.sort();
  709. for (i = 0; i < keys.length; i++) {
  710. key = keys[i];
  711. val = map[key];
  712. ret.push(dump.parse(key, "key") + ": " + dump.parse(val, undefined, stack));
  713. }
  714. dump.down();
  715. return join("{", ret, "}");
  716. },
  717. node: function node(_node) {
  718. var len,
  719. i,
  720. val,
  721. open = dump.HTML ? "&lt;" : "<",
  722. close = dump.HTML ? "&gt;" : ">",
  723. tag = _node.nodeName.toLowerCase(),
  724. ret = open + tag,
  725. attrs = _node.attributes;
  726. if (attrs) {
  727. for (i = 0, len = attrs.length; i < len; i++) {
  728. val = attrs[i].nodeValue;
  729. // IE6 includes all attributes in .attributes, even ones not explicitly
  730. // set. Those have values like undefined, null, 0, false, "" or
  731. // "inherit".
  732. if (val && val !== "inherit") {
  733. ret += " " + attrs[i].nodeName + "=" + dump.parse(val, "attribute");
  734. }
  735. }
  736. }
  737. ret += close;
  738. // Show content of TextNode or CDATASection
  739. if (_node.nodeType === 3 || _node.nodeType === 4) {
  740. ret += _node.nodeValue;
  741. }
  742. return ret + open + "/" + tag + close;
  743. },
  744. // Function calls it internally, it's the arguments part of the function
  745. functionArgs: function functionArgs(fn) {
  746. var args,
  747. l = fn.length;
  748. if (!l) {
  749. return "";
  750. }
  751. args = new Array(l);
  752. while (l--) {
  753. // 97 is 'a'
  754. args[l] = String.fromCharCode(97 + l);
  755. }
  756. return " " + args.join(", ") + " ";
  757. },
  758. // Object calls it internally, the key part of an item in a map
  759. key: quote,
  760. // Function calls it internally, it's the content of the function
  761. functionCode: "[code]",
  762. // Node calls it internally, it's a html attribute value
  763. attribute: quote,
  764. string: quote,
  765. date: quote,
  766. regexp: literal,
  767. number: literal,
  768. "boolean": literal,
  769. symbol: function symbol(sym) {
  770. return sym.toString();
  771. }
  772. },
  773. // If true, entities are escaped ( <, >, \t, space and \n )
  774. HTML: false,
  775. // Indentation unit
  776. indentChar: " ",
  777. // If true, items in a collection, are separated by a \n, else just a space.
  778. multiline: true
  779. };
  780. return dump;
  781. })();
  782. var SuiteReport = function () {
  783. function SuiteReport(name, parentSuite) {
  784. classCallCheck(this, SuiteReport);
  785. this.name = name;
  786. this.fullName = parentSuite ? parentSuite.fullName.concat(name) : [];
  787. this.tests = [];
  788. this.childSuites = [];
  789. if (parentSuite) {
  790. parentSuite.pushChildSuite(this);
  791. }
  792. }
  793. createClass(SuiteReport, [{
  794. key: "start",
  795. value: function start(recordTime) {
  796. if (recordTime) {
  797. this._startTime = performanceNow();
  798. if (performance) {
  799. var suiteLevel = this.fullName.length;
  800. performance.mark("qunit_suite_" + suiteLevel + "_start");
  801. }
  802. }
  803. return {
  804. name: this.name,
  805. fullName: this.fullName.slice(),
  806. tests: this.tests.map(function (test) {
  807. return test.start();
  808. }),
  809. childSuites: this.childSuites.map(function (suite) {
  810. return suite.start();
  811. }),
  812. testCounts: {
  813. total: this.getTestCounts().total
  814. }
  815. };
  816. }
  817. }, {
  818. key: "end",
  819. value: function end(recordTime) {
  820. if (recordTime) {
  821. this._endTime = performanceNow();
  822. if (performance) {
  823. var suiteLevel = this.fullName.length;
  824. performance.mark("qunit_suite_" + suiteLevel + "_end");
  825. var suiteName = this.fullName.join(" – ");
  826. measure(suiteLevel === 0 ? "QUnit Test Run" : "QUnit Test Suite: " + suiteName, "qunit_suite_" + suiteLevel + "_start", "qunit_suite_" + suiteLevel + "_end");
  827. }
  828. }
  829. return {
  830. name: this.name,
  831. fullName: this.fullName.slice(),
  832. tests: this.tests.map(function (test) {
  833. return test.end();
  834. }),
  835. childSuites: this.childSuites.map(function (suite) {
  836. return suite.end();
  837. }),
  838. testCounts: this.getTestCounts(),
  839. runtime: this.getRuntime(),
  840. status: this.getStatus()
  841. };
  842. }
  843. }, {
  844. key: "pushChildSuite",
  845. value: function pushChildSuite(suite) {
  846. this.childSuites.push(suite);
  847. }
  848. }, {
  849. key: "pushTest",
  850. value: function pushTest(test) {
  851. this.tests.push(test);
  852. }
  853. }, {
  854. key: "getRuntime",
  855. value: function getRuntime() {
  856. return this._endTime - this._startTime;
  857. }
  858. }, {
  859. key: "getTestCounts",
  860. value: function getTestCounts() {
  861. var counts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 };
  862. counts = this.tests.reduce(function (counts, test) {
  863. if (test.valid) {
  864. counts[test.getStatus()]++;
  865. counts.total++;
  866. }
  867. return counts;
  868. }, counts);
  869. return this.childSuites.reduce(function (counts, suite) {
  870. return suite.getTestCounts(counts);
  871. }, counts);
  872. }
  873. }, {
  874. key: "getStatus",
  875. value: function getStatus() {
  876. var _getTestCounts = this.getTestCounts(),
  877. total = _getTestCounts.total,
  878. failed = _getTestCounts.failed,
  879. skipped = _getTestCounts.skipped,
  880. todo = _getTestCounts.todo;
  881. if (failed) {
  882. return "failed";
  883. } else {
  884. if (skipped === total) {
  885. return "skipped";
  886. } else if (todo === total) {
  887. return "todo";
  888. } else {
  889. return "passed";
  890. }
  891. }
  892. }
  893. }]);
  894. return SuiteReport;
  895. }();
  896. var focused = false;
  897. var moduleStack = [];
  898. function createModule(name, testEnvironment, modifiers) {
  899. var parentModule = moduleStack.length ? moduleStack.slice(-1)[0] : null;
  900. var moduleName = parentModule !== null ? [parentModule.name, name].join(" > ") : name;
  901. var parentSuite = parentModule ? parentModule.suiteReport : globalSuite;
  902. var skip = parentModule !== null && parentModule.skip || modifiers.skip;
  903. var todo = parentModule !== null && parentModule.todo || modifiers.todo;
  904. var module = {
  905. name: moduleName,
  906. parentModule: parentModule,
  907. tests: [],
  908. moduleId: generateHash(moduleName),
  909. testsRun: 0,
  910. unskippedTestsRun: 0,
  911. childModules: [],
  912. suiteReport: new SuiteReport(name, parentSuite),
  913. // Pass along `skip` and `todo` properties from parent module, in case
  914. // there is one, to childs. And use own otherwise.
  915. // This property will be used to mark own tests and tests of child suites
  916. // as either `skipped` or `todo`.
  917. skip: skip,
  918. todo: skip ? false : todo
  919. };
  920. var env = {};
  921. if (parentModule) {
  922. parentModule.childModules.push(module);
  923. extend(env, parentModule.testEnvironment);
  924. }
  925. extend(env, testEnvironment);
  926. module.testEnvironment = env;
  927. config.modules.push(module);
  928. return module;
  929. }
  930. function processModule(name, options, executeNow) {
  931. var modifiers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  932. if (objectType(options) === "function") {
  933. executeNow = options;
  934. options = undefined;
  935. }
  936. var module = createModule(name, options, modifiers);
  937. // Move any hooks to a 'hooks' object
  938. var testEnvironment = module.testEnvironment;
  939. var hooks = module.hooks = {};
  940. setHookFromEnvironment(hooks, testEnvironment, "before");
  941. setHookFromEnvironment(hooks, testEnvironment, "beforeEach");
  942. setHookFromEnvironment(hooks, testEnvironment, "afterEach");
  943. setHookFromEnvironment(hooks, testEnvironment, "after");
  944. var moduleFns = {
  945. before: setHookFunction(module, "before"),
  946. beforeEach: setHookFunction(module, "beforeEach"),
  947. afterEach: setHookFunction(module, "afterEach"),
  948. after: setHookFunction(module, "after")
  949. };
  950. var currentModule = config.currentModule;
  951. if (objectType(executeNow) === "function") {
  952. moduleStack.push(module);
  953. config.currentModule = module;
  954. executeNow.call(module.testEnvironment, moduleFns);
  955. moduleStack.pop();
  956. module = module.parentModule || currentModule;
  957. }
  958. config.currentModule = module;
  959. function setHookFromEnvironment(hooks, environment, name) {
  960. var potentialHook = environment[name];
  961. hooks[name] = typeof potentialHook === "function" ? [potentialHook] : [];
  962. delete environment[name];
  963. }
  964. function setHookFunction(module, hookName) {
  965. return function setHook(callback) {
  966. module.hooks[hookName].push(callback);
  967. };
  968. }
  969. }
  970. function module$1(name, options, executeNow) {
  971. if (focused) {
  972. return;
  973. }
  974. processModule(name, options, executeNow);
  975. }
  976. module$1.only = function () {
  977. if (focused) {
  978. return;
  979. }
  980. config.modules.length = 0;
  981. config.queue.length = 0;
  982. module$1.apply(undefined, arguments);
  983. focused = true;
  984. };
  985. module$1.skip = function (name, options, executeNow) {
  986. if (focused) {
  987. return;
  988. }
  989. processModule(name, options, executeNow, { skip: true });
  990. };
  991. module$1.todo = function (name, options, executeNow) {
  992. if (focused) {
  993. return;
  994. }
  995. processModule(name, options, executeNow, { todo: true });
  996. };
  997. var LISTENERS = Object.create(null);
  998. var SUPPORTED_EVENTS = ["runStart", "suiteStart", "testStart", "assertion", "testEnd", "suiteEnd", "runEnd"];
  999. /**
  1000. * Emits an event with the specified data to all currently registered listeners.
  1001. * Callbacks will fire in the order in which they are registered (FIFO). This
  1002. * function is not exposed publicly; it is used by QUnit internals to emit
  1003. * logging events.
  1004. *
  1005. * @private
  1006. * @method emit
  1007. * @param {String} eventName
  1008. * @param {Object} data
  1009. * @return {Void}
  1010. */
  1011. function emit(eventName, data) {
  1012. if (objectType(eventName) !== "string") {
  1013. throw new TypeError("eventName must be a string when emitting an event");
  1014. }
  1015. // Clone the callbacks in case one of them registers a new callback
  1016. var originalCallbacks = LISTENERS[eventName];
  1017. var callbacks = originalCallbacks ? [].concat(toConsumableArray(originalCallbacks)) : [];
  1018. for (var i = 0; i < callbacks.length; i++) {
  1019. callbacks[i](data);
  1020. }
  1021. }
  1022. /**
  1023. * Registers a callback as a listener to the specified event.
  1024. *
  1025. * @public
  1026. * @method on
  1027. * @param {String} eventName
  1028. * @param {Function} callback
  1029. * @return {Void}
  1030. */
  1031. function on(eventName, callback) {
  1032. if (objectType(eventName) !== "string") {
  1033. throw new TypeError("eventName must be a string when registering a listener");
  1034. } else if (!inArray(eventName, SUPPORTED_EVENTS)) {
  1035. var events = SUPPORTED_EVENTS.join(", ");
  1036. throw new Error("\"" + eventName + "\" is not a valid event; must be one of: " + events + ".");
  1037. } else if (objectType(callback) !== "function") {
  1038. throw new TypeError("callback must be a function when registering a listener");
  1039. }
  1040. if (!LISTENERS[eventName]) {
  1041. LISTENERS[eventName] = [];
  1042. }
  1043. // Don't register the same callback more than once
  1044. if (!inArray(callback, LISTENERS[eventName])) {
  1045. LISTENERS[eventName].push(callback);
  1046. }
  1047. }
  1048. function objectOrFunction(x) {
  1049. var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
  1050. return x !== null && (type === 'object' || type === 'function');
  1051. }
  1052. function isFunction(x) {
  1053. return typeof x === 'function';
  1054. }
  1055. var _isArray = void 0;
  1056. if (Array.isArray) {
  1057. _isArray = Array.isArray;
  1058. } else {
  1059. _isArray = function _isArray(x) {
  1060. return Object.prototype.toString.call(x) === '[object Array]';
  1061. };
  1062. }
  1063. var isArray = _isArray;
  1064. var len = 0;
  1065. var vertxNext = void 0;
  1066. var customSchedulerFn = void 0;
  1067. var asap = function asap(callback, arg) {
  1068. queue[len] = callback;
  1069. queue[len + 1] = arg;
  1070. len += 2;
  1071. if (len === 2) {
  1072. // If len is 2, that means that we need to schedule an async flush.
  1073. // If additional callbacks are queued before the queue is flushed, they
  1074. // will be processed by this flush that we are scheduling.
  1075. if (customSchedulerFn) {
  1076. customSchedulerFn(flush);
  1077. } else {
  1078. scheduleFlush();
  1079. }
  1080. }
  1081. };
  1082. function setScheduler(scheduleFn) {
  1083. customSchedulerFn = scheduleFn;
  1084. }
  1085. function setAsap(asapFn) {
  1086. asap = asapFn;
  1087. }
  1088. var browserWindow = typeof window !== 'undefined' ? window : undefined;
  1089. var browserGlobal = browserWindow || {};
  1090. var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
  1091. var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
  1092. // test for web worker but not in IE10
  1093. var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
  1094. // node
  1095. function useNextTick() {
  1096. // node version 0.10.x displays a deprecation warning when nextTick is used recursively
  1097. // see https://github.com/cujojs/when/issues/410 for details
  1098. return function () {
  1099. return process.nextTick(flush);
  1100. };
  1101. }
  1102. // vertx
  1103. function useVertxTimer() {
  1104. if (typeof vertxNext !== 'undefined') {
  1105. return function () {
  1106. vertxNext(flush);
  1107. };
  1108. }
  1109. return useSetTimeout();
  1110. }
  1111. function useMutationObserver() {
  1112. var iterations = 0;
  1113. var observer = new BrowserMutationObserver(flush);
  1114. var node = document.createTextNode('');
  1115. observer.observe(node, { characterData: true });
  1116. return function () {
  1117. node.data = iterations = ++iterations % 2;
  1118. };
  1119. }
  1120. // web worker
  1121. function useMessageChannel() {
  1122. var channel = new MessageChannel();
  1123. channel.port1.onmessage = flush;
  1124. return function () {
  1125. return channel.port2.postMessage(0);
  1126. };
  1127. }
  1128. function useSetTimeout() {
  1129. // Store setTimeout reference so es6-promise will be unaffected by
  1130. // other code modifying setTimeout (like sinon.useFakeTimers())
  1131. var globalSetTimeout = setTimeout;
  1132. return function () {
  1133. return globalSetTimeout(flush, 1);
  1134. };
  1135. }
  1136. var queue = new Array(1000);
  1137. function flush() {
  1138. for (var i = 0; i < len; i += 2) {
  1139. var callback = queue[i];
  1140. var arg = queue[i + 1];
  1141. callback(arg);
  1142. queue[i] = undefined;
  1143. queue[i + 1] = undefined;
  1144. }
  1145. len = 0;
  1146. }
  1147. function attemptVertx() {
  1148. try {
  1149. var vertx = Function('return this')().require('vertx');
  1150. vertxNext = vertx.runOnLoop || vertx.runOnContext;
  1151. return useVertxTimer();
  1152. } catch (e) {
  1153. return useSetTimeout();
  1154. }
  1155. }
  1156. var scheduleFlush = void 0;
  1157. // Decide what async method to use to triggering processing of queued callbacks:
  1158. if (isNode) {
  1159. scheduleFlush = useNextTick();
  1160. } else if (BrowserMutationObserver) {
  1161. scheduleFlush = useMutationObserver();
  1162. } else if (isWorker) {
  1163. scheduleFlush = useMessageChannel();
  1164. } else if (browserWindow === undefined && typeof require === 'function') {
  1165. scheduleFlush = attemptVertx();
  1166. } else {
  1167. scheduleFlush = useSetTimeout();
  1168. }
  1169. function then(onFulfillment, onRejection) {
  1170. var parent = this;
  1171. var child = new this.constructor(noop);
  1172. if (child[PROMISE_ID] === undefined) {
  1173. makePromise(child);
  1174. }
  1175. var _state = parent._state;
  1176. if (_state) {
  1177. var callback = arguments[_state - 1];
  1178. asap(function () {
  1179. return invokeCallback(_state, child, callback, parent._result);
  1180. });
  1181. } else {
  1182. subscribe(parent, child, onFulfillment, onRejection);
  1183. }
  1184. return child;
  1185. }
  1186. /**
  1187. `Promise.resolve` returns a promise that will become resolved with the
  1188. passed `value`. It is shorthand for the following:
  1189. ```javascript
  1190. let promise = new Promise(function(resolve, reject){
  1191. resolve(1);
  1192. });
  1193. promise.then(function(value){
  1194. // value === 1
  1195. });
  1196. ```
  1197. Instead of writing the above, your code now simply becomes the following:
  1198. ```javascript
  1199. let promise = Promise.resolve(1);
  1200. promise.then(function(value){
  1201. // value === 1
  1202. });
  1203. ```
  1204. @method resolve
  1205. @static
  1206. @param {Any} value value that the returned promise will be resolved with
  1207. Useful for tooling.
  1208. @return {Promise} a promise that will become fulfilled with the given
  1209. `value`
  1210. */
  1211. function resolve$1(object) {
  1212. /*jshint validthis:true */
  1213. var Constructor = this;
  1214. if (object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.constructor === Constructor) {
  1215. return object;
  1216. }
  1217. var promise = new Constructor(noop);
  1218. resolve(promise, object);
  1219. return promise;
  1220. }
  1221. var PROMISE_ID = Math.random().toString(36).substring(2);
  1222. function noop() {}
  1223. var PENDING = void 0;
  1224. var FULFILLED = 1;
  1225. var REJECTED = 2;
  1226. var TRY_CATCH_ERROR = { error: null };
  1227. function selfFulfillment() {
  1228. return new TypeError("You cannot resolve a promise with itself");
  1229. }
  1230. function cannotReturnOwn() {
  1231. return new TypeError('A promises callback cannot return that same promise.');
  1232. }
  1233. function getThen(promise) {
  1234. try {
  1235. return promise.then;
  1236. } catch (error) {
  1237. TRY_CATCH_ERROR.error = error;
  1238. return TRY_CATCH_ERROR;
  1239. }
  1240. }
  1241. function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
  1242. try {
  1243. then$$1.call(value, fulfillmentHandler, rejectionHandler);
  1244. } catch (e) {
  1245. return e;
  1246. }
  1247. }
  1248. function handleForeignThenable(promise, thenable, then$$1) {
  1249. asap(function (promise) {
  1250. var sealed = false;
  1251. var error = tryThen(then$$1, thenable, function (value) {
  1252. if (sealed) {
  1253. return;
  1254. }
  1255. sealed = true;
  1256. if (thenable !== value) {
  1257. resolve(promise, value);
  1258. } else {
  1259. fulfill(promise, value);
  1260. }
  1261. }, function (reason) {
  1262. if (sealed) {
  1263. return;
  1264. }
  1265. sealed = true;
  1266. reject(promise, reason);
  1267. }, 'Settle: ' + (promise._label || ' unknown promise'));
  1268. if (!sealed && error) {
  1269. sealed = true;
  1270. reject(promise, error);
  1271. }
  1272. }, promise);
  1273. }
  1274. function handleOwnThenable(promise, thenable) {
  1275. if (thenable._state === FULFILLED) {
  1276. fulfill(promise, thenable._result);
  1277. } else if (thenable._state === REJECTED) {
  1278. reject(promise, thenable._result);
  1279. } else {
  1280. subscribe(thenable, undefined, function (value) {
  1281. return resolve(promise, value);
  1282. }, function (reason) {
  1283. return reject(promise, reason);
  1284. });
  1285. }
  1286. }
  1287. function handleMaybeThenable(promise, maybeThenable, then$$1) {
  1288. if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
  1289. handleOwnThenable(promise, maybeThenable);
  1290. } else {
  1291. if (then$$1 === TRY_CATCH_ERROR) {
  1292. reject(promise, TRY_CATCH_ERROR.error);
  1293. TRY_CATCH_ERROR.error = null;
  1294. } else if (then$$1 === undefined) {
  1295. fulfill(promise, maybeThenable);
  1296. } else if (isFunction(then$$1)) {
  1297. handleForeignThenable(promise, maybeThenable, then$$1);
  1298. } else {
  1299. fulfill(promise, maybeThenable);
  1300. }
  1301. }
  1302. }
  1303. function resolve(promise, value) {
  1304. if (promise === value) {
  1305. reject(promise, selfFulfillment());
  1306. } else if (objectOrFunction(value)) {
  1307. handleMaybeThenable(promise, value, getThen(value));
  1308. } else {
  1309. fulfill(promise, value);
  1310. }
  1311. }
  1312. function publishRejection(promise) {
  1313. if (promise._onerror) {
  1314. promise._onerror(promise._result);
  1315. }
  1316. publish(promise);
  1317. }
  1318. function fulfill(promise, value) {
  1319. if (promise._state !== PENDING) {
  1320. return;
  1321. }
  1322. promise._result = value;
  1323. promise._state = FULFILLED;
  1324. if (promise._subscribers.length !== 0) {
  1325. asap(publish, promise);
  1326. }
  1327. }
  1328. function reject(promise, reason) {
  1329. if (promise._state !== PENDING) {
  1330. return;
  1331. }
  1332. promise._state = REJECTED;
  1333. promise._result = reason;
  1334. asap(publishRejection, promise);
  1335. }
  1336. function subscribe(parent, child, onFulfillment, onRejection) {
  1337. var _subscribers = parent._subscribers;
  1338. var length = _subscribers.length;
  1339. parent._onerror = null;
  1340. _subscribers[length] = child;
  1341. _subscribers[length + FULFILLED] = onFulfillment;
  1342. _subscribers[length + REJECTED] = onRejection;
  1343. if (length === 0 && parent._state) {
  1344. asap(publish, parent);
  1345. }
  1346. }
  1347. function publish(promise) {
  1348. var subscribers = promise._subscribers;
  1349. var settled = promise._state;
  1350. if (subscribers.length === 0) {
  1351. return;
  1352. }
  1353. var child = void 0,
  1354. callback = void 0,
  1355. detail = promise._result;
  1356. for (var i = 0; i < subscribers.length; i += 3) {
  1357. child = subscribers[i];
  1358. callback = subscribers[i + settled];
  1359. if (child) {
  1360. invokeCallback(settled, child, callback, detail);
  1361. } else {
  1362. callback(detail);
  1363. }
  1364. }
  1365. promise._subscribers.length = 0;
  1366. }
  1367. function tryCatch(callback, detail) {
  1368. try {
  1369. return callback(detail);
  1370. } catch (e) {
  1371. TRY_CATCH_ERROR.error = e;
  1372. return TRY_CATCH_ERROR;
  1373. }
  1374. }
  1375. function invokeCallback(settled, promise, callback, detail) {
  1376. var hasCallback = isFunction(callback),
  1377. value = void 0,
  1378. error = void 0,
  1379. succeeded = void 0,
  1380. failed = void 0;
  1381. if (hasCallback) {
  1382. value = tryCatch(callback, detail);
  1383. if (value === TRY_CATCH_ERROR) {
  1384. failed = true;
  1385. error = value.error;
  1386. value.error = null;
  1387. } else {
  1388. succeeded = true;
  1389. }
  1390. if (promise === value) {
  1391. reject(promise, cannotReturnOwn());
  1392. return;
  1393. }
  1394. } else {
  1395. value = detail;
  1396. succeeded = true;
  1397. }
  1398. if (promise._state !== PENDING) {
  1399. // noop
  1400. } else if (hasCallback && succeeded) {
  1401. resolve(promise, value);
  1402. } else if (failed) {
  1403. reject(promise, error);
  1404. } else if (settled === FULFILLED) {
  1405. fulfill(promise, value);
  1406. } else if (settled === REJECTED) {
  1407. reject(promise, value);
  1408. }
  1409. }
  1410. function initializePromise(promise, resolver) {
  1411. try {
  1412. resolver(function resolvePromise(value) {
  1413. resolve(promise, value);
  1414. }, function rejectPromise(reason) {
  1415. reject(promise, reason);
  1416. });
  1417. } catch (e) {
  1418. reject(promise, e);
  1419. }
  1420. }
  1421. var id = 0;
  1422. function nextId() {
  1423. return id++;
  1424. }
  1425. function makePromise(promise) {
  1426. promise[PROMISE_ID] = id++;
  1427. promise._state = undefined;
  1428. promise._result = undefined;
  1429. promise._subscribers = [];
  1430. }
  1431. function validationError() {
  1432. return new Error('Array Methods must be provided an Array');
  1433. }
  1434. var Enumerator = function () {
  1435. function Enumerator(Constructor, input) {
  1436. classCallCheck(this, Enumerator);
  1437. this._instanceConstructor = Constructor;
  1438. this.promise = new Constructor(noop);
  1439. if (!this.promise[PROMISE_ID]) {
  1440. makePromise(this.promise);
  1441. }
  1442. if (isArray(input)) {
  1443. this.length = input.length;
  1444. this._remaining = input.length;
  1445. this._result = new Array(this.length);
  1446. if (this.length === 0) {
  1447. fulfill(this.promise, this._result);
  1448. } else {
  1449. this.length = this.length || 0;
  1450. this._enumerate(input);
  1451. if (this._remaining === 0) {
  1452. fulfill(this.promise, this._result);
  1453. }
  1454. }
  1455. } else {
  1456. reject(this.promise, validationError());
  1457. }
  1458. }
  1459. createClass(Enumerator, [{
  1460. key: '_enumerate',
  1461. value: function _enumerate(input) {
  1462. for (var i = 0; this._state === PENDING && i < input.length; i++) {
  1463. this._eachEntry(input[i], i);
  1464. }
  1465. }
  1466. }, {
  1467. key: '_eachEntry',
  1468. value: function _eachEntry(entry, i) {
  1469. var c = this._instanceConstructor;
  1470. var resolve$$1 = c.resolve;
  1471. if (resolve$$1 === resolve$1) {
  1472. var _then = getThen(entry);
  1473. if (_then === then && entry._state !== PENDING) {
  1474. this._settledAt(entry._state, i, entry._result);
  1475. } else if (typeof _then !== 'function') {
  1476. this._remaining--;
  1477. this._result[i] = entry;
  1478. } else if (c === Promise$2) {
  1479. var promise = new c(noop);
  1480. handleMaybeThenable(promise, entry, _then);
  1481. this._willSettleAt(promise, i);
  1482. } else {
  1483. this._willSettleAt(new c(function (resolve$$1) {
  1484. return resolve$$1(entry);
  1485. }), i);
  1486. }
  1487. } else {
  1488. this._willSettleAt(resolve$$1(entry), i);
  1489. }
  1490. }
  1491. }, {
  1492. key: '_settledAt',
  1493. value: function _settledAt(state, i, value) {
  1494. var promise = this.promise;
  1495. if (promise._state === PENDING) {
  1496. this._remaining--;
  1497. if (state === REJECTED) {
  1498. reject(promise, value);
  1499. } else {
  1500. this._result[i] = value;
  1501. }
  1502. }
  1503. if (this._remaining === 0) {
  1504. fulfill(promise, this._result);
  1505. }
  1506. }
  1507. }, {
  1508. key: '_willSettleAt',
  1509. value: function _willSettleAt(promise, i) {
  1510. var enumerator = this;
  1511. subscribe(promise, undefined, function (value) {
  1512. return enumerator._settledAt(FULFILLED, i, value);
  1513. }, function (reason) {
  1514. return enumerator._settledAt(REJECTED, i, reason);
  1515. });
  1516. }
  1517. }]);
  1518. return Enumerator;
  1519. }();
  1520. /**
  1521. `Promise.all` accepts an array of promises, and returns a new promise which
  1522. is fulfilled with an array of fulfillment values for the passed promises, or
  1523. rejected with the reason of the first passed promise to be rejected. It casts all
  1524. elements of the passed iterable to promises as it runs this algorithm.
  1525. Example:
  1526. ```javascript
  1527. let promise1 = resolve(1);
  1528. let promise2 = resolve(2);
  1529. let promise3 = resolve(3);
  1530. let promises = [ promise1, promise2, promise3 ];
  1531. Promise.all(promises).then(function(array){
  1532. // The array here would be [ 1, 2, 3 ];
  1533. });
  1534. ```
  1535. If any of the `promises` given to `all` are rejected, the first promise
  1536. that is rejected will be given as an argument to the returned promises's
  1537. rejection handler. For example:
  1538. Example:
  1539. ```javascript
  1540. let promise1 = resolve(1);
  1541. let promise2 = reject(new Error("2"));
  1542. let promise3 = reject(new Error("3"));
  1543. let promises = [ promise1, promise2, promise3 ];
  1544. Promise.all(promises).then(function(array){
  1545. // Code here never runs because there are rejected promises!
  1546. }, function(error) {
  1547. // error.message === "2"
  1548. });
  1549. ```
  1550. @method all
  1551. @static
  1552. @param {Array} entries array of promises
  1553. @param {String} label optional string for labeling the promise.
  1554. Useful for tooling.
  1555. @return {Promise} promise that is fulfilled when all `promises` have been
  1556. fulfilled, or rejected if any of them become rejected.
  1557. @static
  1558. */
  1559. function all(entries) {
  1560. return new Enumerator(this, entries).promise;
  1561. }
  1562. /**
  1563. `Promise.race` returns a new promise which is settled in the same way as the
  1564. first passed promise to settle.
  1565. Example:
  1566. ```javascript
  1567. let promise1 = new Promise(function(resolve, reject){
  1568. setTimeout(function(){
  1569. resolve('promise 1');
  1570. }, 200);
  1571. });
  1572. let promise2 = new Promise(function(resolve, reject){
  1573. setTimeout(function(){
  1574. resolve('promise 2');
  1575. }, 100);
  1576. });
  1577. Promise.race([promise1, promise2]).then(function(result){
  1578. // result === 'promise 2' because it was resolved before promise1
  1579. // was resolved.
  1580. });
  1581. ```
  1582. `Promise.race` is deterministic in that only the state of the first
  1583. settled promise matters. For example, even if other promises given to the
  1584. `promises` array argument are resolved, but the first settled promise has
  1585. become rejected before the other promises became fulfilled, the returned
  1586. promise will become rejected:
  1587. ```javascript
  1588. let promise1 = new Promise(function(resolve, reject){
  1589. setTimeout(function(){
  1590. resolve('promise 1');
  1591. }, 200);
  1592. });
  1593. let promise2 = new Promise(function(resolve, reject){
  1594. setTimeout(function(){
  1595. reject(new Error('promise 2'));
  1596. }, 100);
  1597. });
  1598. Promise.race([promise1, promise2]).then(function(result){
  1599. // Code here never runs
  1600. }, function(reason){
  1601. // reason.message === 'promise 2' because promise 2 became rejected before
  1602. // promise 1 became fulfilled
  1603. });
  1604. ```
  1605. An example real-world use case is implementing timeouts:
  1606. ```javascript
  1607. Promise.race([ajax('foo.json'), timeout(5000)])
  1608. ```
  1609. @method race
  1610. @static
  1611. @param {Array} promises array of promises to observe
  1612. Useful for tooling.
  1613. @return {Promise} a promise which settles in the same way as the first passed
  1614. promise to settle.
  1615. */
  1616. function race(entries) {
  1617. /*jshint validthis:true */
  1618. var Constructor = this;
  1619. if (!isArray(entries)) {
  1620. return new Constructor(function (_, reject) {
  1621. return reject(new TypeError('You must pass an array to race.'));
  1622. });
  1623. } else {
  1624. return new Constructor(function (resolve, reject) {
  1625. var length = entries.length;
  1626. for (var i = 0; i < length; i++) {
  1627. Constructor.resolve(entries[i]).then(resolve, reject);
  1628. }
  1629. });
  1630. }
  1631. }
  1632. /**
  1633. `Promise.reject` returns a promise rejected with the passed `reason`.
  1634. It is shorthand for the following:
  1635. ```javascript
  1636. let promise = new Promise(function(resolve, reject){
  1637. reject(new Error('WHOOPS'));
  1638. });
  1639. promise.then(function(value){
  1640. // Code here doesn't run because the promise is rejected!
  1641. }, function(reason){
  1642. // reason.message === 'WHOOPS'
  1643. });
  1644. ```
  1645. Instead of writing the above, your code now simply becomes the following:
  1646. ```javascript
  1647. let promise = Promise.reject(new Error('WHOOPS'));
  1648. promise.then(function(value){
  1649. // Code here doesn't run because the promise is rejected!
  1650. }, function(reason){
  1651. // reason.message === 'WHOOPS'
  1652. });
  1653. ```
  1654. @method reject
  1655. @static
  1656. @param {Any} reason value that the returned promise will be rejected with.
  1657. Useful for tooling.
  1658. @return {Promise} a promise rejected with the given `reason`.
  1659. */
  1660. function reject$1(reason) {
  1661. /*jshint validthis:true */
  1662. var Constructor = this;
  1663. var promise = new Constructor(noop);
  1664. reject(promise, reason);
  1665. return promise;
  1666. }
  1667. function needsResolver() {
  1668. throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
  1669. }
  1670. function needsNew() {
  1671. throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
  1672. }
  1673. /**
  1674. Promise objects represent the eventual result of an asynchronous operation. The
  1675. primary way of interacting with a promise is through its `then` method, which
  1676. registers callbacks to receive either a promise's eventual value or the reason
  1677. why the promise cannot be fulfilled.
  1678. Terminology
  1679. -----------
  1680. - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
  1681. - `thenable` is an object or function that defines a `then` method.
  1682. - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
  1683. - `exception` is a value that is thrown using the throw statement.
  1684. - `reason` is a value that indicates why a promise was rejected.
  1685. - `settled` the final resting state of a promise, fulfilled or rejected.
  1686. A promise can be in one of three states: pending, fulfilled, or rejected.
  1687. Promises that are fulfilled have a fulfillment value and are in the fulfilled
  1688. state. Promises that are rejected have a rejection reason and are in the
  1689. rejected state. A fulfillment value is never a thenable.
  1690. Promises can also be said to *resolve* a value. If this value is also a
  1691. promise, then the original promise's settled state will match the value's
  1692. settled state. So a promise that *resolves* a promise that rejects will
  1693. itself reject, and a promise that *resolves* a promise that fulfills will
  1694. itself fulfill.
  1695. Basic Usage:
  1696. ------------
  1697. ```js
  1698. let promise = new Promise(function(resolve, reject) {
  1699. // on success
  1700. resolve(value);
  1701. // on failure
  1702. reject(reason);
  1703. });
  1704. promise.then(function(value) {
  1705. // on fulfillment
  1706. }, function(reason) {
  1707. // on rejection
  1708. });
  1709. ```
  1710. Advanced Usage:
  1711. ---------------
  1712. Promises shine when abstracting away asynchronous interactions such as
  1713. `XMLHttpRequest`s.
  1714. ```js
  1715. function getJSON(url) {
  1716. return new Promise(function(resolve, reject){
  1717. let xhr = new XMLHttpRequest();
  1718. xhr.open('GET', url);
  1719. xhr.onreadystatechange = handler;
  1720. xhr.responseType = 'json';
  1721. xhr.setRequestHeader('Accept', 'application/json');
  1722. xhr.send();
  1723. function handler() {
  1724. if (this.readyState === this.DONE) {
  1725. if (this.status === 200) {
  1726. resolve(this.response);
  1727. } else {
  1728. reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
  1729. }
  1730. }
  1731. };
  1732. });
  1733. }
  1734. getJSON('/posts.json').then(function(json) {
  1735. // on fulfillment
  1736. }, function(reason) {
  1737. // on rejection
  1738. });
  1739. ```
  1740. Unlike callbacks, promises are great composable primitives.
  1741. ```js
  1742. Promise.all([
  1743. getJSON('/posts'),
  1744. getJSON('/comments')
  1745. ]).then(function(values){
  1746. values[0] // => postsJSON
  1747. values[1] // => commentsJSON
  1748. return values;
  1749. });
  1750. ```
  1751. @class Promise
  1752. @param {Function} resolver
  1753. Useful for tooling.
  1754. @constructor
  1755. */
  1756. var Promise$2 = function () {
  1757. function Promise(resolver) {
  1758. classCallCheck(this, Promise);
  1759. this[PROMISE_ID] = nextId();
  1760. this._result = this._state = undefined;
  1761. this._subscribers = [];
  1762. if (noop !== resolver) {
  1763. typeof resolver !== 'function' && needsResolver();
  1764. this instanceof Promise ? initializePromise(this, resolver) : needsNew();
  1765. }
  1766. }
  1767. /**
  1768. The primary way of interacting with a promise is through its `then` method,
  1769. which registers callbacks to receive either a promise's eventual value or the
  1770. reason why the promise cannot be fulfilled.
  1771. ```js
  1772. findUser().then(function(user){
  1773. // user is available
  1774. }, function(reason){
  1775. // user is unavailable, and you are given the reason why
  1776. });
  1777. ```
  1778. Chaining
  1779. --------
  1780. The return value of `then` is itself a promise. This second, 'downstream'
  1781. promise is resolved with the return value of the first promise's fulfillment
  1782. or rejection handler, or rejected if the handler throws an exception.
  1783. ```js
  1784. findUser().then(function (user) {
  1785. return user.name;
  1786. }, function (reason) {
  1787. return 'default name';
  1788. }).then(function (userName) {
  1789. // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
  1790. // will be `'default name'`
  1791. });
  1792. findUser().then(function (user) {
  1793. throw new Error('Found user, but still unhappy');
  1794. }, function (reason) {
  1795. throw new Error('`findUser` rejected and we're unhappy');
  1796. }).then(function (value) {
  1797. // never reached
  1798. }, function (reason) {
  1799. // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
  1800. // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
  1801. });
  1802. ```
  1803. If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
  1804. ```js
  1805. findUser().then(function (user) {
  1806. throw new PedagogicalException('Upstream error');
  1807. }).then(function (value) {
  1808. // never reached
  1809. }).then(function (value) {
  1810. // never reached
  1811. }, function (reason) {
  1812. // The `PedgagocialException` is propagated all the way down to here
  1813. });
  1814. ```
  1815. Assimilation
  1816. ------------
  1817. Sometimes the value you want to propagate to a downstream promise can only be
  1818. retrieved asynchronously. This can be achieved by returning a promise in the
  1819. fulfillment or rejection handler. The downstream promise will then be pending
  1820. until the returned promise is settled. This is called *assimilation*.
  1821. ```js
  1822. findUser().then(function (user) {
  1823. return findCommentsByAuthor(user);
  1824. }).then(function (comments) {
  1825. // The user's comments are now available
  1826. });
  1827. ```
  1828. If the assimliated promise rejects, then the downstream promise will also reject.
  1829. ```js
  1830. findUser().then(function (user) {
  1831. return findCommentsByAuthor(user);
  1832. }).then(function (comments) {
  1833. // If `findCommentsByAuthor` fulfills, we'll have the value here
  1834. }, function (reason) {
  1835. // If `findCommentsByAuthor` rejects, we'll have the reason here
  1836. });
  1837. ```
  1838. Simple Example
  1839. --------------
  1840. Synchronous Example
  1841. ```javascript
  1842. let result;
  1843. try {
  1844. result = findResult();
  1845. // success
  1846. } catch(reason) {
  1847. // failure
  1848. }
  1849. ```
  1850. Errback Example
  1851. ```js
  1852. findResult(function(result, err){
  1853. if (err) {
  1854. // failure
  1855. } else {
  1856. // success
  1857. }
  1858. });
  1859. ```
  1860. Promise Example;
  1861. ```javascript
  1862. findResult().then(function(result){
  1863. // success
  1864. }, function(reason){
  1865. // failure
  1866. });
  1867. ```
  1868. Advanced Example
  1869. --------------
  1870. Synchronous Example
  1871. ```javascript
  1872. let author, books;
  1873. try {
  1874. author = findAuthor();
  1875. books = findBooksByAuthor(author);
  1876. // success
  1877. } catch(reason) {
  1878. // failure
  1879. }
  1880. ```
  1881. Errback Example
  1882. ```js
  1883. function foundBooks(books) {
  1884. }
  1885. function failure(reason) {
  1886. }
  1887. findAuthor(function(author, err){
  1888. if (err) {
  1889. failure(err);
  1890. // failure
  1891. } else {
  1892. try {
  1893. findBoooksByAuthor(author, function(books, err) {
  1894. if (err) {
  1895. failure(err);
  1896. } else {
  1897. try {
  1898. foundBooks(books);
  1899. } catch(reason) {
  1900. failure(reason);
  1901. }
  1902. }
  1903. });
  1904. } catch(error) {
  1905. failure(err);
  1906. }
  1907. // success
  1908. }
  1909. });
  1910. ```
  1911. Promise Example;
  1912. ```javascript
  1913. findAuthor().
  1914. then(findBooksByAuthor).
  1915. then(function(books){
  1916. // found books
  1917. }).catch(function(reason){
  1918. // something went wrong
  1919. });
  1920. ```
  1921. @method then
  1922. @param {Function} onFulfilled
  1923. @param {Function} onRejected
  1924. Useful for tooling.
  1925. @return {Promise}
  1926. */
  1927. /**
  1928. `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
  1929. as the catch block of a try/catch statement.
  1930. ```js
  1931. function findAuthor(){
  1932. throw new Error('couldn't find that author');
  1933. }
  1934. // synchronous
  1935. try {
  1936. findAuthor();
  1937. } catch(reason) {
  1938. // something went wrong
  1939. }
  1940. // async with promises
  1941. findAuthor().catch(function(reason){
  1942. // something went wrong
  1943. });
  1944. ```
  1945. @method catch
  1946. @param {Function} onRejection
  1947. Useful for tooling.
  1948. @return {Promise}
  1949. */
  1950. createClass(Promise, [{
  1951. key: 'catch',
  1952. value: function _catch(onRejection) {
  1953. return this.then(null, onRejection);
  1954. }
  1955. /**
  1956. `finally` will be invoked regardless of the promise's fate just as native
  1957. try/catch/finally behaves
  1958. Synchronous example:
  1959. ```js
  1960. findAuthor() {
  1961. if (Math.random() > 0.5) {
  1962. throw new Error();
  1963. }
  1964. return new Author();
  1965. }
  1966. try {
  1967. return findAuthor(); // succeed or fail
  1968. } catch(error) {
  1969. return findOtherAuther();
  1970. } finally {
  1971. // always runs
  1972. // doesn't affect the return value
  1973. }
  1974. ```
  1975. Asynchronous example:
  1976. ```js
  1977. findAuthor().catch(function(reason){
  1978. return findOtherAuther();
  1979. }).finally(function(){
  1980. // author was either found, or not
  1981. });
  1982. ```
  1983. @method finally
  1984. @param {Function} callback
  1985. @return {Promise}
  1986. */
  1987. }, {
  1988. key: 'finally',
  1989. value: function _finally(callback) {
  1990. var promise = this;
  1991. var constructor = promise.constructor;
  1992. if (isFunction(callback)) {
  1993. return promise.then(function (value) {
  1994. return constructor.resolve(callback()).then(function () {
  1995. return value;
  1996. });
  1997. }, function (reason) {
  1998. return constructor.resolve(callback()).then(function () {
  1999. throw reason;
  2000. });
  2001. });
  2002. }
  2003. return promise.then(callback, callback);
  2004. }
  2005. }]);
  2006. return Promise;
  2007. }();
  2008. Promise$2.prototype.then = then;
  2009. Promise$2.all = all;
  2010. Promise$2.race = race;
  2011. Promise$2.resolve = resolve$1;
  2012. Promise$2.reject = reject$1;
  2013. Promise$2._setScheduler = setScheduler;
  2014. Promise$2._setAsap = setAsap;
  2015. Promise$2._asap = asap;
  2016. /*global self*/
  2017. function polyfill() {
  2018. var local = void 0;
  2019. if (typeof global !== 'undefined') {
  2020. local = global;
  2021. } else if (typeof self !== 'undefined') {
  2022. local = self;
  2023. } else {
  2024. try {
  2025. local = Function('return this')();
  2026. } catch (e) {
  2027. throw new Error('polyfill failed because global object is unavailable in this environment');
  2028. }
  2029. }
  2030. var P = local.Promise;
  2031. if (P) {
  2032. var promiseToString = null;
  2033. try {
  2034. promiseToString = Object.prototype.toString.call(P.resolve());
  2035. } catch (e) {
  2036. // silently ignored
  2037. }
  2038. if (promiseToString === '[object Promise]' && !P.cast) {
  2039. return;
  2040. }
  2041. }
  2042. local.Promise = Promise$2;
  2043. }
  2044. // Strange compat..
  2045. Promise$2.polyfill = polyfill;
  2046. Promise$2.Promise = Promise$2;
  2047. var Promise$1 = typeof Promise !== "undefined" ? Promise : Promise$2;
  2048. // Register logging callbacks
  2049. function registerLoggingCallbacks(obj) {
  2050. var i,
  2051. l,
  2052. key,
  2053. callbackNames = ["begin", "done", "log", "testStart", "testDone", "moduleStart", "moduleDone"];
  2054. function registerLoggingCallback(key) {
  2055. var loggingCallback = function loggingCallback(callback) {
  2056. if (objectType(callback) !== "function") {
  2057. throw new Error("QUnit logging methods require a callback function as their first parameters.");
  2058. }
  2059. config.callbacks[key].push(callback);
  2060. };
  2061. return loggingCallback;
  2062. }
  2063. for (i = 0, l = callbackNames.length; i < l; i++) {
  2064. key = callbackNames[i];
  2065. // Initialize key collection of logging callback
  2066. if (objectType(config.callbacks[key]) === "undefined") {
  2067. config.callbacks[key] = [];
  2068. }
  2069. obj[key] = registerLoggingCallback(key);
  2070. }
  2071. }
  2072. function runLoggingCallbacks(key, args) {
  2073. var callbacks = config.callbacks[key];
  2074. // Handling 'log' callbacks separately. Unlike the other callbacks,
  2075. // the log callback is not controlled by the processing queue,
  2076. // but rather used by asserts. Hence to promisfy the 'log' callback
  2077. // would mean promisfying each step of a test
  2078. if (key === "log") {
  2079. callbacks.map(function (callback) {
  2080. return callback(args);
  2081. });
  2082. return;
  2083. }
  2084. // ensure that each callback is executed serially
  2085. return callbacks.reduce(function (promiseChain, callback) {
  2086. return promiseChain.then(function () {
  2087. return Promise$1.resolve(callback(args));
  2088. });
  2089. }, Promise$1.resolve([]));
  2090. }
  2091. // Doesn't support IE9, it will return undefined on these browsers
  2092. // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
  2093. var fileName = (sourceFromStacktrace(0) || "").replace(/(:\d+)+\)?/, "").replace(/.+\//, "");
  2094. function extractStacktrace(e, offset) {
  2095. offset = offset === undefined ? 4 : offset;
  2096. var stack, include, i;
  2097. if (e && e.stack) {
  2098. stack = e.stack.split("\n");
  2099. if (/^error$/i.test(stack[0])) {
  2100. stack.shift();
  2101. }
  2102. if (fileName) {
  2103. include = [];
  2104. for (i = offset; i < stack.length; i++) {
  2105. if (stack[i].indexOf(fileName) !== -1) {
  2106. break;
  2107. }
  2108. include.push(stack[i]);
  2109. }
  2110. if (include.length) {
  2111. return include.join("\n");
  2112. }
  2113. }
  2114. return stack[offset];
  2115. }
  2116. }
  2117. function sourceFromStacktrace(offset) {
  2118. var error = new Error();
  2119. // Support: Safari <=7 only, IE <=10 - 11 only
  2120. // Not all browsers generate the `stack` property for `new Error()`, see also #636
  2121. if (!error.stack) {
  2122. try {
  2123. throw error;
  2124. } catch (err) {
  2125. error = err;
  2126. }
  2127. }
  2128. return extractStacktrace(error, offset);
  2129. }
  2130. var priorityCount = 0;
  2131. var unitSampler = void 0;
  2132. // This is a queue of functions that are tasks within a single test.
  2133. // After tests are dequeued from config.queue they are expanded into
  2134. // a set of tasks in this queue.
  2135. var taskQueue = [];
  2136. /**
  2137. * Advances the taskQueue to the next task. If the taskQueue is empty,
  2138. * process the testQueue
  2139. */
  2140. function advance() {
  2141. advanceTaskQueue();
  2142. if (!taskQueue.length && !config.blocking && !config.current) {
  2143. advanceTestQueue();
  2144. }
  2145. }
  2146. /**
  2147. * Advances the taskQueue with an increased depth
  2148. */
  2149. function advanceTaskQueue() {
  2150. var start = now();
  2151. config.depth = (config.depth || 0) + 1;
  2152. processTaskQueue(start);
  2153. config.depth--;
  2154. }
  2155. /**
  2156. * Process the first task on the taskQueue as a promise.
  2157. * Each task is a function returned by https://github.com/qunitjs/qunit/blob/master/src/test.js#L381
  2158. */
  2159. function processTaskQueue(start) {
  2160. if (taskQueue.length && !config.blocking) {
  2161. var elapsedTime = now() - start;
  2162. if (!defined.setTimeout || config.updateRate <= 0 || elapsedTime < config.updateRate) {
  2163. var task = taskQueue.shift();
  2164. Promise$1.resolve(task()).then(function () {
  2165. if (!taskQueue.length) {
  2166. advance();
  2167. } else {
  2168. processTaskQueue(start);
  2169. }
  2170. });
  2171. } else {
  2172. setTimeout$1(advance);
  2173. }
  2174. }
  2175. }
  2176. /**
  2177. * Advance the testQueue to the next test to process. Call done() if testQueue completes.
  2178. */
  2179. function advanceTestQueue() {
  2180. if (!config.blocking && !config.queue.length && config.depth === 0) {
  2181. done();
  2182. return;
  2183. }
  2184. var testTasks = config.queue.shift();
  2185. addToTaskQueue(testTasks());
  2186. if (priorityCount > 0) {
  2187. priorityCount--;
  2188. }
  2189. advance();
  2190. }
  2191. /**
  2192. * Enqueue the tasks for a test into the task queue.
  2193. * @param {Array} tasksArray
  2194. */
  2195. function addToTaskQueue(tasksArray) {
  2196. taskQueue.push.apply(taskQueue, toConsumableArray(tasksArray));
  2197. }
  2198. /**
  2199. * Return the number of tasks remaining in the task queue to be processed.
  2200. * @return {Number}
  2201. */
  2202. function taskQueueLength() {
  2203. return taskQueue.length;
  2204. }
  2205. /**
  2206. * Adds a test to the TestQueue for execution.
  2207. * @param {Function} testTasksFunc
  2208. * @param {Boolean} prioritize
  2209. * @param {String} seed
  2210. */
  2211. function addToTestQueue(testTasksFunc, prioritize, seed) {
  2212. if (prioritize) {
  2213. config.queue.splice(priorityCount++, 0, testTasksFunc);
  2214. } else if (seed) {
  2215. if (!unitSampler) {
  2216. unitSampler = unitSamplerGenerator(seed);
  2217. }
  2218. // Insert into a random position after all prioritized items
  2219. var index = Math.floor(unitSampler() * (config.queue.length - priorityCount + 1));
  2220. config.queue.splice(priorityCount + index, 0, testTasksFunc);
  2221. } else {
  2222. config.queue.push(testTasksFunc);
  2223. }
  2224. }
  2225. /**
  2226. * Creates a seeded "sample" generator which is used for randomizing tests.
  2227. */
  2228. function unitSamplerGenerator(seed) {
  2229. // 32-bit xorshift, requires only a nonzero seed
  2230. // http://excamera.com/sphinx/article-xorshift.html
  2231. var sample = parseInt(generateHash(seed), 16) || -1;
  2232. return function () {
  2233. sample ^= sample << 13;
  2234. sample ^= sample >>> 17;
  2235. sample ^= sample << 5;
  2236. // ECMAScript has no unsigned number type
  2237. if (sample < 0) {
  2238. sample += 0x100000000;
  2239. }
  2240. return sample / 0x100000000;
  2241. };
  2242. }
  2243. /**
  2244. * This function is called when the ProcessingQueue is done processing all
  2245. * items. It handles emitting the final run events.
  2246. */
  2247. function done() {
  2248. var storage = config.storage;
  2249. ProcessingQueue.finished = true;
  2250. var runtime = now() - config.started;
  2251. var passed = config.stats.all - config.stats.bad;
  2252. if (config.stats.all === 0) {
  2253. if (config.filter && config.filter.length) {
  2254. throw new Error("No tests matched the filter \"" + config.filter + "\".");
  2255. }
  2256. if (config.module && config.module.length) {
  2257. throw new Error("No tests matched the module \"" + config.module + "\".");
  2258. }
  2259. if (config.moduleId && config.moduleId.length) {
  2260. throw new Error("No tests matched the moduleId \"" + config.moduleId + "\".");
  2261. }
  2262. if (config.testId && config.testId.length) {
  2263. throw new Error("No tests matched the testId \"" + config.testId + "\".");
  2264. }
  2265. throw new Error("No tests were run.");
  2266. }
  2267. emit("runEnd", globalSuite.end(true));
  2268. runLoggingCallbacks("done", {
  2269. passed: passed,
  2270. failed: config.stats.bad,
  2271. total: config.stats.all,
  2272. runtime: runtime
  2273. }).then(function () {
  2274. // Clear own storage items if all tests passed
  2275. if (storage && config.stats.bad === 0) {
  2276. for (var i = storage.length - 1; i >= 0; i--) {
  2277. var key = storage.key(i);
  2278. if (key.indexOf("qunit-test-") === 0) {
  2279. storage.removeItem(key);
  2280. }
  2281. }
  2282. }
  2283. });
  2284. }
  2285. var ProcessingQueue = {
  2286. finished: false,
  2287. add: addToTestQueue,
  2288. advance: advance,
  2289. taskCount: taskQueueLength
  2290. };
  2291. var TestReport = function () {
  2292. function TestReport(name, suite, options) {
  2293. classCallCheck(this, TestReport);
  2294. this.name = name;
  2295. this.suiteName = suite.name;
  2296. this.fullName = suite.fullName.concat(name);
  2297. this.runtime = 0;
  2298. this.assertions = [];
  2299. this.skipped = !!options.skip;
  2300. this.todo = !!options.todo;
  2301. this.valid = options.valid;
  2302. this._startTime = 0;
  2303. this._endTime = 0;
  2304. suite.pushTest(this);
  2305. }
  2306. createClass(TestReport, [{
  2307. key: "start",
  2308. value: function start(recordTime) {
  2309. if (recordTime) {
  2310. this._startTime = performanceNow();
  2311. if (performance) {
  2312. performance.mark("qunit_test_start");
  2313. }
  2314. }
  2315. return {
  2316. name: this.name,
  2317. suiteName: this.suiteName,
  2318. fullName: this.fullName.slice()
  2319. };
  2320. }
  2321. }, {
  2322. key: "end",
  2323. value: function end(recordTime) {
  2324. if (recordTime) {
  2325. this._endTime = performanceNow();
  2326. if (performance) {
  2327. performance.mark("qunit_test_end");
  2328. var testName = this.fullName.join(" – ");
  2329. measure("QUnit Test: " + testName, "qunit_test_start", "qunit_test_end");
  2330. }
  2331. }
  2332. return extend(this.start(), {
  2333. runtime: this.getRuntime(),
  2334. status: this.getStatus(),
  2335. errors: this.getFailedAssertions(),
  2336. assertions: this.getAssertions()
  2337. });
  2338. }
  2339. }, {
  2340. key: "pushAssertion",
  2341. value: function pushAssertion(assertion) {
  2342. this.assertions.push(assertion);
  2343. }
  2344. }, {
  2345. key: "getRuntime",
  2346. value: function getRuntime() {
  2347. return this._endTime - this._startTime;
  2348. }
  2349. }, {
  2350. key: "getStatus",
  2351. value: function getStatus() {
  2352. if (this.skipped) {
  2353. return "skipped";
  2354. }
  2355. var testPassed = this.getFailedAssertions().length > 0 ? this.todo : !this.todo;
  2356. if (!testPassed) {
  2357. return "failed";
  2358. } else if (this.todo) {
  2359. return "todo";
  2360. } else {
  2361. return "passed";
  2362. }
  2363. }
  2364. }, {
  2365. key: "getFailedAssertions",
  2366. value: function getFailedAssertions() {
  2367. return this.assertions.filter(function (assertion) {
  2368. return !assertion.passed;
  2369. });
  2370. }
  2371. }, {
  2372. key: "getAssertions",
  2373. value: function getAssertions() {
  2374. return this.assertions.slice();
  2375. }
  2376. // Remove actual and expected values from assertions. This is to prevent
  2377. // leaking memory throughout a test suite.
  2378. }, {
  2379. key: "slimAssertions",
  2380. value: function slimAssertions() {
  2381. this.assertions = this.assertions.map(function (assertion) {
  2382. delete assertion.actual;
  2383. delete assertion.expected;
  2384. return assertion;
  2385. });
  2386. }
  2387. }]);
  2388. return TestReport;
  2389. }();
  2390. var focused$1 = false;
  2391. function Test(settings) {
  2392. var i, l;
  2393. ++Test.count;
  2394. this.expected = null;
  2395. this.assertions = [];
  2396. this.semaphore = 0;
  2397. this.module = config.currentModule;
  2398. this.stack = sourceFromStacktrace(3);
  2399. this.steps = [];
  2400. this.timeout = undefined;
  2401. // If a module is skipped, all its tests and the tests of the child suites
  2402. // should be treated as skipped even if they are defined as `only` or `todo`.
  2403. // As for `todo` module, all its tests will be treated as `todo` except for
  2404. // tests defined as `skip` which will be left intact.
  2405. //
  2406. // So, if a test is defined as `todo` and is inside a skipped module, we should
  2407. // then treat that test as if was defined as `skip`.
  2408. if (this.module.skip) {
  2409. settings.skip = true;
  2410. settings.todo = false;
  2411. // Skipped tests should be left intact
  2412. } else if (this.module.todo && !settings.skip) {
  2413. settings.todo = true;
  2414. }
  2415. extend(this, settings);
  2416. this.testReport = new TestReport(settings.testName, this.module.suiteReport, {
  2417. todo: settings.todo,
  2418. skip: settings.skip,
  2419. valid: this.valid()
  2420. });
  2421. // Register unique strings
  2422. for (i = 0, l = this.module.tests; i < l.length; i++) {
  2423. if (this.module.tests[i].name === this.testName) {
  2424. this.testName += " ";
  2425. }
  2426. }
  2427. this.testId = generateHash(this.module.name, this.testName);
  2428. this.module.tests.push({
  2429. name: this.testName,
  2430. testId: this.testId,
  2431. skip: !!settings.skip
  2432. });
  2433. if (settings.skip) {
  2434. // Skipped tests will fully ignore any sent callback
  2435. this.callback = function () {};
  2436. this.async = false;
  2437. this.expected = 0;
  2438. } else {
  2439. if (typeof this.callback !== "function") {
  2440. var method = this.todo ? "todo" : "test";
  2441. // eslint-disable-next-line max-len
  2442. throw new TypeError("You must provide a function as a test callback to QUnit." + method + "(\"" + settings.testName + "\")");
  2443. }
  2444. this.assert = new Assert(this);
  2445. }
  2446. }
  2447. Test.count = 0;
  2448. function getNotStartedModules(startModule) {
  2449. var module = startModule,
  2450. modules = [];
  2451. while (module && module.testsRun === 0) {
  2452. modules.push(module);
  2453. module = module.parentModule;
  2454. }
  2455. // The above push modules from the child to the parent
  2456. // return a reversed order with the top being the top most parent module
  2457. return modules.reverse();
  2458. }
  2459. Test.prototype = {
  2460. before: function before() {
  2461. var _this = this;
  2462. var module = this.module,
  2463. notStartedModules = getNotStartedModules(module);
  2464. // ensure the callbacks are executed serially for each module
  2465. var callbackPromises = notStartedModules.reduce(function (promiseChain, startModule) {
  2466. return promiseChain.then(function () {
  2467. startModule.stats = { all: 0, bad: 0, started: now() };
  2468. emit("suiteStart", startModule.suiteReport.start(true));
  2469. return runLoggingCallbacks("moduleStart", {
  2470. name: startModule.name,
  2471. tests: startModule.tests
  2472. });
  2473. });
  2474. }, Promise$1.resolve([]));
  2475. return callbackPromises.then(function () {
  2476. config.current = _this;
  2477. _this.testEnvironment = extend({}, module.testEnvironment);
  2478. _this.started = now();
  2479. emit("testStart", _this.testReport.start(true));
  2480. return runLoggingCallbacks("testStart", {
  2481. name: _this.testName,
  2482. module: module.name,
  2483. testId: _this.testId,
  2484. previousFailure: _this.previousFailure
  2485. }).then(function () {
  2486. if (!config.pollution) {
  2487. saveGlobal();
  2488. }
  2489. });
  2490. });
  2491. },
  2492. run: function run() {
  2493. var promise;
  2494. config.current = this;
  2495. this.callbackStarted = now();
  2496. if (config.notrycatch) {
  2497. runTest(this);
  2498. return;
  2499. }
  2500. try {
  2501. runTest(this);
  2502. } catch (e) {
  2503. this.pushFailure("Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + (e.message || e), extractStacktrace(e, 0));
  2504. // Else next test will carry the responsibility
  2505. saveGlobal();
  2506. // Restart the tests if they're blocking
  2507. if (config.blocking) {
  2508. internalRecover(this);
  2509. }
  2510. }
  2511. function runTest(test) {
  2512. promise = test.callback.call(test.testEnvironment, test.assert);
  2513. test.resolvePromise(promise);
  2514. // If the test has a "lock" on it, but the timeout is 0, then we push a
  2515. // failure as the test should be synchronous.
  2516. if (test.timeout === 0 && test.semaphore !== 0) {
  2517. pushFailure("Test did not finish synchronously even though assert.timeout( 0 ) was used.", sourceFromStacktrace(2));
  2518. }
  2519. }
  2520. },
  2521. after: function after() {
  2522. checkPollution();
  2523. },
  2524. queueHook: function queueHook(hook, hookName, hookOwner) {
  2525. var _this2 = this;
  2526. var callHook = function callHook() {
  2527. var promise = hook.call(_this2.testEnvironment, _this2.assert);
  2528. _this2.resolvePromise(promise, hookName);
  2529. };
  2530. var runHook = function runHook() {
  2531. if (hookName === "before") {
  2532. if (hookOwner.unskippedTestsRun !== 0) {
  2533. return;
  2534. }
  2535. _this2.preserveEnvironment = true;
  2536. }
  2537. // The 'after' hook should only execute when there are not tests left and
  2538. // when the 'after' and 'finish' tasks are the only tasks left to process
  2539. if (hookName === "after" && hookOwner.unskippedTestsRun !== numberOfUnskippedTests(hookOwner) - 1 && (config.queue.length > 0 || ProcessingQueue.taskCount() > 2)) {
  2540. return;
  2541. }
  2542. config.current = _this2;
  2543. if (config.notrycatch) {
  2544. callHook();
  2545. return;
  2546. }
  2547. try {
  2548. callHook();
  2549. } catch (error) {
  2550. _this2.pushFailure(hookName + " failed on " + _this2.testName + ": " + (error.message || error), extractStacktrace(error, 0));
  2551. }
  2552. };
  2553. return runHook;
  2554. },
  2555. // Currently only used for module level hooks, can be used to add global level ones
  2556. hooks: function hooks(handler) {
  2557. var hooks = [];
  2558. function processHooks(test, module) {
  2559. if (module.parentModule) {
  2560. processHooks(test, module.parentModule);
  2561. }
  2562. if (module.hooks[handler].length) {
  2563. for (var i = 0; i < module.hooks[handler].length; i++) {
  2564. hooks.push(test.queueHook(module.hooks[handler][i], handler, module));
  2565. }
  2566. }
  2567. }
  2568. // Hooks are ignored on skipped tests
  2569. if (!this.skip) {
  2570. processHooks(this, this.module);
  2571. }
  2572. return hooks;
  2573. },
  2574. finish: function finish() {
  2575. config.current = this;
  2576. // Release the test callback to ensure that anything referenced has been
  2577. // released to be garbage collected.
  2578. this.callback = undefined;
  2579. if (this.steps.length) {
  2580. var stepsList = this.steps.join(", ");
  2581. this.pushFailure("Expected assert.verifySteps() to be called before end of test " + ("after using assert.step(). Unverified steps: " + stepsList), this.stack);
  2582. }
  2583. if (config.requireExpects && this.expected === null) {
  2584. this.pushFailure("Expected number of assertions to be defined, but expect() was " + "not called.", this.stack);
  2585. } else if (this.expected !== null && this.expected !== this.assertions.length) {
  2586. this.pushFailure("Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack);
  2587. } else if (this.expected === null && !this.assertions.length) {
  2588. this.pushFailure("Expected at least one assertion, but none were run - call " + "expect(0) to accept zero assertions.", this.stack);
  2589. }
  2590. var i,
  2591. module = this.module,
  2592. moduleName = module.name,
  2593. testName = this.testName,
  2594. skipped = !!this.skip,
  2595. todo = !!this.todo,
  2596. bad = 0,
  2597. storage = config.storage;
  2598. this.runtime = now() - this.started;
  2599. config.stats.all += this.assertions.length;
  2600. module.stats.all += this.assertions.length;
  2601. for (i = 0; i < this.assertions.length; i++) {
  2602. if (!this.assertions[i].result) {
  2603. bad++;
  2604. config.stats.bad++;
  2605. module.stats.bad++;
  2606. }
  2607. }
  2608. notifyTestsRan(module, skipped);
  2609. // Store result when possible
  2610. if (storage) {
  2611. if (bad) {
  2612. storage.setItem("qunit-test-" + moduleName + "-" + testName, bad);
  2613. } else {
  2614. storage.removeItem("qunit-test-" + moduleName + "-" + testName);
  2615. }
  2616. }
  2617. // After emitting the js-reporters event we cleanup the assertion data to
  2618. // avoid leaking it. It is not used by the legacy testDone callbacks.
  2619. emit("testEnd", this.testReport.end(true));
  2620. this.testReport.slimAssertions();
  2621. return runLoggingCallbacks("testDone", {
  2622. name: testName,
  2623. module: moduleName,
  2624. skipped: skipped,
  2625. todo: todo,
  2626. failed: bad,
  2627. passed: this.assertions.length - bad,
  2628. total: this.assertions.length,
  2629. runtime: skipped ? 0 : this.runtime,
  2630. // HTML Reporter use
  2631. assertions: this.assertions,
  2632. testId: this.testId,
  2633. // Source of Test
  2634. source: this.stack
  2635. }).then(function () {
  2636. if (module.testsRun === numberOfTests(module)) {
  2637. var completedModules = [module];
  2638. // Check if the parent modules, iteratively, are done. If that the case,
  2639. // we emit the `suiteEnd` event and trigger `moduleDone` callback.
  2640. var parent = module.parentModule;
  2641. while (parent && parent.testsRun === numberOfTests(parent)) {
  2642. completedModules.push(parent);
  2643. parent = parent.parentModule;
  2644. }
  2645. return completedModules.reduce(function (promiseChain, completedModule) {
  2646. return promiseChain.then(function () {
  2647. return logSuiteEnd(completedModule);
  2648. });
  2649. }, Promise$1.resolve([]));
  2650. }
  2651. }).then(function () {
  2652. config.current = undefined;
  2653. });
  2654. function logSuiteEnd(module) {
  2655. // Reset `module.hooks` to ensure that anything referenced in these hooks
  2656. // has been released to be garbage collected.
  2657. module.hooks = {};
  2658. emit("suiteEnd", module.suiteReport.end(true));
  2659. return runLoggingCallbacks("moduleDone", {
  2660. name: module.name,
  2661. tests: module.tests,
  2662. failed: module.stats.bad,
  2663. passed: module.stats.all - module.stats.bad,
  2664. total: module.stats.all,
  2665. runtime: now() - module.stats.started
  2666. });
  2667. }
  2668. },
  2669. preserveTestEnvironment: function preserveTestEnvironment() {
  2670. if (this.preserveEnvironment) {
  2671. this.module.testEnvironment = this.testEnvironment;
  2672. this.testEnvironment = extend({}, this.module.testEnvironment);
  2673. }
  2674. },
  2675. queue: function queue() {
  2676. var test = this;
  2677. if (!this.valid()) {
  2678. return;
  2679. }
  2680. function runTest() {
  2681. return [function () {
  2682. return test.before();
  2683. }].concat(toConsumableArray(test.hooks("before")), [function () {
  2684. test.preserveTestEnvironment();
  2685. }], toConsumableArray(test.hooks("beforeEach")), [function () {
  2686. test.run();
  2687. }], toConsumableArray(test.hooks("afterEach").reverse()), toConsumableArray(test.hooks("after").reverse()), [function () {
  2688. test.after();
  2689. }, function () {
  2690. return test.finish();
  2691. }]);
  2692. }
  2693. var previousFailCount = config.storage && +config.storage.getItem("qunit-test-" + this.module.name + "-" + this.testName);
  2694. // Prioritize previously failed tests, detected from storage
  2695. var prioritize = config.reorder && !!previousFailCount;
  2696. this.previousFailure = !!previousFailCount;
  2697. ProcessingQueue.add(runTest, prioritize, config.seed);
  2698. // If the queue has already finished, we manually process the new test
  2699. if (ProcessingQueue.finished) {
  2700. ProcessingQueue.advance();
  2701. }
  2702. },
  2703. pushResult: function pushResult(resultInfo) {
  2704. if (this !== config.current) {
  2705. throw new Error("Assertion occurred after test had finished.");
  2706. }
  2707. // Destructure of resultInfo = { result, actual, expected, message, negative }
  2708. var source,
  2709. details = {
  2710. module: this.module.name,
  2711. name: this.testName,
  2712. result: resultInfo.result,
  2713. message: resultInfo.message,
  2714. actual: resultInfo.actual,
  2715. testId: this.testId,
  2716. negative: resultInfo.negative || false,
  2717. runtime: now() - this.started,
  2718. todo: !!this.todo
  2719. };
  2720. if (hasOwn.call(resultInfo, "expected")) {
  2721. details.expected = resultInfo.expected;
  2722. }
  2723. if (!resultInfo.result) {
  2724. source = resultInfo.source || sourceFromStacktrace();
  2725. if (source) {
  2726. details.source = source;
  2727. }
  2728. }
  2729. this.logAssertion(details);
  2730. this.assertions.push({
  2731. result: !!resultInfo.result,
  2732. message: resultInfo.message
  2733. });
  2734. },
  2735. pushFailure: function pushFailure(message, source, actual) {
  2736. if (!(this instanceof Test)) {
  2737. throw new Error("pushFailure() assertion outside test context, was " + sourceFromStacktrace(2));
  2738. }
  2739. this.pushResult({
  2740. result: false,
  2741. message: message || "error",
  2742. actual: actual || null,
  2743. source: source
  2744. });
  2745. },
  2746. /**
  2747. * Log assertion details using both the old QUnit.log interface and
  2748. * QUnit.on( "assertion" ) interface.
  2749. *
  2750. * @private
  2751. */
  2752. logAssertion: function logAssertion(details) {
  2753. runLoggingCallbacks("log", details);
  2754. var assertion = {
  2755. passed: details.result,
  2756. actual: details.actual,
  2757. expected: details.expected,
  2758. message: details.message,
  2759. stack: details.source,
  2760. todo: details.todo
  2761. };
  2762. this.testReport.pushAssertion(assertion);
  2763. emit("assertion", assertion);
  2764. },
  2765. resolvePromise: function resolvePromise(promise, phase) {
  2766. var then,
  2767. resume,
  2768. message,
  2769. test = this;
  2770. if (promise != null) {
  2771. then = promise.then;
  2772. if (objectType(then) === "function") {
  2773. resume = internalStop(test);
  2774. if (config.notrycatch) {
  2775. then.call(promise, function () {
  2776. resume();
  2777. });
  2778. } else {
  2779. then.call(promise, function () {
  2780. resume();
  2781. }, function (error) {
  2782. message = "Promise rejected " + (!phase ? "during" : phase.replace(/Each$/, "")) + " \"" + test.testName + "\": " + (error && error.message || error);
  2783. test.pushFailure(message, extractStacktrace(error, 0));
  2784. // Else next test will carry the responsibility
  2785. saveGlobal();
  2786. // Unblock
  2787. internalRecover(test);
  2788. });
  2789. }
  2790. }
  2791. }
  2792. },
  2793. valid: function valid() {
  2794. var filter = config.filter,
  2795. regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec(filter),
  2796. module = config.module && config.module.toLowerCase(),
  2797. fullName = this.module.name + ": " + this.testName;
  2798. function moduleChainNameMatch(testModule) {
  2799. var testModuleName = testModule.name ? testModule.name.toLowerCase() : null;
  2800. if (testModuleName === module) {
  2801. return true;
  2802. } else if (testModule.parentModule) {
  2803. return moduleChainNameMatch(testModule.parentModule);
  2804. } else {
  2805. return false;
  2806. }
  2807. }
  2808. function moduleChainIdMatch(testModule) {
  2809. return inArray(testModule.moduleId, config.moduleId) || testModule.parentModule && moduleChainIdMatch(testModule.parentModule);
  2810. }
  2811. // Internally-generated tests are always valid
  2812. if (this.callback && this.callback.validTest) {
  2813. return true;
  2814. }
  2815. if (config.moduleId && config.moduleId.length > 0 && !moduleChainIdMatch(this.module)) {
  2816. return false;
  2817. }
  2818. if (config.testId && config.testId.length > 0 && !inArray(this.testId, config.testId)) {
  2819. return false;
  2820. }
  2821. if (module && !moduleChainNameMatch(this.module)) {
  2822. return false;
  2823. }
  2824. if (!filter) {
  2825. return true;
  2826. }
  2827. return regexFilter ? this.regexFilter(!!regexFilter[1], regexFilter[2], regexFilter[3], fullName) : this.stringFilter(filter, fullName);
  2828. },
  2829. regexFilter: function regexFilter(exclude, pattern, flags, fullName) {
  2830. var regex = new RegExp(pattern, flags);
  2831. var match = regex.test(fullName);
  2832. return match !== exclude;
  2833. },
  2834. stringFilter: function stringFilter(filter, fullName) {
  2835. filter = filter.toLowerCase();
  2836. fullName = fullName.toLowerCase();
  2837. var include = filter.charAt(0) !== "!";
  2838. if (!include) {
  2839. filter = filter.slice(1);
  2840. }
  2841. // If the filter matches, we need to honour include
  2842. if (fullName.indexOf(filter) !== -1) {
  2843. return include;
  2844. }
  2845. // Otherwise, do the opposite
  2846. return !include;
  2847. }
  2848. };
  2849. function pushFailure() {
  2850. if (!config.current) {
  2851. throw new Error("pushFailure() assertion outside test context, in " + sourceFromStacktrace(2));
  2852. }
  2853. // Gets current test obj
  2854. var currentTest = config.current;
  2855. return currentTest.pushFailure.apply(currentTest, arguments);
  2856. }
  2857. function saveGlobal() {
  2858. config.pollution = [];
  2859. if (config.noglobals) {
  2860. for (var key in global$1) {
  2861. if (hasOwn.call(global$1, key)) {
  2862. // In Opera sometimes DOM element ids show up here, ignore them
  2863. if (/^qunit-test-output/.test(key)) {
  2864. continue;
  2865. }
  2866. config.pollution.push(key);
  2867. }
  2868. }
  2869. }
  2870. }
  2871. function checkPollution() {
  2872. var newGlobals,
  2873. deletedGlobals,
  2874. old = config.pollution;
  2875. saveGlobal();
  2876. newGlobals = diff(config.pollution, old);
  2877. if (newGlobals.length > 0) {
  2878. pushFailure("Introduced global variable(s): " + newGlobals.join(", "));
  2879. }
  2880. deletedGlobals = diff(old, config.pollution);
  2881. if (deletedGlobals.length > 0) {
  2882. pushFailure("Deleted global variable(s): " + deletedGlobals.join(", "));
  2883. }
  2884. }
  2885. // Will be exposed as QUnit.test
  2886. function test(testName, callback) {
  2887. if (focused$1) {
  2888. return;
  2889. }
  2890. var newTest = new Test({
  2891. testName: testName,
  2892. callback: callback
  2893. });
  2894. newTest.queue();
  2895. }
  2896. function todo(testName, callback) {
  2897. if (focused$1) {
  2898. return;
  2899. }
  2900. var newTest = new Test({
  2901. testName: testName,
  2902. callback: callback,
  2903. todo: true
  2904. });
  2905. newTest.queue();
  2906. }
  2907. // Will be exposed as QUnit.skip
  2908. function skip(testName) {
  2909. if (focused$1) {
  2910. return;
  2911. }
  2912. var test = new Test({
  2913. testName: testName,
  2914. skip: true
  2915. });
  2916. test.queue();
  2917. }
  2918. // Will be exposed as QUnit.only
  2919. function only(testName, callback) {
  2920. if (focused$1) {
  2921. return;
  2922. }
  2923. config.queue.length = 0;
  2924. focused$1 = true;
  2925. var newTest = new Test({
  2926. testName: testName,
  2927. callback: callback
  2928. });
  2929. newTest.queue();
  2930. }
  2931. // Put a hold on processing and return a function that will release it.
  2932. function internalStop(test) {
  2933. var released = false;
  2934. test.semaphore += 1;
  2935. config.blocking = true;
  2936. // Set a recovery timeout, if so configured.
  2937. if (defined.setTimeout) {
  2938. var timeoutDuration = void 0;
  2939. if (typeof test.timeout === "number") {
  2940. timeoutDuration = test.timeout;
  2941. } else if (typeof config.testTimeout === "number") {
  2942. timeoutDuration = config.testTimeout;
  2943. }
  2944. if (typeof timeoutDuration === "number" && timeoutDuration > 0) {
  2945. clearTimeout(config.timeout);
  2946. config.timeout = setTimeout$1(function () {
  2947. pushFailure("Test took longer than " + timeoutDuration + "ms; test timed out.", sourceFromStacktrace(2));
  2948. released = true;
  2949. internalRecover(test);
  2950. }, timeoutDuration);
  2951. }
  2952. }
  2953. return function resume() {
  2954. if (released) {
  2955. return;
  2956. }
  2957. released = true;
  2958. test.semaphore -= 1;
  2959. internalStart(test);
  2960. };
  2961. }
  2962. // Forcefully release all processing holds.
  2963. function internalRecover(test) {
  2964. test.semaphore = 0;
  2965. internalStart(test);
  2966. }
  2967. // Release a processing hold, scheduling a resumption attempt if no holds remain.
  2968. function internalStart(test) {
  2969. // If semaphore is non-numeric, throw error
  2970. if (isNaN(test.semaphore)) {
  2971. test.semaphore = 0;
  2972. pushFailure("Invalid value on test.semaphore", sourceFromStacktrace(2));
  2973. return;
  2974. }
  2975. // Don't start until equal number of stop-calls
  2976. if (test.semaphore > 0) {
  2977. return;
  2978. }
  2979. // Throw an Error if start is called more often than stop
  2980. if (test.semaphore < 0) {
  2981. test.semaphore = 0;
  2982. pushFailure("Tried to restart test while already started (test's semaphore was 0 already)", sourceFromStacktrace(2));
  2983. return;
  2984. }
  2985. // Add a slight delay to allow more assertions etc.
  2986. if (defined.setTimeout) {
  2987. if (config.timeout) {
  2988. clearTimeout(config.timeout);
  2989. }
  2990. config.timeout = setTimeout$1(function () {
  2991. if (test.semaphore > 0) {
  2992. return;
  2993. }
  2994. if (config.timeout) {
  2995. clearTimeout(config.timeout);
  2996. }
  2997. begin();
  2998. });
  2999. } else {
  3000. begin();
  3001. }
  3002. }
  3003. function collectTests(module) {
  3004. var tests = [].concat(module.tests);
  3005. var modules = [].concat(toConsumableArray(module.childModules));
  3006. // Do a breadth-first traversal of the child modules
  3007. while (modules.length) {
  3008. var nextModule = modules.shift();
  3009. tests.push.apply(tests, nextModule.tests);
  3010. modules.push.apply(modules, toConsumableArray(nextModule.childModules));
  3011. }
  3012. return tests;
  3013. }
  3014. function numberOfTests(module) {
  3015. return collectTests(module).length;
  3016. }
  3017. function numberOfUnskippedTests(module) {
  3018. return collectTests(module).filter(function (test) {
  3019. return !test.skip;
  3020. }).length;
  3021. }
  3022. function notifyTestsRan(module, skipped) {
  3023. module.testsRun++;
  3024. if (!skipped) {
  3025. module.unskippedTestsRun++;
  3026. }
  3027. while (module = module.parentModule) {
  3028. module.testsRun++;
  3029. if (!skipped) {
  3030. module.unskippedTestsRun++;
  3031. }
  3032. }
  3033. }
  3034. var Assert = function () {
  3035. function Assert(testContext) {
  3036. classCallCheck(this, Assert);
  3037. this.test = testContext;
  3038. }
  3039. // Assert helpers
  3040. createClass(Assert, [{
  3041. key: "timeout",
  3042. value: function timeout(duration) {
  3043. if (typeof duration !== "number") {
  3044. throw new Error("You must pass a number as the duration to assert.timeout");
  3045. }
  3046. this.test.timeout = duration;
  3047. }
  3048. // Documents a "step", which is a string value, in a test as a passing assertion
  3049. }, {
  3050. key: "step",
  3051. value: function step(message) {
  3052. var assertionMessage = message;
  3053. var result = !!message;
  3054. this.test.steps.push(message);
  3055. if (objectType(message) === "undefined" || message === "") {
  3056. assertionMessage = "You must provide a message to assert.step";
  3057. } else if (objectType(message) !== "string") {
  3058. assertionMessage = "You must provide a string value to assert.step";
  3059. result = false;
  3060. }
  3061. this.pushResult({
  3062. result: result,
  3063. message: assertionMessage
  3064. });
  3065. }
  3066. // Verifies the steps in a test match a given array of string values
  3067. }, {
  3068. key: "verifySteps",
  3069. value: function verifySteps(steps, message) {
  3070. // Since the steps array is just string values, we can clone with slice
  3071. var actualStepsClone = this.test.steps.slice();
  3072. this.deepEqual(actualStepsClone, steps, message);
  3073. this.test.steps.length = 0;
  3074. }
  3075. // Specify the number of expected assertions to guarantee that failed test
  3076. // (no assertions are run at all) don't slip through.
  3077. }, {
  3078. key: "expect",
  3079. value: function expect(asserts) {
  3080. if (arguments.length === 1) {
  3081. this.test.expected = asserts;
  3082. } else {
  3083. return this.test.expected;
  3084. }
  3085. }
  3086. // Put a hold on processing and return a function that will release it a maximum of once.
  3087. }, {
  3088. key: "async",
  3089. value: function async(count) {
  3090. var test$$1 = this.test;
  3091. var popped = false,
  3092. acceptCallCount = count;
  3093. if (typeof acceptCallCount === "undefined") {
  3094. acceptCallCount = 1;
  3095. }
  3096. var resume = internalStop(test$$1);
  3097. return function done() {
  3098. if (config.current !== test$$1) {
  3099. throw Error("assert.async callback called after test finished.");
  3100. }
  3101. if (popped) {
  3102. test$$1.pushFailure("Too many calls to the `assert.async` callback", sourceFromStacktrace(2));
  3103. return;
  3104. }
  3105. acceptCallCount -= 1;
  3106. if (acceptCallCount > 0) {
  3107. return;
  3108. }
  3109. popped = true;
  3110. resume();
  3111. };
  3112. }
  3113. // Exports test.push() to the user API
  3114. // Alias of pushResult.
  3115. }, {
  3116. key: "push",
  3117. value: function push(result, actual, expected, message, negative) {
  3118. Logger.warn("assert.push is deprecated and will be removed in QUnit 3.0." + " Please use assert.pushResult instead (https://api.qunitjs.com/assert/pushResult).");
  3119. var currentAssert = this instanceof Assert ? this : config.current.assert;
  3120. return currentAssert.pushResult({
  3121. result: result,
  3122. actual: actual,
  3123. expected: expected,
  3124. message: message,
  3125. negative: negative
  3126. });
  3127. }
  3128. }, {
  3129. key: "pushResult",
  3130. value: function pushResult(resultInfo) {
  3131. // Destructure of resultInfo = { result, actual, expected, message, negative }
  3132. var assert = this;
  3133. var currentTest = assert instanceof Assert && assert.test || config.current;
  3134. // Backwards compatibility fix.
  3135. // Allows the direct use of global exported assertions and QUnit.assert.*
  3136. // Although, it's use is not recommended as it can leak assertions
  3137. // to other tests from async tests, because we only get a reference to the current test,
  3138. // not exactly the test where assertion were intended to be called.
  3139. if (!currentTest) {
  3140. throw new Error("assertion outside test context, in " + sourceFromStacktrace(2));
  3141. }
  3142. if (!(assert instanceof Assert)) {
  3143. assert = currentTest.assert;
  3144. }
  3145. return assert.test.pushResult(resultInfo);
  3146. }
  3147. }, {
  3148. key: "ok",
  3149. value: function ok(result, message) {
  3150. if (!message) {
  3151. message = result ? "okay" : "failed, expected argument to be truthy, was: " + dump.parse(result);
  3152. }
  3153. this.pushResult({
  3154. result: !!result,
  3155. actual: result,
  3156. expected: true,
  3157. message: message
  3158. });
  3159. }
  3160. }, {
  3161. key: "notOk",
  3162. value: function notOk(result, message) {
  3163. if (!message) {
  3164. message = !result ? "okay" : "failed, expected argument to be falsy, was: " + dump.parse(result);
  3165. }
  3166. this.pushResult({
  3167. result: !result,
  3168. actual: result,
  3169. expected: false,
  3170. message: message
  3171. });
  3172. }
  3173. }, {
  3174. key: "equal",
  3175. value: function equal(actual, expected, message) {
  3176. // eslint-disable-next-line eqeqeq
  3177. var result = expected == actual;
  3178. this.pushResult({
  3179. result: result,
  3180. actual: actual,
  3181. expected: expected,
  3182. message: message
  3183. });
  3184. }
  3185. }, {
  3186. key: "notEqual",
  3187. value: function notEqual(actual, expected, message) {
  3188. // eslint-disable-next-line eqeqeq
  3189. var result = expected != actual;
  3190. this.pushResult({
  3191. result: result,
  3192. actual: actual,
  3193. expected: expected,
  3194. message: message,
  3195. negative: true
  3196. });
  3197. }
  3198. }, {
  3199. key: "propEqual",
  3200. value: function propEqual(actual, expected, message) {
  3201. actual = objectValues(actual);
  3202. expected = objectValues(expected);
  3203. this.pushResult({
  3204. result: equiv(actual, expected),
  3205. actual: actual,
  3206. expected: expected,
  3207. message: message
  3208. });
  3209. }
  3210. }, {
  3211. key: "notPropEqual",
  3212. value: function notPropEqual(actual, expected, message) {
  3213. actual = objectValues(actual);
  3214. expected = objectValues(expected);
  3215. this.pushResult({
  3216. result: !equiv(actual, expected),
  3217. actual: actual,
  3218. expected: expected,
  3219. message: message,
  3220. negative: true
  3221. });
  3222. }
  3223. }, {
  3224. key: "deepEqual",
  3225. value: function deepEqual(actual, expected, message) {
  3226. this.pushResult({
  3227. result: equiv(actual, expected),
  3228. actual: actual,
  3229. expected: expected,
  3230. message: message
  3231. });
  3232. }
  3233. }, {
  3234. key: "notDeepEqual",
  3235. value: function notDeepEqual(actual, expected, message) {
  3236. this.pushResult({
  3237. result: !equiv(actual, expected),
  3238. actual: actual,
  3239. expected: expected,
  3240. message: message,
  3241. negative: true
  3242. });
  3243. }
  3244. }, {
  3245. key: "strictEqual",
  3246. value: function strictEqual(actual, expected, message) {
  3247. this.pushResult({
  3248. result: expected === actual,
  3249. actual: actual,
  3250. expected: expected,
  3251. message: message
  3252. });
  3253. }
  3254. }, {
  3255. key: "notStrictEqual",
  3256. value: function notStrictEqual(actual, expected, message) {
  3257. this.pushResult({
  3258. result: expected !== actual,
  3259. actual: actual,
  3260. expected: expected,
  3261. message: message,
  3262. negative: true
  3263. });
  3264. }
  3265. }, {
  3266. key: "throws",
  3267. value: function throws(block, expected, message) {
  3268. var actual = void 0,
  3269. result = false;
  3270. var currentTest = this instanceof Assert && this.test || config.current;
  3271. // 'expected' is optional unless doing string comparison
  3272. if (objectType(expected) === "string") {
  3273. if (message == null) {
  3274. message = expected;
  3275. expected = null;
  3276. } else {
  3277. throw new Error("throws/raises does not accept a string value for the expected argument.\n" + "Use a non-string object value (e.g. regExp) instead if it's necessary.");
  3278. }
  3279. }
  3280. currentTest.ignoreGlobalErrors = true;
  3281. try {
  3282. block.call(currentTest.testEnvironment);
  3283. } catch (e) {
  3284. actual = e;
  3285. }
  3286. currentTest.ignoreGlobalErrors = false;
  3287. if (actual) {
  3288. var expectedType = objectType(expected);
  3289. // We don't want to validate thrown error
  3290. if (!expected) {
  3291. result = true;
  3292. // Expected is a regexp
  3293. } else if (expectedType === "regexp") {
  3294. result = expected.test(errorString(actual));
  3295. // Log the string form of the regexp
  3296. expected = String(expected);
  3297. // Expected is a constructor, maybe an Error constructor
  3298. } else if (expectedType === "function" && actual instanceof expected) {
  3299. result = true;
  3300. // Expected is an Error object
  3301. } else if (expectedType === "object") {
  3302. result = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message;
  3303. // Log the string form of the Error object
  3304. expected = errorString(expected);
  3305. // Expected is a validation function which returns true if validation passed
  3306. } else if (expectedType === "function" && expected.call({}, actual) === true) {
  3307. expected = null;
  3308. result = true;
  3309. }
  3310. }
  3311. currentTest.assert.pushResult({
  3312. result: result,
  3313. // undefined if it didn't throw
  3314. actual: actual && errorString(actual),
  3315. expected: expected,
  3316. message: message
  3317. });
  3318. }
  3319. }, {
  3320. key: "rejects",
  3321. value: function rejects(promise, expected, message) {
  3322. var result = false;
  3323. var currentTest = this instanceof Assert && this.test || config.current;
  3324. // 'expected' is optional unless doing string comparison
  3325. if (objectType(expected) === "string") {
  3326. if (message === undefined) {
  3327. message = expected;
  3328. expected = undefined;
  3329. } else {
  3330. message = "assert.rejects does not accept a string value for the expected " + "argument.\nUse a non-string object value (e.g. validator function) instead " + "if necessary.";
  3331. currentTest.assert.pushResult({
  3332. result: false,
  3333. message: message
  3334. });
  3335. return;
  3336. }
  3337. }
  3338. var then = promise && promise.then;
  3339. if (objectType(then) !== "function") {
  3340. var _message = "The value provided to `assert.rejects` in " + "\"" + currentTest.testName + "\" was not a promise.";
  3341. currentTest.assert.pushResult({
  3342. result: false,
  3343. message: _message,
  3344. actual: promise
  3345. });
  3346. return;
  3347. }
  3348. var done = this.async();
  3349. return then.call(promise, function handleFulfillment() {
  3350. var message = "The promise returned by the `assert.rejects` callback in " + "\"" + currentTest.testName + "\" did not reject.";
  3351. currentTest.assert.pushResult({
  3352. result: false,
  3353. message: message,
  3354. actual: promise
  3355. });
  3356. done();
  3357. }, function handleRejection(actual) {
  3358. var expectedType = objectType(expected);
  3359. // We don't want to validate
  3360. if (expected === undefined) {
  3361. result = true;
  3362. // Expected is a regexp
  3363. } else if (expectedType === "regexp") {
  3364. result = expected.test(errorString(actual));
  3365. // Log the string form of the regexp
  3366. expected = String(expected);
  3367. // Expected is a constructor, maybe an Error constructor
  3368. } else if (expectedType === "function" && actual instanceof expected) {
  3369. result = true;
  3370. // Expected is an Error object
  3371. } else if (expectedType === "object") {
  3372. result = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message;
  3373. // Log the string form of the Error object
  3374. expected = errorString(expected);
  3375. // Expected is a validation function which returns true if validation passed
  3376. } else {
  3377. if (expectedType === "function") {
  3378. result = expected.call({}, actual) === true;
  3379. expected = null;
  3380. // Expected is some other invalid type
  3381. } else {
  3382. result = false;
  3383. message = "invalid expected value provided to `assert.rejects` " + "callback in \"" + currentTest.testName + "\": " + expectedType + ".";
  3384. }
  3385. }
  3386. currentTest.assert.pushResult({
  3387. result: result,
  3388. // leave rejection value of undefined as-is
  3389. actual: actual && errorString(actual),
  3390. expected: expected,
  3391. message: message
  3392. });
  3393. done();
  3394. });
  3395. }
  3396. }]);
  3397. return Assert;
  3398. }();
  3399. // Provide an alternative to assert.throws(), for environments that consider throws a reserved word
  3400. // Known to us are: Closure Compiler, Narwhal
  3401. // eslint-disable-next-line dot-notation
  3402. Assert.prototype.raises = Assert.prototype["throws"];
  3403. /**
  3404. * Converts an error into a simple string for comparisons.
  3405. *
  3406. * @param {Error|Object} error
  3407. * @return {String}
  3408. */
  3409. function errorString(error) {
  3410. var resultErrorString = error.toString();
  3411. // If the error wasn't a subclass of Error but something like
  3412. // an object literal with name and message properties...
  3413. if (resultErrorString.substring(0, 7) === "[object") {
  3414. var name = error.name ? error.name.toString() : "Error";
  3415. var message = error.message ? error.message.toString() : "";
  3416. if (name && message) {
  3417. return name + ": " + message;
  3418. } else if (name) {
  3419. return name;
  3420. } else if (message) {
  3421. return message;
  3422. } else {
  3423. return "Error";
  3424. }
  3425. } else {
  3426. return resultErrorString;
  3427. }
  3428. }
  3429. /* global module, exports, define */
  3430. function exportQUnit(QUnit) {
  3431. if (defined.document) {
  3432. // QUnit may be defined when it is preconfigured but then only QUnit and QUnit.config may be defined.
  3433. if (window$1.QUnit && window$1.QUnit.version) {
  3434. throw new Error("QUnit has already been defined.");
  3435. }
  3436. window$1.QUnit = QUnit;
  3437. }
  3438. // For nodejs
  3439. if (typeof module !== "undefined" && module && module.exports) {
  3440. module.exports = QUnit;
  3441. // For consistency with CommonJS environments' exports
  3442. module.exports.QUnit = QUnit;
  3443. }
  3444. // For CommonJS with exports, but without module.exports, like Rhino
  3445. if (typeof exports !== "undefined" && exports) {
  3446. exports.QUnit = QUnit;
  3447. }
  3448. if (typeof define === "function" && define.amd) {
  3449. define(function () {
  3450. return QUnit;
  3451. });
  3452. QUnit.config.autostart = false;
  3453. }
  3454. // For Web/Service Workers
  3455. if (self$1 && self$1.WorkerGlobalScope && self$1 instanceof self$1.WorkerGlobalScope) {
  3456. self$1.QUnit = QUnit;
  3457. }
  3458. }
  3459. // Handle an unhandled exception. By convention, returns true if further
  3460. // error handling should be suppressed and false otherwise.
  3461. // In this case, we will only suppress further error handling if the
  3462. // "ignoreGlobalErrors" configuration option is enabled.
  3463. function onError(error) {
  3464. for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  3465. args[_key - 1] = arguments[_key];
  3466. }
  3467. if (config.current) {
  3468. if (config.current.ignoreGlobalErrors) {
  3469. return true;
  3470. }
  3471. pushFailure.apply(undefined, [error.message, error.stacktrace || error.fileName + ":" + error.lineNumber].concat(args));
  3472. } else {
  3473. test("global failure", extend(function () {
  3474. pushFailure.apply(undefined, [error.message, error.stacktrace || error.fileName + ":" + error.lineNumber].concat(args));
  3475. }, { validTest: true }));
  3476. }
  3477. return false;
  3478. }
  3479. // Handle an unhandled rejection
  3480. function onUnhandledRejection(reason) {
  3481. var resultInfo = {
  3482. result: false,
  3483. message: reason.message || "error",
  3484. actual: reason,
  3485. source: reason.stack || sourceFromStacktrace(3)
  3486. };
  3487. var currentTest = config.current;
  3488. if (currentTest) {
  3489. currentTest.assert.pushResult(resultInfo);
  3490. } else {
  3491. test("global failure", extend(function (assert) {
  3492. assert.pushResult(resultInfo);
  3493. }, { validTest: true }));
  3494. }
  3495. }
  3496. var QUnit = {};
  3497. var globalSuite = new SuiteReport();
  3498. // The initial "currentModule" represents the global (or top-level) module that
  3499. // is not explicitly defined by the user, therefore we add the "globalSuite" to
  3500. // it since each module has a suiteReport associated with it.
  3501. config.currentModule.suiteReport = globalSuite;
  3502. var globalStartCalled = false;
  3503. var runStarted = false;
  3504. // Figure out if we're running the tests from a server or not
  3505. QUnit.isLocal = !(defined.document && window$1.location.protocol !== "file:");
  3506. // Expose the current QUnit version
  3507. QUnit.version = "2.9.2";
  3508. extend(QUnit, {
  3509. on: on,
  3510. module: module$1,
  3511. test: test,
  3512. todo: todo,
  3513. skip: skip,
  3514. only: only,
  3515. start: function start(count) {
  3516. var globalStartAlreadyCalled = globalStartCalled;
  3517. if (!config.current) {
  3518. globalStartCalled = true;
  3519. if (runStarted) {
  3520. throw new Error("Called start() while test already started running");
  3521. } else if (globalStartAlreadyCalled || count > 1) {
  3522. throw new Error("Called start() outside of a test context too many times");
  3523. } else if (config.autostart) {
  3524. throw new Error("Called start() outside of a test context when " + "QUnit.config.autostart was true");
  3525. } else if (!config.pageLoaded) {
  3526. // The page isn't completely loaded yet, so we set autostart and then
  3527. // load if we're in Node or wait for the browser's load event.
  3528. config.autostart = true;
  3529. // Starts from Node even if .load was not previously called. We still return
  3530. // early otherwise we'll wind up "beginning" twice.
  3531. if (!defined.document) {
  3532. QUnit.load();
  3533. }
  3534. return;
  3535. }
  3536. } else {
  3537. throw new Error("QUnit.start cannot be called inside a test context.");
  3538. }
  3539. scheduleBegin();
  3540. },
  3541. config: config,
  3542. is: is,
  3543. objectType: objectType,
  3544. extend: extend,
  3545. load: function load() {
  3546. config.pageLoaded = true;
  3547. // Initialize the configuration options
  3548. extend(config, {
  3549. stats: { all: 0, bad: 0 },
  3550. started: 0,
  3551. updateRate: 1000,
  3552. autostart: true,
  3553. filter: ""
  3554. }, true);
  3555. if (!runStarted) {
  3556. config.blocking = false;
  3557. if (config.autostart) {
  3558. scheduleBegin();
  3559. }
  3560. }
  3561. },
  3562. stack: function stack(offset) {
  3563. offset = (offset || 0) + 2;
  3564. return sourceFromStacktrace(offset);
  3565. },
  3566. onError: onError,
  3567. onUnhandledRejection: onUnhandledRejection
  3568. });
  3569. QUnit.pushFailure = pushFailure;
  3570. QUnit.assert = Assert.prototype;
  3571. QUnit.equiv = equiv;
  3572. QUnit.dump = dump;
  3573. registerLoggingCallbacks(QUnit);
  3574. function scheduleBegin() {
  3575. runStarted = true;
  3576. // Add a slight delay to allow definition of more modules and tests.
  3577. if (defined.setTimeout) {
  3578. setTimeout$1(function () {
  3579. begin();
  3580. });
  3581. } else {
  3582. begin();
  3583. }
  3584. }
  3585. function unblockAndAdvanceQueue() {
  3586. config.blocking = false;
  3587. ProcessingQueue.advance();
  3588. }
  3589. function begin() {
  3590. var i,
  3591. l,
  3592. modulesLog = [];
  3593. // If the test run hasn't officially begun yet
  3594. if (!config.started) {
  3595. // Record the time of the test run's beginning
  3596. config.started = now();
  3597. // Delete the loose unnamed module if unused.
  3598. if (config.modules[0].name === "" && config.modules[0].tests.length === 0) {
  3599. config.modules.shift();
  3600. }
  3601. // Avoid unnecessary information by not logging modules' test environments
  3602. for (i = 0, l = config.modules.length; i < l; i++) {
  3603. modulesLog.push({
  3604. name: config.modules[i].name,
  3605. tests: config.modules[i].tests
  3606. });
  3607. }
  3608. // The test run is officially beginning now
  3609. emit("runStart", globalSuite.start(true));
  3610. runLoggingCallbacks("begin", {
  3611. totalTests: Test.count,
  3612. modules: modulesLog
  3613. }).then(unblockAndAdvanceQueue);
  3614. } else {
  3615. unblockAndAdvanceQueue();
  3616. }
  3617. }
  3618. exportQUnit(QUnit);
  3619. (function () {
  3620. if (typeof window$1 === "undefined" || typeof document$1 === "undefined") {
  3621. return;
  3622. }
  3623. var config = QUnit.config,
  3624. hasOwn = Object.prototype.hasOwnProperty;
  3625. // Stores fixture HTML for resetting later
  3626. function storeFixture() {
  3627. // Avoid overwriting user-defined values
  3628. if (hasOwn.call(config, "fixture")) {
  3629. return;
  3630. }
  3631. var fixture = document$1.getElementById("qunit-fixture");
  3632. if (fixture) {
  3633. config.fixture = fixture.cloneNode(true);
  3634. }
  3635. }
  3636. QUnit.begin(storeFixture);
  3637. // Resets the fixture DOM element if available.
  3638. function resetFixture() {
  3639. if (config.fixture == null) {
  3640. return;
  3641. }
  3642. var fixture = document$1.getElementById("qunit-fixture");
  3643. var resetFixtureType = _typeof(config.fixture);
  3644. if (resetFixtureType === "string") {
  3645. // support user defined values for `config.fixture`
  3646. var newFixture = document$1.createElement("div");
  3647. newFixture.setAttribute("id", "qunit-fixture");
  3648. newFixture.innerHTML = config.fixture;
  3649. fixture.parentNode.replaceChild(newFixture, fixture);
  3650. } else {
  3651. var clonedFixture = config.fixture.cloneNode(true);
  3652. fixture.parentNode.replaceChild(clonedFixture, fixture);
  3653. }
  3654. }
  3655. QUnit.testStart(resetFixture);
  3656. })();
  3657. (function () {
  3658. // Only interact with URLs via window.location
  3659. var location = typeof window$1 !== "undefined" && window$1.location;
  3660. if (!location) {
  3661. return;
  3662. }
  3663. var urlParams = getUrlParams();
  3664. QUnit.urlParams = urlParams;
  3665. // Match module/test by inclusion in an array
  3666. QUnit.config.moduleId = [].concat(urlParams.moduleId || []);
  3667. QUnit.config.testId = [].concat(urlParams.testId || []);
  3668. // Exact case-insensitive match of the module name
  3669. QUnit.config.module = urlParams.module;
  3670. // Regular expression or case-insenstive substring match against "moduleName: testName"
  3671. QUnit.config.filter = urlParams.filter;
  3672. // Test order randomization
  3673. if (urlParams.seed === true) {
  3674. // Generate a random seed if the option is specified without a value
  3675. QUnit.config.seed = Math.random().toString(36).slice(2);
  3676. } else if (urlParams.seed) {
  3677. QUnit.config.seed = urlParams.seed;
  3678. }
  3679. // Add URL-parameter-mapped config values with UI form rendering data
  3680. QUnit.config.urlConfig.push({
  3681. id: "hidepassed",
  3682. label: "Hide passed tests",
  3683. tooltip: "Only show tests and assertions that fail. Stored as query-strings."
  3684. }, {
  3685. id: "noglobals",
  3686. label: "Check for Globals",
  3687. tooltip: "Enabling this will test if any test introduces new properties on the " + "global object (`window` in Browsers). Stored as query-strings."
  3688. }, {
  3689. id: "notrycatch",
  3690. label: "No try-catch",
  3691. tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + "exceptions in IE reasonable. Stored as query-strings."
  3692. });
  3693. QUnit.begin(function () {
  3694. var i,
  3695. option,
  3696. urlConfig = QUnit.config.urlConfig;
  3697. for (i = 0; i < urlConfig.length; i++) {
  3698. // Options can be either strings or objects with nonempty "id" properties
  3699. option = QUnit.config.urlConfig[i];
  3700. if (typeof option !== "string") {
  3701. option = option.id;
  3702. }
  3703. if (QUnit.config[option] === undefined) {
  3704. QUnit.config[option] = urlParams[option];
  3705. }
  3706. }
  3707. });
  3708. function getUrlParams() {
  3709. var i, param, name, value;
  3710. var urlParams = Object.create(null);
  3711. var params = location.search.slice(1).split("&");
  3712. var length = params.length;
  3713. for (i = 0; i < length; i++) {
  3714. if (params[i]) {
  3715. param = params[i].split("=");
  3716. name = decodeQueryParam(param[0]);
  3717. // Allow just a key to turn on a flag, e.g., test.html?noglobals
  3718. value = param.length === 1 || decodeQueryParam(param.slice(1).join("="));
  3719. if (name in urlParams) {
  3720. urlParams[name] = [].concat(urlParams[name], value);
  3721. } else {
  3722. urlParams[name] = value;
  3723. }
  3724. }
  3725. }
  3726. return urlParams;
  3727. }
  3728. function decodeQueryParam(param) {
  3729. return decodeURIComponent(param.replace(/\+/g, "%20"));
  3730. }
  3731. })();
  3732. var stats = {
  3733. passedTests: 0,
  3734. failedTests: 0,
  3735. skippedTests: 0,
  3736. todoTests: 0
  3737. };
  3738. // Escape text for attribute or text content.
  3739. function escapeText(s) {
  3740. if (!s) {
  3741. return "";
  3742. }
  3743. s = s + "";
  3744. // Both single quotes and double quotes (for attributes)
  3745. return s.replace(/['"<>&]/g, function (s) {
  3746. switch (s) {
  3747. case "'":
  3748. return "&#039;";
  3749. case "\"":
  3750. return "&quot;";
  3751. case "<":
  3752. return "&lt;";
  3753. case ">":
  3754. return "&gt;";
  3755. case "&":
  3756. return "&amp;";
  3757. }
  3758. });
  3759. }
  3760. (function () {
  3761. // Don't load the HTML Reporter on non-browser environments
  3762. if (typeof window$1 === "undefined" || !window$1.document) {
  3763. return;
  3764. }
  3765. var config = QUnit.config,
  3766. hiddenTests = [],
  3767. document = window$1.document,
  3768. collapseNext = false,
  3769. hasOwn = Object.prototype.hasOwnProperty,
  3770. unfilteredUrl = setUrl({ filter: undefined, module: undefined,
  3771. moduleId: undefined, testId: undefined }),
  3772. modulesList = [];
  3773. function addEvent(elem, type, fn) {
  3774. elem.addEventListener(type, fn, false);
  3775. }
  3776. function removeEvent(elem, type, fn) {
  3777. elem.removeEventListener(type, fn, false);
  3778. }
  3779. function addEvents(elems, type, fn) {
  3780. var i = elems.length;
  3781. while (i--) {
  3782. addEvent(elems[i], type, fn);
  3783. }
  3784. }
  3785. function hasClass(elem, name) {
  3786. return (" " + elem.className + " ").indexOf(" " + name + " ") >= 0;
  3787. }
  3788. function addClass(elem, name) {
  3789. if (!hasClass(elem, name)) {
  3790. elem.className += (elem.className ? " " : "") + name;
  3791. }
  3792. }
  3793. function toggleClass(elem, name, force) {
  3794. if (force || typeof force === "undefined" && !hasClass(elem, name)) {
  3795. addClass(elem, name);
  3796. } else {
  3797. removeClass(elem, name);
  3798. }
  3799. }
  3800. function removeClass(elem, name) {
  3801. var set = " " + elem.className + " ";
  3802. // Class name may appear multiple times
  3803. while (set.indexOf(" " + name + " ") >= 0) {
  3804. set = set.replace(" " + name + " ", " ");
  3805. }
  3806. // Trim for prettiness
  3807. elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
  3808. }
  3809. function id(name) {
  3810. return document.getElementById && document.getElementById(name);
  3811. }
  3812. function abortTests() {
  3813. var abortButton = id("qunit-abort-tests-button");
  3814. if (abortButton) {
  3815. abortButton.disabled = true;
  3816. abortButton.innerHTML = "Aborting...";
  3817. }
  3818. QUnit.config.queue.length = 0;
  3819. return false;
  3820. }
  3821. function interceptNavigation(ev) {
  3822. applyUrlParams();
  3823. if (ev && ev.preventDefault) {
  3824. ev.preventDefault();
  3825. }
  3826. return false;
  3827. }
  3828. function getUrlConfigHtml() {
  3829. var i,
  3830. j,
  3831. val,
  3832. escaped,
  3833. escapedTooltip,
  3834. selection = false,
  3835. urlConfig = config.urlConfig,
  3836. urlConfigHtml = "";
  3837. for (i = 0; i < urlConfig.length; i++) {
  3838. // Options can be either strings or objects with nonempty "id" properties
  3839. val = config.urlConfig[i];
  3840. if (typeof val === "string") {
  3841. val = {
  3842. id: val,
  3843. label: val
  3844. };
  3845. }
  3846. escaped = escapeText(val.id);
  3847. escapedTooltip = escapeText(val.tooltip);
  3848. if (!val.value || typeof val.value === "string") {
  3849. urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + "' title='" + escapedTooltip + "'><input id='qunit-urlconfig-" + escaped + "' name='" + escaped + "' type='checkbox'" + (val.value ? " value='" + escapeText(val.value) + "'" : "") + (config[val.id] ? " checked='checked'" : "") + " title='" + escapedTooltip + "' />" + escapeText(val.label) + "</label>";
  3850. } else {
  3851. urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + "' title='" + escapedTooltip + "'>" + val.label + ": </label><select id='qunit-urlconfig-" + escaped + "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
  3852. if (QUnit.is("array", val.value)) {
  3853. for (j = 0; j < val.value.length; j++) {
  3854. escaped = escapeText(val.value[j]);
  3855. urlConfigHtml += "<option value='" + escaped + "'" + (config[val.id] === val.value[j] ? (selection = true) && " selected='selected'" : "") + ">" + escaped + "</option>";
  3856. }
  3857. } else {
  3858. for (j in val.value) {
  3859. if (hasOwn.call(val.value, j)) {
  3860. urlConfigHtml += "<option value='" + escapeText(j) + "'" + (config[val.id] === j ? (selection = true) && " selected='selected'" : "") + ">" + escapeText(val.value[j]) + "</option>";
  3861. }
  3862. }
  3863. }
  3864. if (config[val.id] && !selection) {
  3865. escaped = escapeText(config[val.id]);
  3866. urlConfigHtml += "<option value='" + escaped + "' selected='selected' disabled='disabled'>" + escaped + "</option>";
  3867. }
  3868. urlConfigHtml += "</select>";
  3869. }
  3870. }
  3871. return urlConfigHtml;
  3872. }
  3873. // Handle "click" events on toolbar checkboxes and "change" for select menus.
  3874. // Updates the URL with the new state of `config.urlConfig` values.
  3875. function toolbarChanged() {
  3876. var updatedUrl,
  3877. value,
  3878. tests,
  3879. field = this,
  3880. params = {};
  3881. // Detect if field is a select menu or a checkbox
  3882. if ("selectedIndex" in field) {
  3883. value = field.options[field.selectedIndex].value || undefined;
  3884. } else {
  3885. value = field.checked ? field.defaultValue || true : undefined;
  3886. }
  3887. params[field.name] = value;
  3888. updatedUrl = setUrl(params);
  3889. // Check if we can apply the change without a page refresh
  3890. if ("hidepassed" === field.name && "replaceState" in window$1.history) {
  3891. QUnit.urlParams[field.name] = value;
  3892. config[field.name] = value || false;
  3893. tests = id("qunit-tests");
  3894. if (tests) {
  3895. var length = tests.children.length;
  3896. var children = tests.children;
  3897. if (field.checked) {
  3898. for (var i = 0; i < length; i++) {
  3899. var test = children[i];
  3900. if (test && test.className.indexOf("pass") > -1) {
  3901. hiddenTests.push(test);
  3902. }
  3903. }
  3904. var _iteratorNormalCompletion = true;
  3905. var _didIteratorError = false;
  3906. var _iteratorError = undefined;
  3907. try {
  3908. for (var _iterator = hiddenTests[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  3909. var hiddenTest = _step.value;
  3910. tests.removeChild(hiddenTest);
  3911. }
  3912. } catch (err) {
  3913. _didIteratorError = true;
  3914. _iteratorError = err;
  3915. } finally {
  3916. try {
  3917. if (!_iteratorNormalCompletion && _iterator.return) {
  3918. _iterator.return();
  3919. }
  3920. } finally {
  3921. if (_didIteratorError) {
  3922. throw _iteratorError;
  3923. }
  3924. }
  3925. }
  3926. } else {
  3927. while ((test = hiddenTests.pop()) != null) {
  3928. tests.appendChild(test);
  3929. }
  3930. }
  3931. }
  3932. window$1.history.replaceState(null, "", updatedUrl);
  3933. } else {
  3934. window$1.location = updatedUrl;
  3935. }
  3936. }
  3937. function setUrl(params) {
  3938. var key,
  3939. arrValue,
  3940. i,
  3941. querystring = "?",
  3942. location = window$1.location;
  3943. params = QUnit.extend(QUnit.extend({}, QUnit.urlParams), params);
  3944. for (key in params) {
  3945. // Skip inherited or undefined properties
  3946. if (hasOwn.call(params, key) && params[key] !== undefined) {
  3947. // Output a parameter for each value of this key
  3948. // (but usually just one)
  3949. arrValue = [].concat(params[key]);
  3950. for (i = 0; i < arrValue.length; i++) {
  3951. querystring += encodeURIComponent(key);
  3952. if (arrValue[i] !== true) {
  3953. querystring += "=" + encodeURIComponent(arrValue[i]);
  3954. }
  3955. querystring += "&";
  3956. }
  3957. }
  3958. }
  3959. return location.protocol + "//" + location.host + location.pathname + querystring.slice(0, -1);
  3960. }
  3961. function applyUrlParams() {
  3962. var i,
  3963. selectedModules = [],
  3964. modulesList = id("qunit-modulefilter-dropdown-list").getElementsByTagName("input"),
  3965. filter = id("qunit-filter-input").value;
  3966. for (i = 0; i < modulesList.length; i++) {
  3967. if (modulesList[i].checked) {
  3968. selectedModules.push(modulesList[i].value);
  3969. }
  3970. }
  3971. window$1.location = setUrl({
  3972. filter: filter === "" ? undefined : filter,
  3973. moduleId: selectedModules.length === 0 ? undefined : selectedModules,
  3974. // Remove module and testId filter
  3975. module: undefined,
  3976. testId: undefined
  3977. });
  3978. }
  3979. function toolbarUrlConfigContainer() {
  3980. var urlConfigContainer = document.createElement("span");
  3981. urlConfigContainer.innerHTML = getUrlConfigHtml();
  3982. addClass(urlConfigContainer, "qunit-url-config");
  3983. addEvents(urlConfigContainer.getElementsByTagName("input"), "change", toolbarChanged);
  3984. addEvents(urlConfigContainer.getElementsByTagName("select"), "change", toolbarChanged);
  3985. return urlConfigContainer;
  3986. }
  3987. function abortTestsButton() {
  3988. var button = document.createElement("button");
  3989. button.id = "qunit-abort-tests-button";
  3990. button.innerHTML = "Abort";
  3991. addEvent(button, "click", abortTests);
  3992. return button;
  3993. }
  3994. function toolbarLooseFilter() {
  3995. var filter = document.createElement("form"),
  3996. label = document.createElement("label"),
  3997. input = document.createElement("input"),
  3998. button = document.createElement("button");
  3999. addClass(filter, "qunit-filter");
  4000. label.innerHTML = "Filter: ";
  4001. input.type = "text";
  4002. input.value = config.filter || "";
  4003. input.name = "filter";
  4004. input.id = "qunit-filter-input";
  4005. button.innerHTML = "Go";
  4006. label.appendChild(input);
  4007. filter.appendChild(label);
  4008. filter.appendChild(document.createTextNode(" "));
  4009. filter.appendChild(button);
  4010. addEvent(filter, "submit", interceptNavigation);
  4011. return filter;
  4012. }
  4013. function moduleListHtml() {
  4014. var i,
  4015. checked,
  4016. html = "";
  4017. for (i = 0; i < config.modules.length; i++) {
  4018. if (config.modules[i].name !== "") {
  4019. checked = config.moduleId.indexOf(config.modules[i].moduleId) > -1;
  4020. html += "<li><label class='clickable" + (checked ? " checked" : "") + "'><input type='checkbox' " + "value='" + config.modules[i].moduleId + "'" + (checked ? " checked='checked'" : "") + " />" + escapeText(config.modules[i].name) + "</label></li>";
  4021. }
  4022. }
  4023. return html;
  4024. }
  4025. function toolbarModuleFilter() {
  4026. var commit,
  4027. reset,
  4028. moduleFilter = document.createElement("form"),
  4029. label = document.createElement("label"),
  4030. moduleSearch = document.createElement("input"),
  4031. dropDown = document.createElement("div"),
  4032. actions = document.createElement("span"),
  4033. applyButton = document.createElement("button"),
  4034. resetButton = document.createElement("button"),
  4035. allModulesLabel = document.createElement("label"),
  4036. allCheckbox = document.createElement("input"),
  4037. dropDownList = document.createElement("ul"),
  4038. dirty = false;
  4039. moduleSearch.id = "qunit-modulefilter-search";
  4040. moduleSearch.autocomplete = "off";
  4041. addEvent(moduleSearch, "input", searchInput);
  4042. addEvent(moduleSearch, "input", searchFocus);
  4043. addEvent(moduleSearch, "focus", searchFocus);
  4044. addEvent(moduleSearch, "click", searchFocus);
  4045. label.id = "qunit-modulefilter-search-container";
  4046. label.innerHTML = "Module: ";
  4047. label.appendChild(moduleSearch);
  4048. applyButton.textContent = "Apply";
  4049. applyButton.style.display = "none";
  4050. resetButton.textContent = "Reset";
  4051. resetButton.type = "reset";
  4052. resetButton.style.display = "none";
  4053. allCheckbox.type = "checkbox";
  4054. allCheckbox.checked = config.moduleId.length === 0;
  4055. allModulesLabel.className = "clickable";
  4056. if (config.moduleId.length) {
  4057. allModulesLabel.className = "checked";
  4058. }
  4059. allModulesLabel.appendChild(allCheckbox);
  4060. allModulesLabel.appendChild(document.createTextNode("All modules"));
  4061. actions.id = "qunit-modulefilter-actions";
  4062. actions.appendChild(applyButton);
  4063. actions.appendChild(resetButton);
  4064. actions.appendChild(allModulesLabel);
  4065. commit = actions.firstChild;
  4066. reset = commit.nextSibling;
  4067. addEvent(commit, "click", applyUrlParams);
  4068. dropDownList.id = "qunit-modulefilter-dropdown-list";
  4069. dropDownList.innerHTML = moduleListHtml();
  4070. dropDown.id = "qunit-modulefilter-dropdown";
  4071. dropDown.style.display = "none";
  4072. dropDown.appendChild(actions);
  4073. dropDown.appendChild(dropDownList);
  4074. addEvent(dropDown, "change", selectionChange);
  4075. selectionChange();
  4076. moduleFilter.id = "qunit-modulefilter";
  4077. moduleFilter.appendChild(label);
  4078. moduleFilter.appendChild(dropDown);
  4079. addEvent(moduleFilter, "submit", interceptNavigation);
  4080. addEvent(moduleFilter, "reset", function () {
  4081. // Let the reset happen, then update styles
  4082. window$1.setTimeout(selectionChange);
  4083. });
  4084. // Enables show/hide for the dropdown
  4085. function searchFocus() {
  4086. if (dropDown.style.display !== "none") {
  4087. return;
  4088. }
  4089. dropDown.style.display = "block";
  4090. addEvent(document, "click", hideHandler);
  4091. addEvent(document, "keydown", hideHandler);
  4092. // Hide on Escape keydown or outside-container click
  4093. function hideHandler(e) {
  4094. var inContainer = moduleFilter.contains(e.target);
  4095. if (e.keyCode === 27 || !inContainer) {
  4096. if (e.keyCode === 27 && inContainer) {
  4097. moduleSearch.focus();
  4098. }
  4099. dropDown.style.display = "none";
  4100. removeEvent(document, "click", hideHandler);
  4101. removeEvent(document, "keydown", hideHandler);
  4102. moduleSearch.value = "";
  4103. searchInput();
  4104. }
  4105. }
  4106. }
  4107. // Processes module search box input
  4108. function searchInput() {
  4109. var i,
  4110. item,
  4111. searchText = moduleSearch.value.toLowerCase(),
  4112. listItems = dropDownList.children;
  4113. for (i = 0; i < listItems.length; i++) {
  4114. item = listItems[i];
  4115. if (!searchText || item.textContent.toLowerCase().indexOf(searchText) > -1) {
  4116. item.style.display = "";
  4117. } else {
  4118. item.style.display = "none";
  4119. }
  4120. }
  4121. }
  4122. // Processes selection changes
  4123. function selectionChange(evt) {
  4124. var i,
  4125. item,
  4126. checkbox = evt && evt.target || allCheckbox,
  4127. modulesList = dropDownList.getElementsByTagName("input"),
  4128. selectedNames = [];
  4129. toggleClass(checkbox.parentNode, "checked", checkbox.checked);
  4130. dirty = false;
  4131. if (checkbox.checked && checkbox !== allCheckbox) {
  4132. allCheckbox.checked = false;
  4133. removeClass(allCheckbox.parentNode, "checked");
  4134. }
  4135. for (i = 0; i < modulesList.length; i++) {
  4136. item = modulesList[i];
  4137. if (!evt) {
  4138. toggleClass(item.parentNode, "checked", item.checked);
  4139. } else if (checkbox === allCheckbox && checkbox.checked) {
  4140. item.checked = false;
  4141. removeClass(item.parentNode, "checked");
  4142. }
  4143. dirty = dirty || item.checked !== item.defaultChecked;
  4144. if (item.checked) {
  4145. selectedNames.push(item.parentNode.textContent);
  4146. }
  4147. }
  4148. commit.style.display = reset.style.display = dirty ? "" : "none";
  4149. moduleSearch.placeholder = selectedNames.join(", ") || allCheckbox.parentNode.textContent;
  4150. moduleSearch.title = "Type to filter list. Current selection:\n" + (selectedNames.join("\n") || allCheckbox.parentNode.textContent);
  4151. }
  4152. return moduleFilter;
  4153. }
  4154. function appendToolbar() {
  4155. var toolbar = id("qunit-testrunner-toolbar");
  4156. if (toolbar) {
  4157. toolbar.appendChild(toolbarUrlConfigContainer());
  4158. toolbar.appendChild(toolbarModuleFilter());
  4159. toolbar.appendChild(toolbarLooseFilter());
  4160. toolbar.appendChild(document.createElement("div")).className = "clearfix";
  4161. }
  4162. }
  4163. function appendHeader() {
  4164. var header = id("qunit-header");
  4165. if (header) {
  4166. header.innerHTML = "<a href='" + escapeText(unfilteredUrl) + "'>" + header.innerHTML + "</a> ";
  4167. }
  4168. }
  4169. function appendBanner() {
  4170. var banner = id("qunit-banner");
  4171. if (banner) {
  4172. banner.className = "";
  4173. }
  4174. }
  4175. function appendTestResults() {
  4176. var tests = id("qunit-tests"),
  4177. result = id("qunit-testresult"),
  4178. controls;
  4179. if (result) {
  4180. result.parentNode.removeChild(result);
  4181. }
  4182. if (tests) {
  4183. tests.innerHTML = "";
  4184. result = document.createElement("p");
  4185. result.id = "qunit-testresult";
  4186. result.className = "result";
  4187. tests.parentNode.insertBefore(result, tests);
  4188. result.innerHTML = "<div id=\"qunit-testresult-display\">Running...<br />&#160;</div>" + "<div id=\"qunit-testresult-controls\"></div>" + "<div class=\"clearfix\"></div>";
  4189. controls = id("qunit-testresult-controls");
  4190. }
  4191. if (controls) {
  4192. controls.appendChild(abortTestsButton());
  4193. }
  4194. }
  4195. function appendFilteredTest() {
  4196. var testId = QUnit.config.testId;
  4197. if (!testId || testId.length <= 0) {
  4198. return "";
  4199. }
  4200. return "<div id='qunit-filteredTest'>Rerunning selected tests: " + escapeText(testId.join(", ")) + " <a id='qunit-clearFilter' href='" + escapeText(unfilteredUrl) + "'>Run all tests</a></div>";
  4201. }
  4202. function appendUserAgent() {
  4203. var userAgent = id("qunit-userAgent");
  4204. if (userAgent) {
  4205. userAgent.innerHTML = "";
  4206. userAgent.appendChild(document.createTextNode("QUnit " + QUnit.version + "; " + navigator.userAgent));
  4207. }
  4208. }
  4209. function appendInterface() {
  4210. var qunit = id("qunit");
  4211. if (qunit) {
  4212. qunit.innerHTML = "<h1 id='qunit-header'>" + escapeText(document.title) + "</h1>" + "<h2 id='qunit-banner'></h2>" + "<div id='qunit-testrunner-toolbar'></div>" + appendFilteredTest() + "<h2 id='qunit-userAgent'></h2>" + "<ol id='qunit-tests'></ol>";
  4213. }
  4214. appendHeader();
  4215. appendBanner();
  4216. appendTestResults();
  4217. appendUserAgent();
  4218. appendToolbar();
  4219. }
  4220. function appendTest(name, testId, moduleName) {
  4221. var title,
  4222. rerunTrigger,
  4223. testBlock,
  4224. assertList,
  4225. tests = id("qunit-tests");
  4226. if (!tests) {
  4227. return;
  4228. }
  4229. title = document.createElement("strong");
  4230. title.innerHTML = getNameHtml(name, moduleName);
  4231. rerunTrigger = document.createElement("a");
  4232. rerunTrigger.innerHTML = "Rerun";
  4233. rerunTrigger.href = setUrl({ testId: testId });
  4234. testBlock = document.createElement("li");
  4235. testBlock.appendChild(title);
  4236. testBlock.appendChild(rerunTrigger);
  4237. testBlock.id = "qunit-test-output-" + testId;
  4238. assertList = document.createElement("ol");
  4239. assertList.className = "qunit-assert-list";
  4240. testBlock.appendChild(assertList);
  4241. tests.appendChild(testBlock);
  4242. }
  4243. // HTML Reporter initialization and load
  4244. QUnit.begin(function (details) {
  4245. var i, moduleObj;
  4246. // Sort modules by name for the picker
  4247. for (i = 0; i < details.modules.length; i++) {
  4248. moduleObj = details.modules[i];
  4249. if (moduleObj.name) {
  4250. modulesList.push(moduleObj.name);
  4251. }
  4252. }
  4253. modulesList.sort(function (a, b) {
  4254. return a.localeCompare(b);
  4255. });
  4256. // Initialize QUnit elements
  4257. appendInterface();
  4258. });
  4259. QUnit.done(function (details) {
  4260. var banner = id("qunit-banner"),
  4261. tests = id("qunit-tests"),
  4262. abortButton = id("qunit-abort-tests-button"),
  4263. totalTests = stats.passedTests + stats.skippedTests + stats.todoTests + stats.failedTests,
  4264. html = [totalTests, " tests completed in ", details.runtime, " milliseconds, with ", stats.failedTests, " failed, ", stats.skippedTests, " skipped, and ", stats.todoTests, " todo.<br />", "<span class='passed'>", details.passed, "</span> assertions of <span class='total'>", details.total, "</span> passed, <span class='failed'>", details.failed, "</span> failed."].join(""),
  4265. test,
  4266. assertLi,
  4267. assertList;
  4268. // Update remaing tests to aborted
  4269. if (abortButton && abortButton.disabled) {
  4270. html = "Tests aborted after " + details.runtime + " milliseconds.";
  4271. for (var i = 0; i < tests.children.length; i++) {
  4272. test = tests.children[i];
  4273. if (test.className === "" || test.className === "running") {
  4274. test.className = "aborted";
  4275. assertList = test.getElementsByTagName("ol")[0];
  4276. assertLi = document.createElement("li");
  4277. assertLi.className = "fail";
  4278. assertLi.innerHTML = "Test aborted.";
  4279. assertList.appendChild(assertLi);
  4280. }
  4281. }
  4282. }
  4283. if (banner && (!abortButton || abortButton.disabled === false)) {
  4284. banner.className = stats.failedTests ? "qunit-fail" : "qunit-pass";
  4285. }
  4286. if (abortButton) {
  4287. abortButton.parentNode.removeChild(abortButton);
  4288. }
  4289. if (tests) {
  4290. id("qunit-testresult-display").innerHTML = html;
  4291. }
  4292. if (config.altertitle && document.title) {
  4293. // Show ✖ for good, ✔ for bad suite result in title
  4294. // use escape sequences in case file gets loaded with non-utf-8
  4295. // charset
  4296. document.title = [stats.failedTests ? "\u2716" : "\u2714", document.title.replace(/^[\u2714\u2716] /i, "")].join(" ");
  4297. }
  4298. // Scroll back to top to show results
  4299. if (config.scrolltop && window$1.scrollTo) {
  4300. window$1.scrollTo(0, 0);
  4301. }
  4302. });
  4303. function getNameHtml(name, module) {
  4304. var nameHtml = "";
  4305. if (module) {
  4306. nameHtml = "<span class='module-name'>" + escapeText(module) + "</span>: ";
  4307. }
  4308. nameHtml += "<span class='test-name'>" + escapeText(name) + "</span>";
  4309. return nameHtml;
  4310. }
  4311. QUnit.testStart(function (details) {
  4312. var running, bad;
  4313. appendTest(details.name, details.testId, details.module);
  4314. running = id("qunit-testresult-display");
  4315. if (running) {
  4316. addClass(running, "running");
  4317. bad = QUnit.config.reorder && details.previousFailure;
  4318. running.innerHTML = [bad ? "Rerunning previously failed test: <br />" : "Running: <br />", getNameHtml(details.name, details.module)].join("");
  4319. }
  4320. });
  4321. function stripHtml(string) {
  4322. // Strip tags, html entity and whitespaces
  4323. return string.replace(/<\/?[^>]+(>|$)/g, "").replace(/&quot;/g, "").replace(/\s+/g, "");
  4324. }
  4325. QUnit.log(function (details) {
  4326. var assertList,
  4327. assertLi,
  4328. message,
  4329. expected,
  4330. actual,
  4331. diff,
  4332. showDiff = false,
  4333. testItem = id("qunit-test-output-" + details.testId);
  4334. if (!testItem) {
  4335. return;
  4336. }
  4337. message = escapeText(details.message) || (details.result ? "okay" : "failed");
  4338. message = "<span class='test-message'>" + message + "</span>";
  4339. message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
  4340. // The pushFailure doesn't provide details.expected
  4341. // when it calls, it's implicit to also not show expected and diff stuff
  4342. // Also, we need to check details.expected existence, as it can exist and be undefined
  4343. if (!details.result && hasOwn.call(details, "expected")) {
  4344. if (details.negative) {
  4345. expected = "NOT " + QUnit.dump.parse(details.expected);
  4346. } else {
  4347. expected = QUnit.dump.parse(details.expected);
  4348. }
  4349. actual = QUnit.dump.parse(details.actual);
  4350. message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + escapeText(expected) + "</pre></td></tr>";
  4351. if (actual !== expected) {
  4352. message += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText(actual) + "</pre></td></tr>";
  4353. if (typeof details.actual === "number" && typeof details.expected === "number") {
  4354. if (!isNaN(details.actual) && !isNaN(details.expected)) {
  4355. showDiff = true;
  4356. diff = details.actual - details.expected;
  4357. diff = (diff > 0 ? "+" : "") + diff;
  4358. }
  4359. } else if (typeof details.actual !== "boolean" && typeof details.expected !== "boolean") {
  4360. diff = QUnit.diff(expected, actual);
  4361. // don't show diff if there is zero overlap
  4362. showDiff = stripHtml(diff).length !== stripHtml(expected).length + stripHtml(actual).length;
  4363. }
  4364. if (showDiff) {
  4365. message += "<tr class='test-diff'><th>Diff: </th><td><pre>" + diff + "</pre></td></tr>";
  4366. }
  4367. } else if (expected.indexOf("[object Array]") !== -1 || expected.indexOf("[object Object]") !== -1) {
  4368. message += "<tr class='test-message'><th>Message: </th><td>" + "Diff suppressed as the depth of object is more than current max depth (" + QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " + " run with a higher max depth or <a href='" + escapeText(setUrl({ maxDepth: -1 })) + "'>" + "Rerun</a> without max depth.</p></td></tr>";
  4369. } else {
  4370. message += "<tr class='test-message'><th>Message: </th><td>" + "Diff suppressed as the expected and actual results have an equivalent" + " serialization</td></tr>";
  4371. }
  4372. if (details.source) {
  4373. message += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText(details.source) + "</pre></td></tr>";
  4374. }
  4375. message += "</table>";
  4376. // This occurs when pushFailure is set and we have an extracted stack trace
  4377. } else if (!details.result && details.source) {
  4378. message += "<table>" + "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText(details.source) + "</pre></td></tr>" + "</table>";
  4379. }
  4380. assertList = testItem.getElementsByTagName("ol")[0];
  4381. assertLi = document.createElement("li");
  4382. assertLi.className = details.result ? "pass" : "fail";
  4383. assertLi.innerHTML = message;
  4384. assertList.appendChild(assertLi);
  4385. });
  4386. QUnit.testDone(function (details) {
  4387. var testTitle,
  4388. time,
  4389. testItem,
  4390. assertList,
  4391. status,
  4392. good,
  4393. bad,
  4394. testCounts,
  4395. skipped,
  4396. sourceName,
  4397. tests = id("qunit-tests");
  4398. if (!tests) {
  4399. return;
  4400. }
  4401. testItem = id("qunit-test-output-" + details.testId);
  4402. removeClass(testItem, "running");
  4403. if (details.failed > 0) {
  4404. status = "failed";
  4405. } else if (details.todo) {
  4406. status = "todo";
  4407. } else {
  4408. status = details.skipped ? "skipped" : "passed";
  4409. }
  4410. assertList = testItem.getElementsByTagName("ol")[0];
  4411. good = details.passed;
  4412. bad = details.failed;
  4413. // This test passed if it has no unexpected failed assertions
  4414. var testPassed = details.failed > 0 ? details.todo : !details.todo;
  4415. if (testPassed) {
  4416. // Collapse the passing tests
  4417. addClass(assertList, "qunit-collapsed");
  4418. } else if (config.collapse) {
  4419. if (!collapseNext) {
  4420. // Skip collapsing the first failing test
  4421. collapseNext = true;
  4422. } else {
  4423. // Collapse remaining tests
  4424. addClass(assertList, "qunit-collapsed");
  4425. }
  4426. }
  4427. // The testItem.firstChild is the test name
  4428. testTitle = testItem.firstChild;
  4429. testCounts = bad ? "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " : "";
  4430. testTitle.innerHTML += " <b class='counts'>(" + testCounts + details.assertions.length + ")</b>";
  4431. if (details.skipped) {
  4432. stats.skippedTests++;
  4433. testItem.className = "skipped";
  4434. skipped = document.createElement("em");
  4435. skipped.className = "qunit-skipped-label";
  4436. skipped.innerHTML = "skipped";
  4437. testItem.insertBefore(skipped, testTitle);
  4438. } else {
  4439. addEvent(testTitle, "click", function () {
  4440. toggleClass(assertList, "qunit-collapsed");
  4441. });
  4442. testItem.className = testPassed ? "pass" : "fail";
  4443. if (details.todo) {
  4444. var todoLabel = document.createElement("em");
  4445. todoLabel.className = "qunit-todo-label";
  4446. todoLabel.innerHTML = "todo";
  4447. testItem.className += " todo";
  4448. testItem.insertBefore(todoLabel, testTitle);
  4449. }
  4450. time = document.createElement("span");
  4451. time.className = "runtime";
  4452. time.innerHTML = details.runtime + " ms";
  4453. testItem.insertBefore(time, assertList);
  4454. if (!testPassed) {
  4455. stats.failedTests++;
  4456. } else if (details.todo) {
  4457. stats.todoTests++;
  4458. } else {
  4459. stats.passedTests++;
  4460. }
  4461. }
  4462. // Show the source of the test when showing assertions
  4463. if (details.source) {
  4464. sourceName = document.createElement("p");
  4465. sourceName.innerHTML = "<strong>Source: </strong>" + escapeText(details.source);
  4466. addClass(sourceName, "qunit-source");
  4467. if (testPassed) {
  4468. addClass(sourceName, "qunit-collapsed");
  4469. }
  4470. addEvent(testTitle, "click", function () {
  4471. toggleClass(sourceName, "qunit-collapsed");
  4472. });
  4473. testItem.appendChild(sourceName);
  4474. }
  4475. if (config.hidepassed && status === "passed") {
  4476. // use removeChild instead of remove because of support
  4477. hiddenTests.push(testItem);
  4478. tests.removeChild(testItem);
  4479. }
  4480. });
  4481. // Avoid readyState issue with phantomjs
  4482. // Ref: #818
  4483. var notPhantom = function (p) {
  4484. return !(p && p.version && p.version.major > 0);
  4485. }(window$1.phantom);
  4486. if (notPhantom && document.readyState === "complete") {
  4487. QUnit.load();
  4488. } else {
  4489. addEvent(window$1, "load", QUnit.load);
  4490. }
  4491. // Wrap window.onerror. We will call the original window.onerror to see if
  4492. // the existing handler fully handles the error; if not, we will call the
  4493. // QUnit.onError function.
  4494. var originalWindowOnError = window$1.onerror;
  4495. // Cover uncaught exceptions
  4496. // Returning true will suppress the default browser handler,
  4497. // returning false will let it run.
  4498. window$1.onerror = function (message, fileName, lineNumber, columnNumber, errorObj) {
  4499. var ret = false;
  4500. if (originalWindowOnError) {
  4501. for (var _len = arguments.length, args = Array(_len > 5 ? _len - 5 : 0), _key = 5; _key < _len; _key++) {
  4502. args[_key - 5] = arguments[_key];
  4503. }
  4504. ret = originalWindowOnError.call.apply(originalWindowOnError, [this, message, fileName, lineNumber, columnNumber, errorObj].concat(args));
  4505. }
  4506. // Treat return value as window.onerror itself does,
  4507. // Only do our handling if not suppressed.
  4508. if (ret !== true) {
  4509. var error = {
  4510. message: message,
  4511. fileName: fileName,
  4512. lineNumber: lineNumber
  4513. };
  4514. // According to
  4515. // https://blog.sentry.io/2016/01/04/client-javascript-reporting-window-onerror,
  4516. // most modern browsers support an errorObj argument; use that to
  4517. // get a full stack trace if it's available.
  4518. if (errorObj && errorObj.stack) {
  4519. error.stacktrace = extractStacktrace(errorObj, 0);
  4520. }
  4521. ret = QUnit.onError(error);
  4522. }
  4523. return ret;
  4524. };
  4525. // Listen for unhandled rejections, and call QUnit.onUnhandledRejection
  4526. window$1.addEventListener("unhandledrejection", function (event) {
  4527. QUnit.onUnhandledRejection(event.reason);
  4528. });
  4529. })();
  4530. /*
  4531. * This file is a modified version of google-diff-match-patch's JavaScript implementation
  4532. * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js),
  4533. * modifications are licensed as more fully set forth in LICENSE.txt.
  4534. *
  4535. * The original source of google-diff-match-patch is attributable and licensed as follows:
  4536. *
  4537. * Copyright 2006 Google Inc.
  4538. * https://code.google.com/p/google-diff-match-patch/
  4539. *
  4540. * Licensed under the Apache License, Version 2.0 (the "License");
  4541. * you may not use this file except in compliance with the License.
  4542. * You may obtain a copy of the License at
  4543. *
  4544. * https://www.apache.org/licenses/LICENSE-2.0
  4545. *
  4546. * Unless required by applicable law or agreed to in writing, software
  4547. * distributed under the License is distributed on an "AS IS" BASIS,
  4548. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4549. * See the License for the specific language governing permissions and
  4550. * limitations under the License.
  4551. *
  4552. * More Info:
  4553. * https://code.google.com/p/google-diff-match-patch/
  4554. *
  4555. * Usage: QUnit.diff(expected, actual)
  4556. *
  4557. */
  4558. QUnit.diff = function () {
  4559. function DiffMatchPatch() {}
  4560. // DIFF FUNCTIONS
  4561. /**
  4562. * The data structure representing a diff is an array of tuples:
  4563. * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
  4564. * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
  4565. */
  4566. var DIFF_DELETE = -1,
  4567. DIFF_INSERT = 1,
  4568. DIFF_EQUAL = 0;
  4569. /**
  4570. * Find the differences between two texts. Simplifies the problem by stripping
  4571. * any common prefix or suffix off the texts before diffing.
  4572. * @param {string} text1 Old string to be diffed.
  4573. * @param {string} text2 New string to be diffed.
  4574. * @param {boolean=} optChecklines Optional speedup flag. If present and false,
  4575. * then don't run a line-level diff first to identify the changed areas.
  4576. * Defaults to true, which does a faster, slightly less optimal diff.
  4577. * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
  4578. */
  4579. DiffMatchPatch.prototype.DiffMain = function (text1, text2, optChecklines) {
  4580. var deadline, checklines, commonlength, commonprefix, commonsuffix, diffs;
  4581. // The diff must be complete in up to 1 second.
  4582. deadline = new Date().getTime() + 1000;
  4583. // Check for null inputs.
  4584. if (text1 === null || text2 === null) {
  4585. throw new Error("Null input. (DiffMain)");
  4586. }
  4587. // Check for equality (speedup).
  4588. if (text1 === text2) {
  4589. if (text1) {
  4590. return [[DIFF_EQUAL, text1]];
  4591. }
  4592. return [];
  4593. }
  4594. if (typeof optChecklines === "undefined") {
  4595. optChecklines = true;
  4596. }
  4597. checklines = optChecklines;
  4598. // Trim off common prefix (speedup).
  4599. commonlength = this.diffCommonPrefix(text1, text2);
  4600. commonprefix = text1.substring(0, commonlength);
  4601. text1 = text1.substring(commonlength);
  4602. text2 = text2.substring(commonlength);
  4603. // Trim off common suffix (speedup).
  4604. commonlength = this.diffCommonSuffix(text1, text2);
  4605. commonsuffix = text1.substring(text1.length - commonlength);
  4606. text1 = text1.substring(0, text1.length - commonlength);
  4607. text2 = text2.substring(0, text2.length - commonlength);
  4608. // Compute the diff on the middle block.
  4609. diffs = this.diffCompute(text1, text2, checklines, deadline);
  4610. // Restore the prefix and suffix.
  4611. if (commonprefix) {
  4612. diffs.unshift([DIFF_EQUAL, commonprefix]);
  4613. }
  4614. if (commonsuffix) {
  4615. diffs.push([DIFF_EQUAL, commonsuffix]);
  4616. }
  4617. this.diffCleanupMerge(diffs);
  4618. return diffs;
  4619. };
  4620. /**
  4621. * Reduce the number of edits by eliminating operationally trivial equalities.
  4622. * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
  4623. */
  4624. DiffMatchPatch.prototype.diffCleanupEfficiency = function (diffs) {
  4625. var changes, equalities, equalitiesLength, lastequality, pointer, preIns, preDel, postIns, postDel;
  4626. changes = false;
  4627. equalities = []; // Stack of indices where equalities are found.
  4628. equalitiesLength = 0; // Keeping our own length var is faster in JS.
  4629. /** @type {?string} */
  4630. lastequality = null;
  4631. // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  4632. pointer = 0; // Index of current position.
  4633. // Is there an insertion operation before the last equality.
  4634. preIns = false;
  4635. // Is there a deletion operation before the last equality.
  4636. preDel = false;
  4637. // Is there an insertion operation after the last equality.
  4638. postIns = false;
  4639. // Is there a deletion operation after the last equality.
  4640. postDel = false;
  4641. while (pointer < diffs.length) {
  4642. // Equality found.
  4643. if (diffs[pointer][0] === DIFF_EQUAL) {
  4644. if (diffs[pointer][1].length < 4 && (postIns || postDel)) {
  4645. // Candidate found.
  4646. equalities[equalitiesLength++] = pointer;
  4647. preIns = postIns;
  4648. preDel = postDel;
  4649. lastequality = diffs[pointer][1];
  4650. } else {
  4651. // Not a candidate, and can never become one.
  4652. equalitiesLength = 0;
  4653. lastequality = null;
  4654. }
  4655. postIns = postDel = false;
  4656. // An insertion or deletion.
  4657. } else {
  4658. if (diffs[pointer][0] === DIFF_DELETE) {
  4659. postDel = true;
  4660. } else {
  4661. postIns = true;
  4662. }
  4663. /*
  4664. * Five types to be split:
  4665. * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
  4666. * <ins>A</ins>X<ins>C</ins><del>D</del>
  4667. * <ins>A</ins><del>B</del>X<ins>C</ins>
  4668. * <ins>A</del>X<ins>C</ins><del>D</del>
  4669. * <ins>A</ins><del>B</del>X<del>C</del>
  4670. */
  4671. if (lastequality && (preIns && preDel && postIns && postDel || lastequality.length < 2 && preIns + preDel + postIns + postDel === 3)) {
  4672. // Duplicate record.
  4673. diffs.splice(equalities[equalitiesLength - 1], 0, [DIFF_DELETE, lastequality]);
  4674. // Change second copy to insert.
  4675. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  4676. equalitiesLength--; // Throw away the equality we just deleted;
  4677. lastequality = null;
  4678. if (preIns && preDel) {
  4679. // No changes made which could affect previous entry, keep going.
  4680. postIns = postDel = true;
  4681. equalitiesLength = 0;
  4682. } else {
  4683. equalitiesLength--; // Throw away the previous equality.
  4684. pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
  4685. postIns = postDel = false;
  4686. }
  4687. changes = true;
  4688. }
  4689. }
  4690. pointer++;
  4691. }
  4692. if (changes) {
  4693. this.diffCleanupMerge(diffs);
  4694. }
  4695. };
  4696. /**
  4697. * Convert a diff array into a pretty HTML report.
  4698. * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
  4699. * @param {integer} string to be beautified.
  4700. * @return {string} HTML representation.
  4701. */
  4702. DiffMatchPatch.prototype.diffPrettyHtml = function (diffs) {
  4703. var op,
  4704. data,
  4705. x,
  4706. html = [];
  4707. for (x = 0; x < diffs.length; x++) {
  4708. op = diffs[x][0]; // Operation (insert, delete, equal)
  4709. data = diffs[x][1]; // Text of change.
  4710. switch (op) {
  4711. case DIFF_INSERT:
  4712. html[x] = "<ins>" + escapeText(data) + "</ins>";
  4713. break;
  4714. case DIFF_DELETE:
  4715. html[x] = "<del>" + escapeText(data) + "</del>";
  4716. break;
  4717. case DIFF_EQUAL:
  4718. html[x] = "<span>" + escapeText(data) + "</span>";
  4719. break;
  4720. }
  4721. }
  4722. return html.join("");
  4723. };
  4724. /**
  4725. * Determine the common prefix of two strings.
  4726. * @param {string} text1 First string.
  4727. * @param {string} text2 Second string.
  4728. * @return {number} The number of characters common to the start of each
  4729. * string.
  4730. */
  4731. DiffMatchPatch.prototype.diffCommonPrefix = function (text1, text2) {
  4732. var pointermid, pointermax, pointermin, pointerstart;
  4733. // Quick check for common null cases.
  4734. if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) {
  4735. return 0;
  4736. }
  4737. // Binary search.
  4738. // Performance analysis: https://neil.fraser.name/news/2007/10/09/
  4739. pointermin = 0;
  4740. pointermax = Math.min(text1.length, text2.length);
  4741. pointermid = pointermax;
  4742. pointerstart = 0;
  4743. while (pointermin < pointermid) {
  4744. if (text1.substring(pointerstart, pointermid) === text2.substring(pointerstart, pointermid)) {
  4745. pointermin = pointermid;
  4746. pointerstart = pointermin;
  4747. } else {
  4748. pointermax = pointermid;
  4749. }
  4750. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  4751. }
  4752. return pointermid;
  4753. };
  4754. /**
  4755. * Determine the common suffix of two strings.
  4756. * @param {string} text1 First string.
  4757. * @param {string} text2 Second string.
  4758. * @return {number} The number of characters common to the end of each string.
  4759. */
  4760. DiffMatchPatch.prototype.diffCommonSuffix = function (text1, text2) {
  4761. var pointermid, pointermax, pointermin, pointerend;
  4762. // Quick check for common null cases.
  4763. if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) {
  4764. return 0;
  4765. }
  4766. // Binary search.
  4767. // Performance analysis: https://neil.fraser.name/news/2007/10/09/
  4768. pointermin = 0;
  4769. pointermax = Math.min(text1.length, text2.length);
  4770. pointermid = pointermax;
  4771. pointerend = 0;
  4772. while (pointermin < pointermid) {
  4773. if (text1.substring(text1.length - pointermid, text1.length - pointerend) === text2.substring(text2.length - pointermid, text2.length - pointerend)) {
  4774. pointermin = pointermid;
  4775. pointerend = pointermin;
  4776. } else {
  4777. pointermax = pointermid;
  4778. }
  4779. pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
  4780. }
  4781. return pointermid;
  4782. };
  4783. /**
  4784. * Find the differences between two texts. Assumes that the texts do not
  4785. * have any common prefix or suffix.
  4786. * @param {string} text1 Old string to be diffed.
  4787. * @param {string} text2 New string to be diffed.
  4788. * @param {boolean} checklines Speedup flag. If false, then don't run a
  4789. * line-level diff first to identify the changed areas.
  4790. * If true, then run a faster, slightly less optimal diff.
  4791. * @param {number} deadline Time when the diff should be complete by.
  4792. * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
  4793. * @private
  4794. */
  4795. DiffMatchPatch.prototype.diffCompute = function (text1, text2, checklines, deadline) {
  4796. var diffs, longtext, shorttext, i, hm, text1A, text2A, text1B, text2B, midCommon, diffsA, diffsB;
  4797. if (!text1) {
  4798. // Just add some text (speedup).
  4799. return [[DIFF_INSERT, text2]];
  4800. }
  4801. if (!text2) {
  4802. // Just delete some text (speedup).
  4803. return [[DIFF_DELETE, text1]];
  4804. }
  4805. longtext = text1.length > text2.length ? text1 : text2;
  4806. shorttext = text1.length > text2.length ? text2 : text1;
  4807. i = longtext.indexOf(shorttext);
  4808. if (i !== -1) {
  4809. // Shorter text is inside the longer text (speedup).
  4810. diffs = [[DIFF_INSERT, longtext.substring(0, i)], [DIFF_EQUAL, shorttext], [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
  4811. // Swap insertions for deletions if diff is reversed.
  4812. if (text1.length > text2.length) {
  4813. diffs[0][0] = diffs[2][0] = DIFF_DELETE;
  4814. }
  4815. return diffs;
  4816. }
  4817. if (shorttext.length === 1) {
  4818. // Single character string.
  4819. // After the previous speedup, the character can't be an equality.
  4820. return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
  4821. }
  4822. // Check to see if the problem can be split in two.
  4823. hm = this.diffHalfMatch(text1, text2);
  4824. if (hm) {
  4825. // A half-match was found, sort out the return data.
  4826. text1A = hm[0];
  4827. text1B = hm[1];
  4828. text2A = hm[2];
  4829. text2B = hm[3];
  4830. midCommon = hm[4];
  4831. // Send both pairs off for separate processing.
  4832. diffsA = this.DiffMain(text1A, text2A, checklines, deadline);
  4833. diffsB = this.DiffMain(text1B, text2B, checklines, deadline);
  4834. // Merge the results.
  4835. return diffsA.concat([[DIFF_EQUAL, midCommon]], diffsB);
  4836. }
  4837. if (checklines && text1.length > 100 && text2.length > 100) {
  4838. return this.diffLineMode(text1, text2, deadline);
  4839. }
  4840. return this.diffBisect(text1, text2, deadline);
  4841. };
  4842. /**
  4843. * Do the two texts share a substring which is at least half the length of the
  4844. * longer text?
  4845. * This speedup can produce non-minimal diffs.
  4846. * @param {string} text1 First string.
  4847. * @param {string} text2 Second string.
  4848. * @return {Array.<string>} Five element Array, containing the prefix of
  4849. * text1, the suffix of text1, the prefix of text2, the suffix of
  4850. * text2 and the common middle. Or null if there was no match.
  4851. * @private
  4852. */
  4853. DiffMatchPatch.prototype.diffHalfMatch = function (text1, text2) {
  4854. var longtext, shorttext, dmp, text1A, text2B, text2A, text1B, midCommon, hm1, hm2, hm;
  4855. longtext = text1.length > text2.length ? text1 : text2;
  4856. shorttext = text1.length > text2.length ? text2 : text1;
  4857. if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
  4858. return null; // Pointless.
  4859. }
  4860. dmp = this; // 'this' becomes 'window' in a closure.
  4861. /**
  4862. * Does a substring of shorttext exist within longtext such that the substring
  4863. * is at least half the length of longtext?
  4864. * Closure, but does not reference any external variables.
  4865. * @param {string} longtext Longer string.
  4866. * @param {string} shorttext Shorter string.
  4867. * @param {number} i Start index of quarter length substring within longtext.
  4868. * @return {Array.<string>} Five element Array, containing the prefix of
  4869. * longtext, the suffix of longtext, the prefix of shorttext, the suffix
  4870. * of shorttext and the common middle. Or null if there was no match.
  4871. * @private
  4872. */
  4873. function diffHalfMatchI(longtext, shorttext, i) {
  4874. var seed, j, bestCommon, prefixLength, suffixLength, bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB;
  4875. // Start with a 1/4 length substring at position i as a seed.
  4876. seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
  4877. j = -1;
  4878. bestCommon = "";
  4879. while ((j = shorttext.indexOf(seed, j + 1)) !== -1) {
  4880. prefixLength = dmp.diffCommonPrefix(longtext.substring(i), shorttext.substring(j));
  4881. suffixLength = dmp.diffCommonSuffix(longtext.substring(0, i), shorttext.substring(0, j));
  4882. if (bestCommon.length < suffixLength + prefixLength) {
  4883. bestCommon = shorttext.substring(j - suffixLength, j) + shorttext.substring(j, j + prefixLength);
  4884. bestLongtextA = longtext.substring(0, i - suffixLength);
  4885. bestLongtextB = longtext.substring(i + prefixLength);
  4886. bestShorttextA = shorttext.substring(0, j - suffixLength);
  4887. bestShorttextB = shorttext.substring(j + prefixLength);
  4888. }
  4889. }
  4890. if (bestCommon.length * 2 >= longtext.length) {
  4891. return [bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB, bestCommon];
  4892. } else {
  4893. return null;
  4894. }
  4895. }
  4896. // First check if the second quarter is the seed for a half-match.
  4897. hm1 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 4));
  4898. // Check again based on the third quarter.
  4899. hm2 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 2));
  4900. if (!hm1 && !hm2) {
  4901. return null;
  4902. } else if (!hm2) {
  4903. hm = hm1;
  4904. } else if (!hm1) {
  4905. hm = hm2;
  4906. } else {
  4907. // Both matched. Select the longest.
  4908. hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
  4909. }
  4910. // A half-match was found, sort out the return data.
  4911. if (text1.length > text2.length) {
  4912. text1A = hm[0];
  4913. text1B = hm[1];
  4914. text2A = hm[2];
  4915. text2B = hm[3];
  4916. } else {
  4917. text2A = hm[0];
  4918. text2B = hm[1];
  4919. text1A = hm[2];
  4920. text1B = hm[3];
  4921. }
  4922. midCommon = hm[4];
  4923. return [text1A, text1B, text2A, text2B, midCommon];
  4924. };
  4925. /**
  4926. * Do a quick line-level diff on both strings, then rediff the parts for
  4927. * greater accuracy.
  4928. * This speedup can produce non-minimal diffs.
  4929. * @param {string} text1 Old string to be diffed.
  4930. * @param {string} text2 New string to be diffed.
  4931. * @param {number} deadline Time when the diff should be complete by.
  4932. * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
  4933. * @private
  4934. */
  4935. DiffMatchPatch.prototype.diffLineMode = function (text1, text2, deadline) {
  4936. var a, diffs, linearray, pointer, countInsert, countDelete, textInsert, textDelete, j;
  4937. // Scan the text on a line-by-line basis first.
  4938. a = this.diffLinesToChars(text1, text2);
  4939. text1 = a.chars1;
  4940. text2 = a.chars2;
  4941. linearray = a.lineArray;
  4942. diffs = this.DiffMain(text1, text2, false, deadline);
  4943. // Convert the diff back to original text.
  4944. this.diffCharsToLines(diffs, linearray);
  4945. // Eliminate freak matches (e.g. blank lines)
  4946. this.diffCleanupSemantic(diffs);
  4947. // Rediff any replacement blocks, this time character-by-character.
  4948. // Add a dummy entry at the end.
  4949. diffs.push([DIFF_EQUAL, ""]);
  4950. pointer = 0;
  4951. countDelete = 0;
  4952. countInsert = 0;
  4953. textDelete = "";
  4954. textInsert = "";
  4955. while (pointer < diffs.length) {
  4956. switch (diffs[pointer][0]) {
  4957. case DIFF_INSERT:
  4958. countInsert++;
  4959. textInsert += diffs[pointer][1];
  4960. break;
  4961. case DIFF_DELETE:
  4962. countDelete++;
  4963. textDelete += diffs[pointer][1];
  4964. break;
  4965. case DIFF_EQUAL:
  4966. // Upon reaching an equality, check for prior redundancies.
  4967. if (countDelete >= 1 && countInsert >= 1) {
  4968. // Delete the offending records and add the merged ones.
  4969. diffs.splice(pointer - countDelete - countInsert, countDelete + countInsert);
  4970. pointer = pointer - countDelete - countInsert;
  4971. a = this.DiffMain(textDelete, textInsert, false, deadline);
  4972. for (j = a.length - 1; j >= 0; j--) {
  4973. diffs.splice(pointer, 0, a[j]);
  4974. }
  4975. pointer = pointer + a.length;
  4976. }
  4977. countInsert = 0;
  4978. countDelete = 0;
  4979. textDelete = "";
  4980. textInsert = "";
  4981. break;
  4982. }
  4983. pointer++;
  4984. }
  4985. diffs.pop(); // Remove the dummy entry at the end.
  4986. return diffs;
  4987. };
  4988. /**
  4989. * Find the 'middle snake' of a diff, split the problem in two
  4990. * and return the recursively constructed diff.
  4991. * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
  4992. * @param {string} text1 Old string to be diffed.
  4993. * @param {string} text2 New string to be diffed.
  4994. * @param {number} deadline Time at which to bail if not yet complete.
  4995. * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
  4996. * @private
  4997. */
  4998. DiffMatchPatch.prototype.diffBisect = function (text1, text2, deadline) {
  4999. var text1Length, text2Length, maxD, vOffset, vLength, v1, v2, x, delta, front, k1start, k1end, k2start, k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2;
  5000. // Cache the text lengths to prevent multiple calls.
  5001. text1Length = text1.length;
  5002. text2Length = text2.length;
  5003. maxD = Math.ceil((text1Length + text2Length) / 2);
  5004. vOffset = maxD;
  5005. vLength = 2 * maxD;
  5006. v1 = new Array(vLength);
  5007. v2 = new Array(vLength);
  5008. // Setting all elements to -1 is faster in Chrome & Firefox than mixing
  5009. // integers and undefined.
  5010. for (x = 0; x < vLength; x++) {
  5011. v1[x] = -1;
  5012. v2[x] = -1;
  5013. }
  5014. v1[vOffset + 1] = 0;
  5015. v2[vOffset + 1] = 0;
  5016. delta = text1Length - text2Length;
  5017. // If the total number of characters is odd, then the front path will collide
  5018. // with the reverse path.
  5019. front = delta % 2 !== 0;
  5020. // Offsets for start and end of k loop.
  5021. // Prevents mapping of space beyond the grid.
  5022. k1start = 0;
  5023. k1end = 0;
  5024. k2start = 0;
  5025. k2end = 0;
  5026. for (d = 0; d < maxD; d++) {
  5027. // Bail out if deadline is reached.
  5028. if (new Date().getTime() > deadline) {
  5029. break;
  5030. }
  5031. // Walk the front path one step.
  5032. for (k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
  5033. k1Offset = vOffset + k1;
  5034. if (k1 === -d || k1 !== d && v1[k1Offset - 1] < v1[k1Offset + 1]) {
  5035. x1 = v1[k1Offset + 1];
  5036. } else {
  5037. x1 = v1[k1Offset - 1] + 1;
  5038. }
  5039. y1 = x1 - k1;
  5040. while (x1 < text1Length && y1 < text2Length && text1.charAt(x1) === text2.charAt(y1)) {
  5041. x1++;
  5042. y1++;
  5043. }
  5044. v1[k1Offset] = x1;
  5045. if (x1 > text1Length) {
  5046. // Ran off the right of the graph.
  5047. k1end += 2;
  5048. } else if (y1 > text2Length) {
  5049. // Ran off the bottom of the graph.
  5050. k1start += 2;
  5051. } else if (front) {
  5052. k2Offset = vOffset + delta - k1;
  5053. if (k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] !== -1) {
  5054. // Mirror x2 onto top-left coordinate system.
  5055. x2 = text1Length - v2[k2Offset];
  5056. if (x1 >= x2) {
  5057. // Overlap detected.
  5058. return this.diffBisectSplit(text1, text2, x1, y1, deadline);
  5059. }
  5060. }
  5061. }
  5062. }
  5063. // Walk the reverse path one step.
  5064. for (k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
  5065. k2Offset = vOffset + k2;
  5066. if (k2 === -d || k2 !== d && v2[k2Offset - 1] < v2[k2Offset + 1]) {
  5067. x2 = v2[k2Offset + 1];
  5068. } else {
  5069. x2 = v2[k2Offset - 1] + 1;
  5070. }
  5071. y2 = x2 - k2;
  5072. while (x2 < text1Length && y2 < text2Length && text1.charAt(text1Length - x2 - 1) === text2.charAt(text2Length - y2 - 1)) {
  5073. x2++;
  5074. y2++;
  5075. }
  5076. v2[k2Offset] = x2;
  5077. if (x2 > text1Length) {
  5078. // Ran off the left of the graph.
  5079. k2end += 2;
  5080. } else if (y2 > text2Length) {
  5081. // Ran off the top of the graph.
  5082. k2start += 2;
  5083. } else if (!front) {
  5084. k1Offset = vOffset + delta - k2;
  5085. if (k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] !== -1) {
  5086. x1 = v1[k1Offset];
  5087. y1 = vOffset + x1 - k1Offset;
  5088. // Mirror x2 onto top-left coordinate system.
  5089. x2 = text1Length - x2;
  5090. if (x1 >= x2) {
  5091. // Overlap detected.
  5092. return this.diffBisectSplit(text1, text2, x1, y1, deadline);
  5093. }
  5094. }
  5095. }
  5096. }
  5097. }
  5098. // Diff took too long and hit the deadline or
  5099. // number of diffs equals number of characters, no commonality at all.
  5100. return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
  5101. };
  5102. /**
  5103. * Given the location of the 'middle snake', split the diff in two parts
  5104. * and recurse.
  5105. * @param {string} text1 Old string to be diffed.
  5106. * @param {string} text2 New string to be diffed.
  5107. * @param {number} x Index of split point in text1.
  5108. * @param {number} y Index of split point in text2.
  5109. * @param {number} deadline Time at which to bail if not yet complete.
  5110. * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
  5111. * @private
  5112. */
  5113. DiffMatchPatch.prototype.diffBisectSplit = function (text1, text2, x, y, deadline) {
  5114. var text1a, text1b, text2a, text2b, diffs, diffsb;
  5115. text1a = text1.substring(0, x);
  5116. text2a = text2.substring(0, y);
  5117. text1b = text1.substring(x);
  5118. text2b = text2.substring(y);
  5119. // Compute both diffs serially.
  5120. diffs = this.DiffMain(text1a, text2a, false, deadline);
  5121. diffsb = this.DiffMain(text1b, text2b, false, deadline);
  5122. return diffs.concat(diffsb);
  5123. };
  5124. /**
  5125. * Reduce the number of edits by eliminating semantically trivial equalities.
  5126. * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
  5127. */
  5128. DiffMatchPatch.prototype.diffCleanupSemantic = function (diffs) {
  5129. var changes, equalities, equalitiesLength, lastequality, pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1, lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2;
  5130. changes = false;
  5131. equalities = []; // Stack of indices where equalities are found.
  5132. equalitiesLength = 0; // Keeping our own length var is faster in JS.
  5133. /** @type {?string} */
  5134. lastequality = null;
  5135. // Always equal to diffs[equalities[equalitiesLength - 1]][1]
  5136. pointer = 0; // Index of current position.
  5137. // Number of characters that changed prior to the equality.
  5138. lengthInsertions1 = 0;
  5139. lengthDeletions1 = 0;
  5140. // Number of characters that changed after the equality.
  5141. lengthInsertions2 = 0;
  5142. lengthDeletions2 = 0;
  5143. while (pointer < diffs.length) {
  5144. if (diffs[pointer][0] === DIFF_EQUAL) {
  5145. // Equality found.
  5146. equalities[equalitiesLength++] = pointer;
  5147. lengthInsertions1 = lengthInsertions2;
  5148. lengthDeletions1 = lengthDeletions2;
  5149. lengthInsertions2 = 0;
  5150. lengthDeletions2 = 0;
  5151. lastequality = diffs[pointer][1];
  5152. } else {
  5153. // An insertion or deletion.
  5154. if (diffs[pointer][0] === DIFF_INSERT) {
  5155. lengthInsertions2 += diffs[pointer][1].length;
  5156. } else {
  5157. lengthDeletions2 += diffs[pointer][1].length;
  5158. }
  5159. // Eliminate an equality that is smaller or equal to the edits on both
  5160. // sides of it.
  5161. if (lastequality && lastequality.length <= Math.max(lengthInsertions1, lengthDeletions1) && lastequality.length <= Math.max(lengthInsertions2, lengthDeletions2)) {
  5162. // Duplicate record.
  5163. diffs.splice(equalities[equalitiesLength - 1], 0, [DIFF_DELETE, lastequality]);
  5164. // Change second copy to insert.
  5165. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
  5166. // Throw away the equality we just deleted.
  5167. equalitiesLength--;
  5168. // Throw away the previous equality (it needs to be reevaluated).
  5169. equalitiesLength--;
  5170. pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
  5171. // Reset the counters.
  5172. lengthInsertions1 = 0;
  5173. lengthDeletions1 = 0;
  5174. lengthInsertions2 = 0;
  5175. lengthDeletions2 = 0;
  5176. lastequality = null;
  5177. changes = true;
  5178. }
  5179. }
  5180. pointer++;
  5181. }
  5182. // Normalize the diff.
  5183. if (changes) {
  5184. this.diffCleanupMerge(diffs);
  5185. }
  5186. // Find any overlaps between deletions and insertions.
  5187. // e.g: <del>abcxxx</del><ins>xxxdef</ins>
  5188. // -> <del>abc</del>xxx<ins>def</ins>
  5189. // e.g: <del>xxxabc</del><ins>defxxx</ins>
  5190. // -> <ins>def</ins>xxx<del>abc</del>
  5191. // Only extract an overlap if it is as big as the edit ahead or behind it.
  5192. pointer = 1;
  5193. while (pointer < diffs.length) {
  5194. if (diffs[pointer - 1][0] === DIFF_DELETE && diffs[pointer][0] === DIFF_INSERT) {
  5195. deletion = diffs[pointer - 1][1];
  5196. insertion = diffs[pointer][1];
  5197. overlapLength1 = this.diffCommonOverlap(deletion, insertion);
  5198. overlapLength2 = this.diffCommonOverlap(insertion, deletion);
  5199. if (overlapLength1 >= overlapLength2) {
  5200. if (overlapLength1 >= deletion.length / 2 || overlapLength1 >= insertion.length / 2) {
  5201. // Overlap found. Insert an equality and trim the surrounding edits.
  5202. diffs.splice(pointer, 0, [DIFF_EQUAL, insertion.substring(0, overlapLength1)]);
  5203. diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlapLength1);
  5204. diffs[pointer + 1][1] = insertion.substring(overlapLength1);
  5205. pointer++;
  5206. }
  5207. } else {
  5208. if (overlapLength2 >= deletion.length / 2 || overlapLength2 >= insertion.length / 2) {
  5209. // Reverse overlap found.
  5210. // Insert an equality and swap and trim the surrounding edits.
  5211. diffs.splice(pointer, 0, [DIFF_EQUAL, deletion.substring(0, overlapLength2)]);
  5212. diffs[pointer - 1][0] = DIFF_INSERT;
  5213. diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlapLength2);
  5214. diffs[pointer + 1][0] = DIFF_DELETE;
  5215. diffs[pointer + 1][1] = deletion.substring(overlapLength2);
  5216. pointer++;
  5217. }
  5218. }
  5219. pointer++;
  5220. }
  5221. pointer++;
  5222. }
  5223. };
  5224. /**
  5225. * Determine if the suffix of one string is the prefix of another.
  5226. * @param {string} text1 First string.
  5227. * @param {string} text2 Second string.
  5228. * @return {number} The number of characters common to the end of the first
  5229. * string and the start of the second string.
  5230. * @private
  5231. */
  5232. DiffMatchPatch.prototype.diffCommonOverlap = function (text1, text2) {
  5233. var text1Length, text2Length, textLength, best, length, pattern, found;
  5234. // Cache the text lengths to prevent multiple calls.
  5235. text1Length = text1.length;
  5236. text2Length = text2.length;
  5237. // Eliminate the null case.
  5238. if (text1Length === 0 || text2Length === 0) {
  5239. return 0;
  5240. }
  5241. // Truncate the longer string.
  5242. if (text1Length > text2Length) {
  5243. text1 = text1.substring(text1Length - text2Length);
  5244. } else if (text1Length < text2Length) {
  5245. text2 = text2.substring(0, text1Length);
  5246. }
  5247. textLength = Math.min(text1Length, text2Length);
  5248. // Quick check for the worst case.
  5249. if (text1 === text2) {
  5250. return textLength;
  5251. }
  5252. // Start by looking for a single character match
  5253. // and increase length until no match is found.
  5254. // Performance analysis: https://neil.fraser.name/news/2010/11/04/
  5255. best = 0;
  5256. length = 1;
  5257. while (true) {
  5258. pattern = text1.substring(textLength - length);
  5259. found = text2.indexOf(pattern);
  5260. if (found === -1) {
  5261. return best;
  5262. }
  5263. length += found;
  5264. if (found === 0 || text1.substring(textLength - length) === text2.substring(0, length)) {
  5265. best = length;
  5266. length++;
  5267. }
  5268. }
  5269. };
  5270. /**
  5271. * Split two texts into an array of strings. Reduce the texts to a string of
  5272. * hashes where each Unicode character represents one line.
  5273. * @param {string} text1 First string.
  5274. * @param {string} text2 Second string.
  5275. * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
  5276. * An object containing the encoded text1, the encoded text2 and
  5277. * the array of unique strings.
  5278. * The zeroth element of the array of unique strings is intentionally blank.
  5279. * @private
  5280. */
  5281. DiffMatchPatch.prototype.diffLinesToChars = function (text1, text2) {
  5282. var lineArray, lineHash, chars1, chars2;
  5283. lineArray = []; // E.g. lineArray[4] === 'Hello\n'
  5284. lineHash = {}; // E.g. lineHash['Hello\n'] === 4
  5285. // '\x00' is a valid character, but various debuggers don't like it.
  5286. // So we'll insert a junk entry to avoid generating a null character.
  5287. lineArray[0] = "";
  5288. /**
  5289. * Split a text into an array of strings. Reduce the texts to a string of
  5290. * hashes where each Unicode character represents one line.
  5291. * Modifies linearray and linehash through being a closure.
  5292. * @param {string} text String to encode.
  5293. * @return {string} Encoded string.
  5294. * @private
  5295. */
  5296. function diffLinesToCharsMunge(text) {
  5297. var chars, lineStart, lineEnd, lineArrayLength, line;
  5298. chars = "";
  5299. // Walk the text, pulling out a substring for each line.
  5300. // text.split('\n') would would temporarily double our memory footprint.
  5301. // Modifying text would create many large strings to garbage collect.
  5302. lineStart = 0;
  5303. lineEnd = -1;
  5304. // Keeping our own length variable is faster than looking it up.
  5305. lineArrayLength = lineArray.length;
  5306. while (lineEnd < text.length - 1) {
  5307. lineEnd = text.indexOf("\n", lineStart);
  5308. if (lineEnd === -1) {
  5309. lineEnd = text.length - 1;
  5310. }
  5311. line = text.substring(lineStart, lineEnd + 1);
  5312. lineStart = lineEnd + 1;
  5313. var lineHashExists = lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : lineHash[line] !== undefined;
  5314. if (lineHashExists) {
  5315. chars += String.fromCharCode(lineHash[line]);
  5316. } else {
  5317. chars += String.fromCharCode(lineArrayLength);
  5318. lineHash[line] = lineArrayLength;
  5319. lineArray[lineArrayLength++] = line;
  5320. }
  5321. }
  5322. return chars;
  5323. }
  5324. chars1 = diffLinesToCharsMunge(text1);
  5325. chars2 = diffLinesToCharsMunge(text2);
  5326. return {
  5327. chars1: chars1,
  5328. chars2: chars2,
  5329. lineArray: lineArray
  5330. };
  5331. };
  5332. /**
  5333. * Rehydrate the text in a diff from a string of line hashes to real lines of
  5334. * text.
  5335. * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
  5336. * @param {!Array.<string>} lineArray Array of unique strings.
  5337. * @private
  5338. */
  5339. DiffMatchPatch.prototype.diffCharsToLines = function (diffs, lineArray) {
  5340. var x, chars, text, y;
  5341. for (x = 0; x < diffs.length; x++) {
  5342. chars = diffs[x][1];
  5343. text = [];
  5344. for (y = 0; y < chars.length; y++) {
  5345. text[y] = lineArray[chars.charCodeAt(y)];
  5346. }
  5347. diffs[x][1] = text.join("");
  5348. }
  5349. };
  5350. /**
  5351. * Reorder and merge like edit sections. Merge equalities.
  5352. * Any edit section can move as long as it doesn't cross an equality.
  5353. * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
  5354. */
  5355. DiffMatchPatch.prototype.diffCleanupMerge = function (diffs) {
  5356. var pointer, countDelete, countInsert, textInsert, textDelete, commonlength, changes, diffPointer, position;
  5357. diffs.push([DIFF_EQUAL, ""]); // Add a dummy entry at the end.
  5358. pointer = 0;
  5359. countDelete = 0;
  5360. countInsert = 0;
  5361. textDelete = "";
  5362. textInsert = "";
  5363. while (pointer < diffs.length) {
  5364. switch (diffs[pointer][0]) {
  5365. case DIFF_INSERT:
  5366. countInsert++;
  5367. textInsert += diffs[pointer][1];
  5368. pointer++;
  5369. break;
  5370. case DIFF_DELETE:
  5371. countDelete++;
  5372. textDelete += diffs[pointer][1];
  5373. pointer++;
  5374. break;
  5375. case DIFF_EQUAL:
  5376. // Upon reaching an equality, check for prior redundancies.
  5377. if (countDelete + countInsert > 1) {
  5378. if (countDelete !== 0 && countInsert !== 0) {
  5379. // Factor out any common prefixes.
  5380. commonlength = this.diffCommonPrefix(textInsert, textDelete);
  5381. if (commonlength !== 0) {
  5382. if (pointer - countDelete - countInsert > 0 && diffs[pointer - countDelete - countInsert - 1][0] === DIFF_EQUAL) {
  5383. diffs[pointer - countDelete - countInsert - 1][1] += textInsert.substring(0, commonlength);
  5384. } else {
  5385. diffs.splice(0, 0, [DIFF_EQUAL, textInsert.substring(0, commonlength)]);
  5386. pointer++;
  5387. }
  5388. textInsert = textInsert.substring(commonlength);
  5389. textDelete = textDelete.substring(commonlength);
  5390. }
  5391. // Factor out any common suffixies.
  5392. commonlength = this.diffCommonSuffix(textInsert, textDelete);
  5393. if (commonlength !== 0) {
  5394. diffs[pointer][1] = textInsert.substring(textInsert.length - commonlength) + diffs[pointer][1];
  5395. textInsert = textInsert.substring(0, textInsert.length - commonlength);
  5396. textDelete = textDelete.substring(0, textDelete.length - commonlength);
  5397. }
  5398. }
  5399. // Delete the offending records and add the merged ones.
  5400. if (countDelete === 0) {
  5401. diffs.splice(pointer - countInsert, countDelete + countInsert, [DIFF_INSERT, textInsert]);
  5402. } else if (countInsert === 0) {
  5403. diffs.splice(pointer - countDelete, countDelete + countInsert, [DIFF_DELETE, textDelete]);
  5404. } else {
  5405. diffs.splice(pointer - countDelete - countInsert, countDelete + countInsert, [DIFF_DELETE, textDelete], [DIFF_INSERT, textInsert]);
  5406. }
  5407. pointer = pointer - countDelete - countInsert + (countDelete ? 1 : 0) + (countInsert ? 1 : 0) + 1;
  5408. } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
  5409. // Merge this equality with the previous one.
  5410. diffs[pointer - 1][1] += diffs[pointer][1];
  5411. diffs.splice(pointer, 1);
  5412. } else {
  5413. pointer++;
  5414. }
  5415. countInsert = 0;
  5416. countDelete = 0;
  5417. textDelete = "";
  5418. textInsert = "";
  5419. break;
  5420. }
  5421. }
  5422. if (diffs[diffs.length - 1][1] === "") {
  5423. diffs.pop(); // Remove the dummy entry at the end.
  5424. }
  5425. // Second pass: look for single edits surrounded on both sides by equalities
  5426. // which can be shifted sideways to eliminate an equality.
  5427. // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
  5428. changes = false;
  5429. pointer = 1;
  5430. // Intentionally ignore the first and last element (don't need checking).
  5431. while (pointer < diffs.length - 1) {
  5432. if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
  5433. diffPointer = diffs[pointer][1];
  5434. position = diffPointer.substring(diffPointer.length - diffs[pointer - 1][1].length);
  5435. // This is a single edit surrounded by equalities.
  5436. if (position === diffs[pointer - 1][1]) {
  5437. // Shift the edit over the previous equality.
  5438. diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length);
  5439. diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
  5440. diffs.splice(pointer - 1, 1);
  5441. changes = true;
  5442. } else if (diffPointer.substring(0, diffs[pointer + 1][1].length) === diffs[pointer + 1][1]) {
  5443. // Shift the edit over the next equality.
  5444. diffs[pointer - 1][1] += diffs[pointer + 1][1];
  5445. diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1];
  5446. diffs.splice(pointer + 1, 1);
  5447. changes = true;
  5448. }
  5449. }
  5450. pointer++;
  5451. }
  5452. // If shifts were made, the diff needs reordering and another shift sweep.
  5453. if (changes) {
  5454. this.diffCleanupMerge(diffs);
  5455. }
  5456. };
  5457. return function (o, n) {
  5458. var diff, output, text;
  5459. diff = new DiffMatchPatch();
  5460. output = diff.DiffMain(o, n);
  5461. diff.diffCleanupEfficiency(output);
  5462. text = diff.diffPrettyHtml(output);
  5463. return text;
  5464. };
  5465. }();
  5466. }((function() { return this; }())));