jasmine.js 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478
  1. var isCommonJS = typeof window == "undefined";
  2. /**
  3. * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
  4. *
  5. * @namespace
  6. */
  7. var jasmine = {};
  8. if (isCommonJS) exports.jasmine = jasmine;
  9. /**
  10. * @private
  11. */
  12. jasmine.unimplementedMethod_ = function() {
  13. throw new Error("unimplemented method");
  14. };
  15. /**
  16. * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
  17. * a plain old variable and may be redefined by somebody else.
  18. *
  19. * @private
  20. */
  21. jasmine.undefined = jasmine.___undefined___;
  22. /**
  23. * Show diagnostic messages in the console if set to true
  24. *
  25. */
  26. jasmine.VERBOSE = false;
  27. /**
  28. * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
  29. *
  30. */
  31. jasmine.DEFAULT_UPDATE_INTERVAL = 250;
  32. /**
  33. * Default timeout interval in milliseconds for waitsFor() blocks.
  34. */
  35. jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
  36. jasmine.getGlobal = function() {
  37. function getGlobal() {
  38. return this;
  39. }
  40. return getGlobal();
  41. };
  42. /**
  43. * Allows for bound functions to be compared. Internal use only.
  44. *
  45. * @ignore
  46. * @private
  47. * @param base {Object} bound 'this' for the function
  48. * @param name {Function} function to find
  49. */
  50. jasmine.bindOriginal_ = function(base, name) {
  51. var original = base[name];
  52. if (original.apply) {
  53. return function() {
  54. return original.apply(base, arguments);
  55. };
  56. } else {
  57. // IE support
  58. return jasmine.getGlobal()[name];
  59. }
  60. };
  61. jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
  62. jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
  63. jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
  64. jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
  65. jasmine.MessageResult = function(values) {
  66. this.type = 'log';
  67. this.values = values;
  68. this.trace = new Error(); // todo: test better
  69. };
  70. jasmine.MessageResult.prototype.toString = function() {
  71. var text = "";
  72. for (var i = 0; i < this.values.length; i++) {
  73. if (i > 0) text += " ";
  74. if (jasmine.isString_(this.values[i])) {
  75. text += this.values[i];
  76. } else {
  77. text += jasmine.pp(this.values[i]);
  78. }
  79. }
  80. return text;
  81. };
  82. jasmine.ExpectationResult = function(params) {
  83. this.type = 'expect';
  84. this.matcherName = params.matcherName;
  85. this.passed_ = params.passed;
  86. this.expected = params.expected;
  87. this.actual = params.actual;
  88. this.message = this.passed_ ? 'Passed.' : params.message;
  89. var trace = (params.trace || new Error(this.message));
  90. this.trace = this.passed_ ? '' : trace;
  91. };
  92. jasmine.ExpectationResult.prototype.toString = function () {
  93. return this.message;
  94. };
  95. jasmine.ExpectationResult.prototype.passed = function () {
  96. return this.passed_;
  97. };
  98. /**
  99. * Getter for the Jasmine environment. Ensures one gets created
  100. */
  101. jasmine.getEnv = function() {
  102. var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
  103. return env;
  104. };
  105. /**
  106. * @ignore
  107. * @private
  108. * @param value
  109. * @returns {Boolean}
  110. */
  111. jasmine.isArray_ = function(value) {
  112. return jasmine.isA_("Array", value);
  113. };
  114. /**
  115. * @ignore
  116. * @private
  117. * @param value
  118. * @returns {Boolean}
  119. */
  120. jasmine.isString_ = function(value) {
  121. return jasmine.isA_("String", value);
  122. };
  123. /**
  124. * @ignore
  125. * @private
  126. * @param value
  127. * @returns {Boolean}
  128. */
  129. jasmine.isNumber_ = function(value) {
  130. return jasmine.isA_("Number", value);
  131. };
  132. /**
  133. * @ignore
  134. * @private
  135. * @param {String} typeName
  136. * @param value
  137. * @returns {Boolean}
  138. */
  139. jasmine.isA_ = function(typeName, value) {
  140. return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
  141. };
  142. /**
  143. * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
  144. *
  145. * @param value {Object} an object to be outputted
  146. * @returns {String}
  147. */
  148. jasmine.pp = function(value) {
  149. var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
  150. stringPrettyPrinter.format(value);
  151. return stringPrettyPrinter.string;
  152. };
  153. /**
  154. * Returns true if the object is a DOM Node.
  155. *
  156. * @param {Object} obj object to check
  157. * @returns {Boolean}
  158. */
  159. jasmine.isDomNode = function(obj) {
  160. return obj.nodeType > 0;
  161. };
  162. /**
  163. * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
  164. *
  165. * @example
  166. * // don't care about which function is passed in, as long as it's a function
  167. * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
  168. *
  169. * @param {Class} clazz
  170. * @returns matchable object of the type clazz
  171. */
  172. jasmine.any = function(clazz) {
  173. return new jasmine.Matchers.Any(clazz);
  174. };
  175. /**
  176. * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
  177. *
  178. * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
  179. * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
  180. *
  181. * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
  182. *
  183. * Spies are torn down at the end of every spec.
  184. *
  185. * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
  186. *
  187. * @example
  188. * // a stub
  189. * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
  190. *
  191. * // spy example
  192. * var foo = {
  193. * not: function(bool) { return !bool; }
  194. * }
  195. *
  196. * // actual foo.not will not be called, execution stops
  197. * spyOn(foo, 'not');
  198. // foo.not spied upon, execution will continue to implementation
  199. * spyOn(foo, 'not').andCallThrough();
  200. *
  201. * // fake example
  202. * var foo = {
  203. * not: function(bool) { return !bool; }
  204. * }
  205. *
  206. * // foo.not(val) will return val
  207. * spyOn(foo, 'not').andCallFake(function(value) {return value;});
  208. *
  209. * // mock example
  210. * foo.not(7 == 7);
  211. * expect(foo.not).toHaveBeenCalled();
  212. * expect(foo.not).toHaveBeenCalledWith(true);
  213. *
  214. * @constructor
  215. * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
  216. * @param {String} name
  217. */
  218. jasmine.Spy = function(name) {
  219. /**
  220. * The name of the spy, if provided.
  221. */
  222. this.identity = name || 'unknown';
  223. /**
  224. * Is this Object a spy?
  225. */
  226. this.isSpy = true;
  227. /**
  228. * The actual function this spy stubs.
  229. */
  230. this.plan = function() {
  231. };
  232. /**
  233. * Tracking of the most recent call to the spy.
  234. * @example
  235. * var mySpy = jasmine.createSpy('foo');
  236. * mySpy(1, 2);
  237. * mySpy.mostRecentCall.args = [1, 2];
  238. */
  239. this.mostRecentCall = {};
  240. /**
  241. * Holds arguments for each call to the spy, indexed by call count
  242. * @example
  243. * var mySpy = jasmine.createSpy('foo');
  244. * mySpy(1, 2);
  245. * mySpy(7, 8);
  246. * mySpy.mostRecentCall.args = [7, 8];
  247. * mySpy.argsForCall[0] = [1, 2];
  248. * mySpy.argsForCall[1] = [7, 8];
  249. */
  250. this.argsForCall = [];
  251. this.calls = [];
  252. };
  253. /**
  254. * Tells a spy to call through to the actual implemenatation.
  255. *
  256. * @example
  257. * var foo = {
  258. * bar: function() { // do some stuff }
  259. * }
  260. *
  261. * // defining a spy on an existing property: foo.bar
  262. * spyOn(foo, 'bar').andCallThrough();
  263. */
  264. jasmine.Spy.prototype.andCallThrough = function() {
  265. this.plan = this.originalValue;
  266. return this;
  267. };
  268. /**
  269. * For setting the return value of a spy.
  270. *
  271. * @example
  272. * // defining a spy from scratch: foo() returns 'baz'
  273. * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
  274. *
  275. * // defining a spy on an existing property: foo.bar() returns 'baz'
  276. * spyOn(foo, 'bar').andReturn('baz');
  277. *
  278. * @param {Object} value
  279. */
  280. jasmine.Spy.prototype.andReturn = function(value) {
  281. this.plan = function() {
  282. return value;
  283. };
  284. return this;
  285. };
  286. /**
  287. * For throwing an exception when a spy is called.
  288. *
  289. * @example
  290. * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
  291. * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
  292. *
  293. * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
  294. * spyOn(foo, 'bar').andThrow('baz');
  295. *
  296. * @param {String} exceptionMsg
  297. */
  298. jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
  299. this.plan = function() {
  300. throw exceptionMsg;
  301. };
  302. return this;
  303. };
  304. /**
  305. * Calls an alternate implementation when a spy is called.
  306. *
  307. * @example
  308. * var baz = function() {
  309. * // do some stuff, return something
  310. * }
  311. * // defining a spy from scratch: foo() calls the function baz
  312. * var foo = jasmine.createSpy('spy on foo').andCall(baz);
  313. *
  314. * // defining a spy on an existing property: foo.bar() calls an anonymnous function
  315. * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
  316. *
  317. * @param {Function} fakeFunc
  318. */
  319. jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
  320. this.plan = fakeFunc;
  321. return this;
  322. };
  323. /**
  324. * Resets all of a spy's the tracking variables so that it can be used again.
  325. *
  326. * @example
  327. * spyOn(foo, 'bar');
  328. *
  329. * foo.bar();
  330. *
  331. * expect(foo.bar.callCount).toEqual(1);
  332. *
  333. * foo.bar.reset();
  334. *
  335. * expect(foo.bar.callCount).toEqual(0);
  336. */
  337. jasmine.Spy.prototype.reset = function() {
  338. this.wasCalled = false;
  339. this.callCount = 0;
  340. this.argsForCall = [];
  341. this.calls = [];
  342. this.mostRecentCall = {};
  343. };
  344. jasmine.createSpy = function(name) {
  345. var spyObj = function() {
  346. spyObj.wasCalled = true;
  347. spyObj.callCount++;
  348. var args = jasmine.util.argsToArray(arguments);
  349. spyObj.mostRecentCall.object = this;
  350. spyObj.mostRecentCall.args = args;
  351. spyObj.argsForCall.push(args);
  352. spyObj.calls.push({object: this, args: args});
  353. return spyObj.plan.apply(this, arguments);
  354. };
  355. var spy = new jasmine.Spy(name);
  356. for (var prop in spy) {
  357. spyObj[prop] = spy[prop];
  358. }
  359. spyObj.reset();
  360. return spyObj;
  361. };
  362. /**
  363. * Determines whether an object is a spy.
  364. *
  365. * @param {jasmine.Spy|Object} putativeSpy
  366. * @returns {Boolean}
  367. */
  368. jasmine.isSpy = function(putativeSpy) {
  369. return putativeSpy && putativeSpy.isSpy;
  370. };
  371. /**
  372. * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
  373. * large in one call.
  374. *
  375. * @param {String} baseName name of spy class
  376. * @param {Array} methodNames array of names of methods to make spies
  377. */
  378. jasmine.createSpyObj = function(baseName, methodNames) {
  379. if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
  380. throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
  381. }
  382. var obj = {};
  383. for (var i = 0; i < methodNames.length; i++) {
  384. obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
  385. }
  386. return obj;
  387. };
  388. /**
  389. * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
  390. *
  391. * Be careful not to leave calls to <code>jasmine.log</code> in production code.
  392. */
  393. jasmine.log = function() {
  394. var spec = jasmine.getEnv().currentSpec;
  395. spec.log.apply(spec, arguments);
  396. };
  397. /**
  398. * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
  399. *
  400. * @example
  401. * // spy example
  402. * var foo = {
  403. * not: function(bool) { return !bool; }
  404. * }
  405. * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
  406. *
  407. * @see jasmine.createSpy
  408. * @param obj
  409. * @param methodName
  410. * @returns a Jasmine spy that can be chained with all spy methods
  411. */
  412. var spyOn = function(obj, methodName) {
  413. return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
  414. };
  415. if (isCommonJS) exports.spyOn = spyOn;
  416. /**
  417. * Creates a Jasmine spec that will be added to the current suite.
  418. *
  419. * // TODO: pending tests
  420. *
  421. * @example
  422. * it('should be true', function() {
  423. * expect(true).toEqual(true);
  424. * });
  425. *
  426. * @param {String} desc description of this specification
  427. * @param {Function} func defines the preconditions and expectations of the spec
  428. */
  429. var it = function(desc, func) {
  430. return jasmine.getEnv().it(desc, func);
  431. };
  432. if (isCommonJS) exports.it = it;
  433. /**
  434. * Creates a <em>disabled</em> Jasmine spec.
  435. *
  436. * A convenience method that allows existing specs to be disabled temporarily during development.
  437. *
  438. * @param {String} desc description of this specification
  439. * @param {Function} func defines the preconditions and expectations of the spec
  440. */
  441. var xit = function(desc, func) {
  442. return jasmine.getEnv().xit(desc, func);
  443. };
  444. if (isCommonJS) exports.xit = xit;
  445. /**
  446. * Starts a chain for a Jasmine expectation.
  447. *
  448. * It is passed an Object that is the actual value and should chain to one of the many
  449. * jasmine.Matchers functions.
  450. *
  451. * @param {Object} actual Actual value to test against and expected value
  452. */
  453. var expect = function(actual) {
  454. return jasmine.getEnv().currentSpec.expect(actual);
  455. };
  456. if (isCommonJS) exports.expect = expect;
  457. /**
  458. * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
  459. *
  460. * @param {Function} func Function that defines part of a jasmine spec.
  461. */
  462. var runs = function(func) {
  463. jasmine.getEnv().currentSpec.runs(func);
  464. };
  465. if (isCommonJS) exports.runs = runs;
  466. /**
  467. * Waits a fixed time period before moving to the next block.
  468. *
  469. * @deprecated Use waitsFor() instead
  470. * @param {Number} timeout milliseconds to wait
  471. */
  472. var waits = function(timeout) {
  473. jasmine.getEnv().currentSpec.waits(timeout);
  474. };
  475. if (isCommonJS) exports.waits = waits;
  476. /**
  477. * Waits for the latchFunction to return true before proceeding to the next block.
  478. *
  479. * @param {Function} latchFunction
  480. * @param {String} optional_timeoutMessage
  481. * @param {Number} optional_timeout
  482. */
  483. var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
  484. jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
  485. };
  486. if (isCommonJS) exports.waitsFor = waitsFor;
  487. /**
  488. * A function that is called before each spec in a suite.
  489. *
  490. * Used for spec setup, including validating assumptions.
  491. *
  492. * @param {Function} beforeEachFunction
  493. */
  494. var beforeEach = function(beforeEachFunction) {
  495. jasmine.getEnv().beforeEach(beforeEachFunction);
  496. };
  497. if (isCommonJS) exports.beforeEach = beforeEach;
  498. /**
  499. * A function that is called after each spec in a suite.
  500. *
  501. * Used for restoring any state that is hijacked during spec execution.
  502. *
  503. * @param {Function} afterEachFunction
  504. */
  505. var afterEach = function(afterEachFunction) {
  506. jasmine.getEnv().afterEach(afterEachFunction);
  507. };
  508. if (isCommonJS) exports.afterEach = afterEach;
  509. /**
  510. * Defines a suite of specifications.
  511. *
  512. * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
  513. * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
  514. * of setup in some tests.
  515. *
  516. * @example
  517. * // TODO: a simple suite
  518. *
  519. * // TODO: a simple suite with a nested describe block
  520. *
  521. * @param {String} description A string, usually the class under test.
  522. * @param {Function} specDefinitions function that defines several specs.
  523. */
  524. var describe = function(description, specDefinitions) {
  525. return jasmine.getEnv().describe(description, specDefinitions);
  526. };
  527. if (isCommonJS) exports.describe = describe;
  528. /**
  529. * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
  530. *
  531. * @param {String} description A string, usually the class under test.
  532. * @param {Function} specDefinitions function that defines several specs.
  533. */
  534. var xdescribe = function(description, specDefinitions) {
  535. return jasmine.getEnv().xdescribe(description, specDefinitions);
  536. };
  537. if (isCommonJS) exports.xdescribe = xdescribe;
  538. // Provide the XMLHttpRequest class for IE 5.x-6.x:
  539. jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
  540. function tryIt(f) {
  541. try {
  542. return f();
  543. } catch(e) {
  544. }
  545. return null;
  546. }
  547. var xhr = tryIt(function() {
  548. return new ActiveXObject("Msxml2.XMLHTTP.6.0");
  549. }) ||
  550. tryIt(function() {
  551. return new ActiveXObject("Msxml2.XMLHTTP.3.0");
  552. }) ||
  553. tryIt(function() {
  554. return new ActiveXObject("Msxml2.XMLHTTP");
  555. }) ||
  556. tryIt(function() {
  557. return new ActiveXObject("Microsoft.XMLHTTP");
  558. });
  559. if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
  560. return xhr;
  561. } : XMLHttpRequest;
  562. /**
  563. * @namespace
  564. */
  565. jasmine.util = {};
  566. /**
  567. * Declare that a child class inherit it's prototype from the parent class.
  568. *
  569. * @private
  570. * @param {Function} childClass
  571. * @param {Function} parentClass
  572. */
  573. jasmine.util.inherit = function(childClass, parentClass) {
  574. /**
  575. * @private
  576. */
  577. var subclass = function() {
  578. };
  579. subclass.prototype = parentClass.prototype;
  580. childClass.prototype = new subclass();
  581. };
  582. jasmine.util.formatException = function(e) {
  583. var lineNumber;
  584. if (e.line) {
  585. lineNumber = e.line;
  586. }
  587. else if (e.lineNumber) {
  588. lineNumber = e.lineNumber;
  589. }
  590. var file;
  591. if (e.sourceURL) {
  592. file = e.sourceURL;
  593. }
  594. else if (e.fileName) {
  595. file = e.fileName;
  596. }
  597. var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
  598. if (file && lineNumber) {
  599. message += ' in ' + file + ' (line ' + lineNumber + ')';
  600. }
  601. return message;
  602. };
  603. jasmine.util.htmlEscape = function(str) {
  604. if (!str) return str;
  605. return str.replace(/&/g, '&amp;')
  606. .replace(/</g, '&lt;')
  607. .replace(/>/g, '&gt;');
  608. };
  609. jasmine.util.argsToArray = function(args) {
  610. var arrayOfArgs = [];
  611. for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
  612. return arrayOfArgs;
  613. };
  614. jasmine.util.extend = function(destination, source) {
  615. for (var property in source) destination[property] = source[property];
  616. return destination;
  617. };
  618. /**
  619. * Environment for Jasmine
  620. *
  621. * @constructor
  622. */
  623. jasmine.Env = function() {
  624. this.currentSpec = null;
  625. this.currentSuite = null;
  626. this.currentRunner_ = new jasmine.Runner(this);
  627. this.reporter = new jasmine.MultiReporter();
  628. this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
  629. this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
  630. this.lastUpdate = 0;
  631. this.specFilter = function() {
  632. return true;
  633. };
  634. this.nextSpecId_ = 0;
  635. this.nextSuiteId_ = 0;
  636. this.equalityTesters_ = [];
  637. // wrap matchers
  638. this.matchersClass = function() {
  639. jasmine.Matchers.apply(this, arguments);
  640. };
  641. jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
  642. jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
  643. };
  644. jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
  645. jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
  646. jasmine.Env.prototype.setInterval = jasmine.setInterval;
  647. jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
  648. /**
  649. * @returns an object containing jasmine version build info, if set.
  650. */
  651. jasmine.Env.prototype.version = function () {
  652. if (jasmine.version_) {
  653. return jasmine.version_;
  654. } else {
  655. throw new Error('Version not set');
  656. }
  657. };
  658. /**
  659. * @returns string containing jasmine version build info, if set.
  660. */
  661. jasmine.Env.prototype.versionString = function() {
  662. if (!jasmine.version_) {
  663. return "version unknown";
  664. }
  665. var version = this.version();
  666. var versionString = version.major + "." + version.minor + "." + version.build;
  667. if (version.release_candidate) {
  668. versionString += ".rc" + version.release_candidate
  669. }
  670. versionString += " revision " + version.revision;
  671. return versionString;
  672. };
  673. /**
  674. * @returns a sequential integer starting at 0
  675. */
  676. jasmine.Env.prototype.nextSpecId = function () {
  677. return this.nextSpecId_++;
  678. };
  679. /**
  680. * @returns a sequential integer starting at 0
  681. */
  682. jasmine.Env.prototype.nextSuiteId = function () {
  683. return this.nextSuiteId_++;
  684. };
  685. /**
  686. * Register a reporter to receive status updates from Jasmine.
  687. * @param {jasmine.Reporter} reporter An object which will receive status updates.
  688. */
  689. jasmine.Env.prototype.addReporter = function(reporter) {
  690. this.reporter.addReporter(reporter);
  691. };
  692. jasmine.Env.prototype.execute = function() {
  693. this.currentRunner_.execute();
  694. };
  695. jasmine.Env.prototype.describe = function(description, specDefinitions) {
  696. var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
  697. var parentSuite = this.currentSuite;
  698. if (parentSuite) {
  699. parentSuite.add(suite);
  700. } else {
  701. this.currentRunner_.add(suite);
  702. }
  703. this.currentSuite = suite;
  704. var declarationError = null;
  705. try {
  706. specDefinitions.call(suite);
  707. } catch(e) {
  708. declarationError = e;
  709. }
  710. if (declarationError) {
  711. this.it("encountered a declaration exception", function() {
  712. throw declarationError;
  713. });
  714. }
  715. this.currentSuite = parentSuite;
  716. return suite;
  717. };
  718. jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
  719. if (this.currentSuite) {
  720. this.currentSuite.beforeEach(beforeEachFunction);
  721. } else {
  722. this.currentRunner_.beforeEach(beforeEachFunction);
  723. }
  724. };
  725. jasmine.Env.prototype.currentRunner = function () {
  726. return this.currentRunner_;
  727. };
  728. jasmine.Env.prototype.afterEach = function(afterEachFunction) {
  729. if (this.currentSuite) {
  730. this.currentSuite.afterEach(afterEachFunction);
  731. } else {
  732. this.currentRunner_.afterEach(afterEachFunction);
  733. }
  734. };
  735. jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
  736. return {
  737. execute: function() {
  738. }
  739. };
  740. };
  741. jasmine.Env.prototype.it = function(description, func) {
  742. var spec = new jasmine.Spec(this, this.currentSuite, description);
  743. this.currentSuite.add(spec);
  744. this.currentSpec = spec;
  745. if (func) {
  746. spec.runs(func);
  747. }
  748. return spec;
  749. };
  750. jasmine.Env.prototype.xit = function(desc, func) {
  751. return {
  752. id: this.nextSpecId(),
  753. runs: function() {
  754. }
  755. };
  756. };
  757. jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
  758. if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
  759. return true;
  760. }
  761. a.__Jasmine_been_here_before__ = b;
  762. b.__Jasmine_been_here_before__ = a;
  763. var hasKey = function(obj, keyName) {
  764. return obj !== null && obj[keyName] !== jasmine.undefined;
  765. };
  766. for (var property in b) {
  767. if (!hasKey(a, property) && hasKey(b, property)) {
  768. mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
  769. }
  770. }
  771. for (property in a) {
  772. if (!hasKey(b, property) && hasKey(a, property)) {
  773. mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
  774. }
  775. }
  776. for (property in b) {
  777. if (property == '__Jasmine_been_here_before__') continue;
  778. if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
  779. mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
  780. }
  781. }
  782. if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
  783. mismatchValues.push("arrays were not the same length");
  784. }
  785. delete a.__Jasmine_been_here_before__;
  786. delete b.__Jasmine_been_here_before__;
  787. return (mismatchKeys.length === 0 && mismatchValues.length === 0);
  788. };
  789. jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
  790. mismatchKeys = mismatchKeys || [];
  791. mismatchValues = mismatchValues || [];
  792. for (var i = 0; i < this.equalityTesters_.length; i++) {
  793. var equalityTester = this.equalityTesters_[i];
  794. var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
  795. if (result !== jasmine.undefined) return result;
  796. }
  797. if (a === b) return true;
  798. if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
  799. return (a == jasmine.undefined && b == jasmine.undefined);
  800. }
  801. if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
  802. return a === b;
  803. }
  804. if (a instanceof Date && b instanceof Date) {
  805. return a.getTime() == b.getTime();
  806. }
  807. if (a instanceof jasmine.Matchers.Any) {
  808. return a.matches(b);
  809. }
  810. if (b instanceof jasmine.Matchers.Any) {
  811. return b.matches(a);
  812. }
  813. if (jasmine.isString_(a) && jasmine.isString_(b)) {
  814. return (a == b);
  815. }
  816. if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
  817. return (a == b);
  818. }
  819. if (typeof a === "object" && typeof b === "object") {
  820. return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
  821. }
  822. //Straight check
  823. return (a === b);
  824. };
  825. jasmine.Env.prototype.contains_ = function(haystack, needle) {
  826. if (jasmine.isArray_(haystack)) {
  827. for (var i = 0; i < haystack.length; i++) {
  828. if (this.equals_(haystack[i], needle)) return true;
  829. }
  830. return false;
  831. }
  832. return haystack.indexOf(needle) >= 0;
  833. };
  834. jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
  835. this.equalityTesters_.push(equalityTester);
  836. };
  837. /** No-op base class for Jasmine reporters.
  838. *
  839. * @constructor
  840. */
  841. jasmine.Reporter = function() {
  842. };
  843. //noinspection JSUnusedLocalSymbols
  844. jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
  845. };
  846. //noinspection JSUnusedLocalSymbols
  847. jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
  848. };
  849. //noinspection JSUnusedLocalSymbols
  850. jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
  851. };
  852. //noinspection JSUnusedLocalSymbols
  853. jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
  854. };
  855. //noinspection JSUnusedLocalSymbols
  856. jasmine.Reporter.prototype.reportSpecResults = function(spec) {
  857. };
  858. //noinspection JSUnusedLocalSymbols
  859. jasmine.Reporter.prototype.log = function(str) {
  860. };
  861. /**
  862. * Blocks are functions with executable code that make up a spec.
  863. *
  864. * @constructor
  865. * @param {jasmine.Env} env
  866. * @param {Function} func
  867. * @param {jasmine.Spec} spec
  868. */
  869. jasmine.Block = function(env, func, spec) {
  870. this.env = env;
  871. this.func = func;
  872. this.spec = spec;
  873. };
  874. jasmine.Block.prototype.execute = function(onComplete) {
  875. try {
  876. this.func.apply(this.spec);
  877. } catch (e) {
  878. this.spec.fail(e);
  879. }
  880. onComplete();
  881. };
  882. /** JavaScript API reporter.
  883. *
  884. * @constructor
  885. */
  886. jasmine.JsApiReporter = function() {
  887. this.started = false;
  888. this.finished = false;
  889. this.suites_ = [];
  890. this.results_ = {};
  891. };
  892. jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
  893. this.started = true;
  894. var suites = runner.topLevelSuites();
  895. for (var i = 0; i < suites.length; i++) {
  896. var suite = suites[i];
  897. this.suites_.push(this.summarize_(suite));
  898. }
  899. };
  900. jasmine.JsApiReporter.prototype.suites = function() {
  901. return this.suites_;
  902. };
  903. jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
  904. var isSuite = suiteOrSpec instanceof jasmine.Suite;
  905. var summary = {
  906. id: suiteOrSpec.id,
  907. name: suiteOrSpec.description,
  908. type: isSuite ? 'suite' : 'spec',
  909. children: []
  910. };
  911. if (isSuite) {
  912. var children = suiteOrSpec.children();
  913. for (var i = 0; i < children.length; i++) {
  914. summary.children.push(this.summarize_(children[i]));
  915. }
  916. }
  917. return summary;
  918. };
  919. jasmine.JsApiReporter.prototype.results = function() {
  920. return this.results_;
  921. };
  922. jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
  923. return this.results_[specId];
  924. };
  925. //noinspection JSUnusedLocalSymbols
  926. jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
  927. this.finished = true;
  928. };
  929. //noinspection JSUnusedLocalSymbols
  930. jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
  931. };
  932. //noinspection JSUnusedLocalSymbols
  933. jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
  934. this.results_[spec.id] = {
  935. messages: spec.results().getItems(),
  936. result: spec.results().failedCount > 0 ? "failed" : "passed"
  937. };
  938. };
  939. //noinspection JSUnusedLocalSymbols
  940. jasmine.JsApiReporter.prototype.log = function(str) {
  941. };
  942. jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
  943. var results = {};
  944. for (var i = 0; i < specIds.length; i++) {
  945. var specId = specIds[i];
  946. results[specId] = this.summarizeResult_(this.results_[specId]);
  947. }
  948. return results;
  949. };
  950. jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
  951. var summaryMessages = [];
  952. var messagesLength = result.messages.length;
  953. for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
  954. var resultMessage = result.messages[messageIndex];
  955. summaryMessages.push({
  956. text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
  957. passed: resultMessage.passed ? resultMessage.passed() : true,
  958. type: resultMessage.type,
  959. message: resultMessage.message,
  960. trace: {
  961. stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
  962. }
  963. });
  964. }
  965. return {
  966. result : result.result,
  967. messages : summaryMessages
  968. };
  969. };
  970. /**
  971. * @constructor
  972. * @param {jasmine.Env} env
  973. * @param actual
  974. * @param {jasmine.Spec} spec
  975. */
  976. jasmine.Matchers = function(env, actual, spec, opt_isNot) {
  977. this.env = env;
  978. this.actual = actual;
  979. this.spec = spec;
  980. this.isNot = opt_isNot || false;
  981. this.reportWasCalled_ = false;
  982. };
  983. // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
  984. jasmine.Matchers.pp = function(str) {
  985. throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
  986. };
  987. // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
  988. jasmine.Matchers.prototype.report = function(result, failing_message, details) {
  989. throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
  990. };
  991. jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
  992. for (var methodName in prototype) {
  993. if (methodName == 'report') continue;
  994. var orig = prototype[methodName];
  995. matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
  996. }
  997. };
  998. jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
  999. return function() {
  1000. var matcherArgs = jasmine.util.argsToArray(arguments);
  1001. var result = matcherFunction.apply(this, arguments);
  1002. if (this.isNot) {
  1003. result = !result;
  1004. }
  1005. if (this.reportWasCalled_) return result;
  1006. var message;
  1007. if (!result) {
  1008. if (this.message) {
  1009. message = this.message.apply(this, arguments);
  1010. if (jasmine.isArray_(message)) {
  1011. message = message[this.isNot ? 1 : 0];
  1012. }
  1013. } else {
  1014. var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
  1015. message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
  1016. if (matcherArgs.length > 0) {
  1017. for (var i = 0; i < matcherArgs.length; i++) {
  1018. if (i > 0) message += ",";
  1019. message += " " + jasmine.pp(matcherArgs[i]);
  1020. }
  1021. }
  1022. message += ".";
  1023. }
  1024. }
  1025. var expectationResult = new jasmine.ExpectationResult({
  1026. matcherName: matcherName,
  1027. passed: result,
  1028. expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
  1029. actual: this.actual,
  1030. message: message
  1031. });
  1032. this.spec.addMatcherResult(expectationResult);
  1033. return jasmine.undefined;
  1034. };
  1035. };
  1036. /**
  1037. * toBe: compares the actual to the expected using ===
  1038. * @param expected
  1039. */
  1040. jasmine.Matchers.prototype.toBe = function(expected) {
  1041. return this.actual === expected;
  1042. };
  1043. /**
  1044. * toNotBe: compares the actual to the expected using !==
  1045. * @param expected
  1046. * @deprecated as of 1.0. Use not.toBe() instead.
  1047. */
  1048. jasmine.Matchers.prototype.toNotBe = function(expected) {
  1049. return this.actual !== expected;
  1050. };
  1051. /**
  1052. * toEqual: compares the actual to the expected using util sense equality. Handles Objects, Arrays, etc.
  1053. *
  1054. * @param expected
  1055. */
  1056. jasmine.Matchers.prototype.toEqual = function(expected) {
  1057. return this.env.equals_(this.actual, expected);
  1058. };
  1059. /**
  1060. * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
  1061. * @param expected
  1062. * @deprecated as of 1.0. Use not.toNotEqual() instead.
  1063. */
  1064. jasmine.Matchers.prototype.toNotEqual = function(expected) {
  1065. return !this.env.equals_(this.actual, expected);
  1066. };
  1067. /**
  1068. * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
  1069. * a pattern or a String.
  1070. *
  1071. * @param expected
  1072. */
  1073. jasmine.Matchers.prototype.toMatch = function(expected) {
  1074. return new RegExp(expected).test(this.actual);
  1075. };
  1076. /**
  1077. * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
  1078. * @param expected
  1079. * @deprecated as of 1.0. Use not.toMatch() instead.
  1080. */
  1081. jasmine.Matchers.prototype.toNotMatch = function(expected) {
  1082. return !(new RegExp(expected).test(this.actual));
  1083. };
  1084. /**
  1085. * Matcher that compares the actual to jasmine.undefined.
  1086. */
  1087. jasmine.Matchers.prototype.toBeDefined = function() {
  1088. return (this.actual !== jasmine.undefined);
  1089. };
  1090. /**
  1091. * Matcher that compares the actual to jasmine.undefined.
  1092. */
  1093. jasmine.Matchers.prototype.toBeUndefined = function() {
  1094. return (this.actual === jasmine.undefined);
  1095. };
  1096. /**
  1097. * Matcher that compares the actual to null.
  1098. */
  1099. jasmine.Matchers.prototype.toBeNull = function() {
  1100. return (this.actual === null);
  1101. };
  1102. /**
  1103. * Matcher that boolean not-nots the actual.
  1104. */
  1105. jasmine.Matchers.prototype.toBeTruthy = function() {
  1106. return !!this.actual;
  1107. };
  1108. /**
  1109. * Matcher that boolean nots the actual.
  1110. */
  1111. jasmine.Matchers.prototype.toBeFalsy = function() {
  1112. return !this.actual;
  1113. };
  1114. /**
  1115. * Matcher that checks to see if the actual, a Jasmine spy, was called.
  1116. */
  1117. jasmine.Matchers.prototype.toHaveBeenCalled = function() {
  1118. if (arguments.length > 0) {
  1119. throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
  1120. }
  1121. if (!jasmine.isSpy(this.actual)) {
  1122. throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
  1123. }
  1124. this.message = function() {
  1125. return [
  1126. "Expected spy " + this.actual.identity + " to have been called.",
  1127. "Expected spy " + this.actual.identity + " not to have been called."
  1128. ];
  1129. };
  1130. return this.actual.wasCalled;
  1131. };
  1132. /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
  1133. jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
  1134. /**
  1135. * Matcher that checks to see if the actual, a Jasmine spy, was not called.
  1136. *
  1137. * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
  1138. */
  1139. jasmine.Matchers.prototype.wasNotCalled = function() {
  1140. if (arguments.length > 0) {
  1141. throw new Error('wasNotCalled does not take arguments');
  1142. }
  1143. if (!jasmine.isSpy(this.actual)) {
  1144. throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
  1145. }
  1146. this.message = function() {
  1147. return [
  1148. "Expected spy " + this.actual.identity + " to not have been called.",
  1149. "Expected spy " + this.actual.identity + " to have been called."
  1150. ];
  1151. };
  1152. return !this.actual.wasCalled;
  1153. };
  1154. /**
  1155. * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
  1156. *
  1157. * @example
  1158. *
  1159. */
  1160. jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
  1161. var expectedArgs = jasmine.util.argsToArray(arguments);
  1162. if (!jasmine.isSpy(this.actual)) {
  1163. throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
  1164. }
  1165. this.message = function() {
  1166. if (this.actual.callCount === 0) {
  1167. // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
  1168. return [
  1169. "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
  1170. "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
  1171. ];
  1172. } else {
  1173. return [
  1174. "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
  1175. "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
  1176. ];
  1177. }
  1178. };
  1179. return this.env.contains_(this.actual.argsForCall, expectedArgs);
  1180. };
  1181. /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
  1182. jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
  1183. /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
  1184. jasmine.Matchers.prototype.wasNotCalledWith = function() {
  1185. var expectedArgs = jasmine.util.argsToArray(arguments);
  1186. if (!jasmine.isSpy(this.actual)) {
  1187. throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
  1188. }
  1189. this.message = function() {
  1190. return [
  1191. "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
  1192. "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
  1193. ];
  1194. };
  1195. return !this.env.contains_(this.actual.argsForCall, expectedArgs);
  1196. };
  1197. /**
  1198. * Matcher that checks that the expected item is an element in the actual Array.
  1199. *
  1200. * @param {Object} expected
  1201. */
  1202. jasmine.Matchers.prototype.toContain = function(expected) {
  1203. return this.env.contains_(this.actual, expected);
  1204. };
  1205. /**
  1206. * Matcher that checks that the expected item is NOT an element in the actual Array.
  1207. *
  1208. * @param {Object} expected
  1209. * @deprecated as of 1.0. Use not.toNotContain() instead.
  1210. */
  1211. jasmine.Matchers.prototype.toNotContain = function(expected) {
  1212. return !this.env.contains_(this.actual, expected);
  1213. };
  1214. jasmine.Matchers.prototype.toBeLessThan = function(expected) {
  1215. return this.actual < expected;
  1216. };
  1217. jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
  1218. return this.actual > expected;
  1219. };
  1220. /**
  1221. * Matcher that checks that the expected item is equal to the actual item
  1222. * up to a given level of decimal precision (default 2).
  1223. *
  1224. * @param {Number} expected
  1225. * @param {Number} precision
  1226. */
  1227. jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
  1228. if (!(precision === 0)) {
  1229. precision = precision || 2;
  1230. }
  1231. var multiplier = Math.pow(10, precision);
  1232. var actual = Math.round(this.actual * multiplier);
  1233. expected = Math.round(expected * multiplier);
  1234. return expected == actual;
  1235. };
  1236. /**
  1237. * Matcher that checks that the expected exception was thrown by the actual.
  1238. *
  1239. * @param {String} expected
  1240. */
  1241. jasmine.Matchers.prototype.toThrow = function(expected) {
  1242. var result = false;
  1243. var exception;
  1244. if (typeof this.actual != 'function') {
  1245. throw new Error('Actual is not a function');
  1246. }
  1247. try {
  1248. this.actual();
  1249. } catch (e) {
  1250. exception = e;
  1251. }
  1252. if (exception) {
  1253. result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
  1254. }
  1255. var not = this.isNot ? "not " : "";
  1256. this.message = function() {
  1257. if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
  1258. return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
  1259. } else {
  1260. return "Expected function to throw an exception.";
  1261. }
  1262. };
  1263. return result;
  1264. };
  1265. jasmine.Matchers.Any = function(expectedClass) {
  1266. this.expectedClass = expectedClass;
  1267. };
  1268. jasmine.Matchers.Any.prototype.matches = function(other) {
  1269. if (this.expectedClass == String) {
  1270. return typeof other == 'string' || other instanceof String;
  1271. }
  1272. if (this.expectedClass == Number) {
  1273. return typeof other == 'number' || other instanceof Number;
  1274. }
  1275. if (this.expectedClass == Function) {
  1276. return typeof other == 'function' || other instanceof Function;
  1277. }
  1278. if (this.expectedClass == Object) {
  1279. return typeof other == 'object';
  1280. }
  1281. return other instanceof this.expectedClass;
  1282. };
  1283. jasmine.Matchers.Any.prototype.toString = function() {
  1284. return '<jasmine.any(' + this.expectedClass + ')>';
  1285. };
  1286. /**
  1287. * @constructor
  1288. */
  1289. jasmine.MultiReporter = function() {
  1290. this.subReporters_ = [];
  1291. };
  1292. jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
  1293. jasmine.MultiReporter.prototype.addReporter = function(reporter) {
  1294. this.subReporters_.push(reporter);
  1295. };
  1296. (function() {
  1297. var functionNames = [
  1298. "reportRunnerStarting",
  1299. "reportRunnerResults",
  1300. "reportSuiteResults",
  1301. "reportSpecStarting",
  1302. "reportSpecResults",
  1303. "log"
  1304. ];
  1305. for (var i = 0; i < functionNames.length; i++) {
  1306. var functionName = functionNames[i];
  1307. jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
  1308. return function() {
  1309. for (var j = 0; j < this.subReporters_.length; j++) {
  1310. var subReporter = this.subReporters_[j];
  1311. if (subReporter[functionName]) {
  1312. subReporter[functionName].apply(subReporter, arguments);
  1313. }
  1314. }
  1315. };
  1316. })(functionName);
  1317. }
  1318. })();
  1319. /**
  1320. * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
  1321. *
  1322. * @constructor
  1323. */
  1324. jasmine.NestedResults = function() {
  1325. /**
  1326. * The total count of results
  1327. */
  1328. this.totalCount = 0;
  1329. /**
  1330. * Number of passed results
  1331. */
  1332. this.passedCount = 0;
  1333. /**
  1334. * Number of failed results
  1335. */
  1336. this.failedCount = 0;
  1337. /**
  1338. * Was this suite/spec skipped?
  1339. */
  1340. this.skipped = false;
  1341. /**
  1342. * @ignore
  1343. */
  1344. this.items_ = [];
  1345. };
  1346. /**
  1347. * Roll up the result counts.
  1348. *
  1349. * @param result
  1350. */
  1351. jasmine.NestedResults.prototype.rollupCounts = function(result) {
  1352. this.totalCount += result.totalCount;
  1353. this.passedCount += result.passedCount;
  1354. this.failedCount += result.failedCount;
  1355. };
  1356. /**
  1357. * Adds a log message.
  1358. * @param values Array of message parts which will be concatenated later.
  1359. */
  1360. jasmine.NestedResults.prototype.log = function(values) {
  1361. this.items_.push(new jasmine.MessageResult(values));
  1362. };
  1363. /**
  1364. * Getter for the results: message & results.
  1365. */
  1366. jasmine.NestedResults.prototype.getItems = function() {
  1367. return this.items_;
  1368. };
  1369. /**
  1370. * Adds a result, tracking counts (total, passed, & failed)
  1371. * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
  1372. */
  1373. jasmine.NestedResults.prototype.addResult = function(result) {
  1374. if (result.type != 'log') {
  1375. if (result.items_) {
  1376. this.rollupCounts(result);
  1377. } else {
  1378. this.totalCount++;
  1379. if (result.passed()) {
  1380. this.passedCount++;
  1381. } else {
  1382. this.failedCount++;
  1383. }
  1384. }
  1385. }
  1386. this.items_.push(result);
  1387. };
  1388. /**
  1389. * @returns {Boolean} True if <b>everything</b> below passed
  1390. */
  1391. jasmine.NestedResults.prototype.passed = function() {
  1392. return this.passedCount === this.totalCount;
  1393. };
  1394. /**
  1395. * Base class for pretty printing for expectation results.
  1396. */
  1397. jasmine.PrettyPrinter = function() {
  1398. this.ppNestLevel_ = 0;
  1399. };
  1400. /**
  1401. * Formats a value in a nice, human-readable string.
  1402. *
  1403. * @param value
  1404. */
  1405. jasmine.PrettyPrinter.prototype.format = function(value) {
  1406. if (this.ppNestLevel_ > 40) {
  1407. throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
  1408. }
  1409. this.ppNestLevel_++;
  1410. try {
  1411. if (value === jasmine.undefined) {
  1412. this.emitScalar('undefined');
  1413. } else if (value === null) {
  1414. this.emitScalar('null');
  1415. } else if (value === jasmine.getGlobal()) {
  1416. this.emitScalar('<global>');
  1417. } else if (value instanceof jasmine.Matchers.Any) {
  1418. this.emitScalar(value.toString());
  1419. } else if (typeof value === 'string') {
  1420. this.emitString(value);
  1421. } else if (jasmine.isSpy(value)) {
  1422. this.emitScalar("spy on " + value.identity);
  1423. } else if (value instanceof RegExp) {
  1424. this.emitScalar(value.toString());
  1425. } else if (typeof value === 'function') {
  1426. this.emitScalar('Function');
  1427. } else if (typeof value.nodeType === 'number') {
  1428. this.emitScalar('HTMLNode');
  1429. } else if (value instanceof Date) {
  1430. this.emitScalar('Date(' + value + ')');
  1431. } else if (value.__Jasmine_been_here_before__) {
  1432. this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
  1433. } else if (jasmine.isArray_(value) || typeof value == 'object') {
  1434. value.__Jasmine_been_here_before__ = true;
  1435. if (jasmine.isArray_(value)) {
  1436. this.emitArray(value);
  1437. } else {
  1438. this.emitObject(value);
  1439. }
  1440. delete value.__Jasmine_been_here_before__;
  1441. } else {
  1442. this.emitScalar(value.toString());
  1443. }
  1444. } finally {
  1445. this.ppNestLevel_--;
  1446. }
  1447. };
  1448. jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
  1449. for (var property in obj) {
  1450. if (property == '__Jasmine_been_here_before__') continue;
  1451. fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
  1452. obj.__lookupGetter__(property) !== null) : false);
  1453. }
  1454. };
  1455. jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
  1456. jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
  1457. jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
  1458. jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
  1459. jasmine.StringPrettyPrinter = function() {
  1460. jasmine.PrettyPrinter.call(this);
  1461. this.string = '';
  1462. };
  1463. jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
  1464. jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
  1465. this.append(value);
  1466. };
  1467. jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
  1468. this.append("'" + value + "'");
  1469. };
  1470. jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
  1471. this.append('[ ');
  1472. for (var i = 0; i < array.length; i++) {
  1473. if (i > 0) {
  1474. this.append(', ');
  1475. }
  1476. this.format(array[i]);
  1477. }
  1478. this.append(' ]');
  1479. };
  1480. jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
  1481. var self = this;
  1482. this.append('{ ');
  1483. var first = true;
  1484. this.iterateObject(obj, function(property, isGetter) {
  1485. if (first) {
  1486. first = false;
  1487. } else {
  1488. self.append(', ');
  1489. }
  1490. self.append(property);
  1491. self.append(' : ');
  1492. if (isGetter) {
  1493. self.append('<getter>');
  1494. } else {
  1495. self.format(obj[property]);
  1496. }
  1497. });
  1498. this.append(' }');
  1499. };
  1500. jasmine.StringPrettyPrinter.prototype.append = function(value) {
  1501. this.string += value;
  1502. };
  1503. jasmine.Queue = function(env) {
  1504. this.env = env;
  1505. this.blocks = [];
  1506. this.running = false;
  1507. this.index = 0;
  1508. this.offset = 0;
  1509. this.abort = false;
  1510. };
  1511. jasmine.Queue.prototype.addBefore = function(block) {
  1512. this.blocks.unshift(block);
  1513. };
  1514. jasmine.Queue.prototype.add = function(block) {
  1515. this.blocks.push(block);
  1516. };
  1517. jasmine.Queue.prototype.insertNext = function(block) {
  1518. this.blocks.splice((this.index + this.offset + 1), 0, block);
  1519. this.offset++;
  1520. };
  1521. jasmine.Queue.prototype.start = function(onComplete) {
  1522. this.running = true;
  1523. this.onComplete = onComplete;
  1524. this.next_();
  1525. };
  1526. jasmine.Queue.prototype.isRunning = function() {
  1527. return this.running;
  1528. };
  1529. jasmine.Queue.LOOP_DONT_RECURSE = true;
  1530. jasmine.Queue.prototype.next_ = function() {
  1531. var self = this;
  1532. var goAgain = true;
  1533. while (goAgain) {
  1534. goAgain = false;
  1535. if (self.index < self.blocks.length && !this.abort) {
  1536. var calledSynchronously = true;
  1537. var completedSynchronously = false;
  1538. var onComplete = function () {
  1539. if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
  1540. completedSynchronously = true;
  1541. return;
  1542. }
  1543. if (self.blocks[self.index].abort) {
  1544. self.abort = true;
  1545. }
  1546. self.offset = 0;
  1547. self.index++;
  1548. var now = new Date().getTime();
  1549. if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
  1550. self.env.lastUpdate = now;
  1551. self.env.setTimeout(function() {
  1552. self.next_();
  1553. }, 0);
  1554. } else {
  1555. if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
  1556. goAgain = true;
  1557. } else {
  1558. self.next_();
  1559. }
  1560. }
  1561. };
  1562. self.blocks[self.index].execute(onComplete);
  1563. calledSynchronously = false;
  1564. if (completedSynchronously) {
  1565. onComplete();
  1566. }
  1567. } else {
  1568. self.running = false;
  1569. if (self.onComplete) {
  1570. self.onComplete();
  1571. }
  1572. }
  1573. }
  1574. };
  1575. jasmine.Queue.prototype.results = function() {
  1576. var results = new jasmine.NestedResults();
  1577. for (var i = 0; i < this.blocks.length; i++) {
  1578. if (this.blocks[i].results) {
  1579. results.addResult(this.blocks[i].results());
  1580. }
  1581. }
  1582. return results;
  1583. };
  1584. /**
  1585. * Runner
  1586. *
  1587. * @constructor
  1588. * @param {jasmine.Env} env
  1589. */
  1590. jasmine.Runner = function(env) {
  1591. var self = this;
  1592. self.env = env;
  1593. self.queue = new jasmine.Queue(env);
  1594. self.before_ = [];
  1595. self.after_ = [];
  1596. self.suites_ = [];
  1597. };
  1598. jasmine.Runner.prototype.execute = function() {
  1599. var self = this;
  1600. if (self.env.reporter.reportRunnerStarting) {
  1601. self.env.reporter.reportRunnerStarting(this);
  1602. }
  1603. self.queue.start(function () {
  1604. self.finishCallback();
  1605. });
  1606. };
  1607. jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
  1608. beforeEachFunction.typeName = 'beforeEach';
  1609. this.before_.splice(0,0,beforeEachFunction);
  1610. };
  1611. jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
  1612. afterEachFunction.typeName = 'afterEach';
  1613. this.after_.splice(0,0,afterEachFunction);
  1614. };
  1615. jasmine.Runner.prototype.finishCallback = function() {
  1616. this.env.reporter.reportRunnerResults(this);
  1617. };
  1618. jasmine.Runner.prototype.addSuite = function(suite) {
  1619. this.suites_.push(suite);
  1620. };
  1621. jasmine.Runner.prototype.add = function(block) {
  1622. if (block instanceof jasmine.Suite) {
  1623. this.addSuite(block);
  1624. }
  1625. this.queue.add(block);
  1626. };
  1627. jasmine.Runner.prototype.specs = function () {
  1628. var suites = this.suites();
  1629. var specs = [];
  1630. for (var i = 0; i < suites.length; i++) {
  1631. specs = specs.concat(suites[i].specs());
  1632. }
  1633. return specs;
  1634. };
  1635. jasmine.Runner.prototype.suites = function() {
  1636. return this.suites_;
  1637. };
  1638. jasmine.Runner.prototype.topLevelSuites = function() {
  1639. var topLevelSuites = [];
  1640. for (var i = 0; i < this.suites_.length; i++) {
  1641. if (!this.suites_[i].parentSuite) {
  1642. topLevelSuites.push(this.suites_[i]);
  1643. }
  1644. }
  1645. return topLevelSuites;
  1646. };
  1647. jasmine.Runner.prototype.results = function() {
  1648. return this.queue.results();
  1649. };
  1650. /**
  1651. * Internal representation of a Jasmine specification, or test.
  1652. *
  1653. * @constructor
  1654. * @param {jasmine.Env} env
  1655. * @param {jasmine.Suite} suite
  1656. * @param {String} description
  1657. */
  1658. jasmine.Spec = function(env, suite, description) {
  1659. if (!env) {
  1660. throw new Error('jasmine.Env() required');
  1661. }
  1662. if (!suite) {
  1663. throw new Error('jasmine.Suite() required');
  1664. }
  1665. var spec = this;
  1666. spec.id = env.nextSpecId ? env.nextSpecId() : null;
  1667. spec.env = env;
  1668. spec.suite = suite;
  1669. spec.description = description;
  1670. spec.queue = new jasmine.Queue(env);
  1671. spec.afterCallbacks = [];
  1672. spec.spies_ = [];
  1673. spec.results_ = new jasmine.NestedResults();
  1674. spec.results_.description = description;
  1675. spec.matchersClass = null;
  1676. };
  1677. jasmine.Spec.prototype.getFullName = function() {
  1678. return this.suite.getFullName() + ' ' + this.description + '.';
  1679. };
  1680. jasmine.Spec.prototype.results = function() {
  1681. return this.results_;
  1682. };
  1683. /**
  1684. * All parameters are pretty-printed and concatenated together, then written to the spec's output.
  1685. *
  1686. * Be careful not to leave calls to <code>jasmine.log</code> in production code.
  1687. */
  1688. jasmine.Spec.prototype.log = function() {
  1689. return this.results_.log(arguments);
  1690. };
  1691. jasmine.Spec.prototype.runs = function (func) {
  1692. var block = new jasmine.Block(this.env, func, this);
  1693. this.addToQueue(block);
  1694. return this;
  1695. };
  1696. jasmine.Spec.prototype.addToQueue = function (block) {
  1697. if (this.queue.isRunning()) {
  1698. this.queue.insertNext(block);
  1699. } else {
  1700. this.queue.add(block);
  1701. }
  1702. };
  1703. /**
  1704. * @param {jasmine.ExpectationResult} result
  1705. */
  1706. jasmine.Spec.prototype.addMatcherResult = function(result) {
  1707. this.results_.addResult(result);
  1708. };
  1709. jasmine.Spec.prototype.expect = function(actual) {
  1710. var positive = new (this.getMatchersClass_())(this.env, actual, this);
  1711. positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
  1712. return positive;
  1713. };
  1714. /**
  1715. * Waits a fixed time period before moving to the next block.
  1716. *
  1717. * @deprecated Use waitsFor() instead
  1718. * @param {Number} timeout milliseconds to wait
  1719. */
  1720. jasmine.Spec.prototype.waits = function(timeout) {
  1721. var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
  1722. this.addToQueue(waitsFunc);
  1723. return this;
  1724. };
  1725. /**
  1726. * Waits for the latchFunction to return true before proceeding to the next block.
  1727. *
  1728. * @param {Function} latchFunction
  1729. * @param {String} optional_timeoutMessage
  1730. * @param {Number} optional_timeout
  1731. */
  1732. jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
  1733. var latchFunction_ = null;
  1734. var optional_timeoutMessage_ = null;
  1735. var optional_timeout_ = null;
  1736. for (var i = 0; i < arguments.length; i++) {
  1737. var arg = arguments[i];
  1738. switch (typeof arg) {
  1739. case 'function':
  1740. latchFunction_ = arg;
  1741. break;
  1742. case 'string':
  1743. optional_timeoutMessage_ = arg;
  1744. break;
  1745. case 'number':
  1746. optional_timeout_ = arg;
  1747. break;
  1748. }
  1749. }
  1750. var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
  1751. this.addToQueue(waitsForFunc);
  1752. return this;
  1753. };
  1754. jasmine.Spec.prototype.fail = function (e) {
  1755. var expectationResult = new jasmine.ExpectationResult({
  1756. passed: false,
  1757. message: e ? jasmine.util.formatException(e) : 'Exception',
  1758. trace: { stack: e.stack }
  1759. });
  1760. this.results_.addResult(expectationResult);
  1761. };
  1762. jasmine.Spec.prototype.getMatchersClass_ = function() {
  1763. return this.matchersClass || this.env.matchersClass;
  1764. };
  1765. jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
  1766. var parent = this.getMatchersClass_();
  1767. var newMatchersClass = function() {
  1768. parent.apply(this, arguments);
  1769. };
  1770. jasmine.util.inherit(newMatchersClass, parent);
  1771. jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
  1772. this.matchersClass = newMatchersClass;
  1773. };
  1774. jasmine.Spec.prototype.finishCallback = function() {
  1775. this.env.reporter.reportSpecResults(this);
  1776. };
  1777. jasmine.Spec.prototype.finish = function(onComplete) {
  1778. this.removeAllSpies();
  1779. this.finishCallback();
  1780. if (onComplete) {
  1781. onComplete();
  1782. }
  1783. };
  1784. jasmine.Spec.prototype.after = function(doAfter) {
  1785. if (this.queue.isRunning()) {
  1786. this.queue.add(new jasmine.Block(this.env, doAfter, this));
  1787. } else {
  1788. this.afterCallbacks.unshift(doAfter);
  1789. }
  1790. };
  1791. jasmine.Spec.prototype.execute = function(onComplete) {
  1792. var spec = this;
  1793. if (!spec.env.specFilter(spec)) {
  1794. spec.results_.skipped = true;
  1795. spec.finish(onComplete);
  1796. return;
  1797. }
  1798. this.env.reporter.reportSpecStarting(this);
  1799. spec.env.currentSpec = spec;
  1800. spec.addBeforesAndAftersToQueue();
  1801. spec.queue.start(function () {
  1802. spec.finish(onComplete);
  1803. });
  1804. };
  1805. jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
  1806. var runner = this.env.currentRunner();
  1807. var i;
  1808. for (var suite = this.suite; suite; suite = suite.parentSuite) {
  1809. for (i = 0; i < suite.before_.length; i++) {
  1810. this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
  1811. }
  1812. }
  1813. for (i = 0; i < runner.before_.length; i++) {
  1814. this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
  1815. }
  1816. for (i = 0; i < this.afterCallbacks.length; i++) {
  1817. this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
  1818. }
  1819. for (suite = this.suite; suite; suite = suite.parentSuite) {
  1820. for (i = 0; i < suite.after_.length; i++) {
  1821. this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
  1822. }
  1823. }
  1824. for (i = 0; i < runner.after_.length; i++) {
  1825. this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
  1826. }
  1827. };
  1828. jasmine.Spec.prototype.explodes = function() {
  1829. throw 'explodes function should not have been called';
  1830. };
  1831. jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
  1832. if (obj == jasmine.undefined) {
  1833. throw "spyOn could not find an object to spy upon for " + methodName + "()";
  1834. }
  1835. if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
  1836. throw methodName + '() method does not exist';
  1837. }
  1838. if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
  1839. throw new Error(methodName + ' has already been spied upon');
  1840. }
  1841. var spyObj = jasmine.createSpy(methodName);
  1842. this.spies_.push(spyObj);
  1843. spyObj.baseObj = obj;
  1844. spyObj.methodName = methodName;
  1845. spyObj.originalValue = obj[methodName];
  1846. obj[methodName] = spyObj;
  1847. return spyObj;
  1848. };
  1849. jasmine.Spec.prototype.removeAllSpies = function() {
  1850. for (var i = 0; i < this.spies_.length; i++) {
  1851. var spy = this.spies_[i];
  1852. spy.baseObj[spy.methodName] = spy.originalValue;
  1853. }
  1854. this.spies_ = [];
  1855. };
  1856. /**
  1857. * Internal representation of a Jasmine suite.
  1858. *
  1859. * @constructor
  1860. * @param {jasmine.Env} env
  1861. * @param {String} description
  1862. * @param {Function} specDefinitions
  1863. * @param {jasmine.Suite} parentSuite
  1864. */
  1865. jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
  1866. var self = this;
  1867. self.id = env.nextSuiteId ? env.nextSuiteId() : null;
  1868. self.description = description;
  1869. self.queue = new jasmine.Queue(env);
  1870. self.parentSuite = parentSuite;
  1871. self.env = env;
  1872. self.before_ = [];
  1873. self.after_ = [];
  1874. self.children_ = [];
  1875. self.suites_ = [];
  1876. self.specs_ = [];
  1877. };
  1878. jasmine.Suite.prototype.getFullName = function() {
  1879. var fullName = this.description;
  1880. for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
  1881. fullName = parentSuite.description + ' ' + fullName;
  1882. }
  1883. return fullName;
  1884. };
  1885. jasmine.Suite.prototype.finish = function(onComplete) {
  1886. this.env.reporter.reportSuiteResults(this);
  1887. this.finished = true;
  1888. if (typeof(onComplete) == 'function') {
  1889. onComplete();
  1890. }
  1891. };
  1892. jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
  1893. beforeEachFunction.typeName = 'beforeEach';
  1894. this.before_.unshift(beforeEachFunction);
  1895. };
  1896. jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
  1897. afterEachFunction.typeName = 'afterEach';
  1898. this.after_.unshift(afterEachFunction);
  1899. };
  1900. jasmine.Suite.prototype.results = function() {
  1901. return this.queue.results();
  1902. };
  1903. jasmine.Suite.prototype.add = function(suiteOrSpec) {
  1904. this.children_.push(suiteOrSpec);
  1905. if (suiteOrSpec instanceof jasmine.Suite) {
  1906. this.suites_.push(suiteOrSpec);
  1907. this.env.currentRunner().addSuite(suiteOrSpec);
  1908. } else {
  1909. this.specs_.push(suiteOrSpec);
  1910. }
  1911. this.queue.add(suiteOrSpec);
  1912. };
  1913. jasmine.Suite.prototype.specs = function() {
  1914. return this.specs_;
  1915. };
  1916. jasmine.Suite.prototype.suites = function() {
  1917. return this.suites_;
  1918. };
  1919. jasmine.Suite.prototype.children = function() {
  1920. return this.children_;
  1921. };
  1922. jasmine.Suite.prototype.execute = function(onComplete) {
  1923. var self = this;
  1924. this.queue.start(function () {
  1925. self.finish(onComplete);
  1926. });
  1927. };
  1928. jasmine.WaitsBlock = function(env, timeout, spec) {
  1929. this.timeout = timeout;
  1930. jasmine.Block.call(this, env, null, spec);
  1931. };
  1932. jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
  1933. jasmine.WaitsBlock.prototype.execute = function (onComplete) {
  1934. if (jasmine.VERBOSE) {
  1935. this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
  1936. }
  1937. this.env.setTimeout(function () {
  1938. onComplete();
  1939. }, this.timeout);
  1940. };
  1941. /**
  1942. * A block which waits for some condition to become true, with timeout.
  1943. *
  1944. * @constructor
  1945. * @extends jasmine.Block
  1946. * @param {jasmine.Env} env The Jasmine environment.
  1947. * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
  1948. * @param {Function} latchFunction A function which returns true when the desired condition has been met.
  1949. * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
  1950. * @param {jasmine.Spec} spec The Jasmine spec.
  1951. */
  1952. jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
  1953. this.timeout = timeout || env.defaultTimeoutInterval;
  1954. this.latchFunction = latchFunction;
  1955. this.message = message;
  1956. this.totalTimeSpentWaitingForLatch = 0;
  1957. jasmine.Block.call(this, env, null, spec);
  1958. };
  1959. jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
  1960. jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
  1961. jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
  1962. if (jasmine.VERBOSE) {
  1963. this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
  1964. }
  1965. var latchFunctionResult;
  1966. try {
  1967. latchFunctionResult = this.latchFunction.apply(this.spec);
  1968. } catch (e) {
  1969. this.spec.fail(e);
  1970. onComplete();
  1971. return;
  1972. }
  1973. if (latchFunctionResult) {
  1974. onComplete();
  1975. } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
  1976. var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
  1977. this.spec.fail({
  1978. name: 'timeout',
  1979. message: message
  1980. });
  1981. this.abort = true;
  1982. onComplete();
  1983. } else {
  1984. this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
  1985. var self = this;
  1986. this.env.setTimeout(function() {
  1987. self.execute(onComplete);
  1988. }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
  1989. }
  1990. };
  1991. // Mock setTimeout, clearTimeout
  1992. // Contributed by Pivotal Computer Systems, www.pivotalsf.com
  1993. jasmine.FakeTimer = function() {
  1994. this.reset();
  1995. var self = this;
  1996. self.setTimeout = function(funcToCall, millis) {
  1997. self.timeoutsMade++;
  1998. self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
  1999. return self.timeoutsMade;
  2000. };
  2001. self.setInterval = function(funcToCall, millis) {
  2002. self.timeoutsMade++;
  2003. self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
  2004. return self.timeoutsMade;
  2005. };
  2006. self.clearTimeout = function(timeoutKey) {
  2007. self.scheduledFunctions[timeoutKey] = jasmine.undefined;
  2008. };
  2009. self.clearInterval = function(timeoutKey) {
  2010. self.scheduledFunctions[timeoutKey] = jasmine.undefined;
  2011. };
  2012. };
  2013. jasmine.FakeTimer.prototype.reset = function() {
  2014. this.timeoutsMade = 0;
  2015. this.scheduledFunctions = {};
  2016. this.nowMillis = 0;
  2017. };
  2018. jasmine.FakeTimer.prototype.tick = function(millis) {
  2019. var oldMillis = this.nowMillis;
  2020. var newMillis = oldMillis + millis;
  2021. this.runFunctionsWithinRange(oldMillis, newMillis);
  2022. this.nowMillis = newMillis;
  2023. };
  2024. jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
  2025. var scheduledFunc;
  2026. var funcsToRun = [];
  2027. for (var timeoutKey in this.scheduledFunctions) {
  2028. scheduledFunc = this.scheduledFunctions[timeoutKey];
  2029. if (scheduledFunc != jasmine.undefined &&
  2030. scheduledFunc.runAtMillis >= oldMillis &&
  2031. scheduledFunc.runAtMillis <= nowMillis) {
  2032. funcsToRun.push(scheduledFunc);
  2033. this.scheduledFunctions[timeoutKey] = jasmine.undefined;
  2034. }
  2035. }
  2036. if (funcsToRun.length > 0) {
  2037. funcsToRun.sort(function(a, b) {
  2038. return a.runAtMillis - b.runAtMillis;
  2039. });
  2040. for (var i = 0; i < funcsToRun.length; ++i) {
  2041. try {
  2042. var funcToRun = funcsToRun[i];
  2043. this.nowMillis = funcToRun.runAtMillis;
  2044. funcToRun.funcToCall();
  2045. if (funcToRun.recurring) {
  2046. this.scheduleFunction(funcToRun.timeoutKey,
  2047. funcToRun.funcToCall,
  2048. funcToRun.millis,
  2049. true);
  2050. }
  2051. } catch(e) {
  2052. }
  2053. }
  2054. this.runFunctionsWithinRange(oldMillis, nowMillis);
  2055. }
  2056. };
  2057. jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
  2058. this.scheduledFunctions[timeoutKey] = {
  2059. runAtMillis: this.nowMillis + millis,
  2060. funcToCall: funcToCall,
  2061. recurring: recurring,
  2062. timeoutKey: timeoutKey,
  2063. millis: millis
  2064. };
  2065. };
  2066. /**
  2067. * @namespace
  2068. */
  2069. jasmine.Clock = {
  2070. defaultFakeTimer: new jasmine.FakeTimer(),
  2071. reset: function() {
  2072. jasmine.Clock.assertInstalled();
  2073. jasmine.Clock.defaultFakeTimer.reset();
  2074. },
  2075. tick: function(millis) {
  2076. jasmine.Clock.assertInstalled();
  2077. jasmine.Clock.defaultFakeTimer.tick(millis);
  2078. },
  2079. runFunctionsWithinRange: function(oldMillis, nowMillis) {
  2080. jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
  2081. },
  2082. scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
  2083. jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
  2084. },
  2085. useMock: function() {
  2086. if (!jasmine.Clock.isInstalled()) {
  2087. var spec = jasmine.getEnv().currentSpec;
  2088. spec.after(jasmine.Clock.uninstallMock);
  2089. jasmine.Clock.installMock();
  2090. }
  2091. },
  2092. installMock: function() {
  2093. jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
  2094. },
  2095. uninstallMock: function() {
  2096. jasmine.Clock.assertInstalled();
  2097. jasmine.Clock.installed = jasmine.Clock.real;
  2098. },
  2099. real: {
  2100. setTimeout: jasmine.getGlobal().setTimeout,
  2101. clearTimeout: jasmine.getGlobal().clearTimeout,
  2102. setInterval: jasmine.getGlobal().setInterval,
  2103. clearInterval: jasmine.getGlobal().clearInterval
  2104. },
  2105. assertInstalled: function() {
  2106. if (!jasmine.Clock.isInstalled()) {
  2107. throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
  2108. }
  2109. },
  2110. isInstalled: function() {
  2111. return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
  2112. },
  2113. installed: null
  2114. };
  2115. jasmine.Clock.installed = jasmine.Clock.real;
  2116. //else for IE support
  2117. jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
  2118. if (jasmine.Clock.installed.setTimeout.apply) {
  2119. return jasmine.Clock.installed.setTimeout.apply(this, arguments);
  2120. } else {
  2121. return jasmine.Clock.installed.setTimeout(funcToCall, millis);
  2122. }
  2123. };
  2124. jasmine.getGlobal().setInterval = function(funcToCall, millis) {
  2125. if (jasmine.Clock.installed.setInterval.apply) {
  2126. return jasmine.Clock.installed.setInterval.apply(this, arguments);
  2127. } else {
  2128. return jasmine.Clock.installed.setInterval(funcToCall, millis);
  2129. }
  2130. };
  2131. jasmine.getGlobal().clearTimeout = function(timeoutKey) {
  2132. if (jasmine.Clock.installed.clearTimeout.apply) {
  2133. return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
  2134. } else {
  2135. return jasmine.Clock.installed.clearTimeout(timeoutKey);
  2136. }
  2137. };
  2138. jasmine.getGlobal().clearInterval = function(timeoutKey) {
  2139. if (jasmine.Clock.installed.clearTimeout.apply) {
  2140. return jasmine.Clock.installed.clearInterval.apply(this, arguments);
  2141. } else {
  2142. return jasmine.Clock.installed.clearInterval(timeoutKey);
  2143. }
  2144. };
  2145. jasmine.version_= {
  2146. "major": 1,
  2147. "minor": 1,
  2148. "build": 0,
  2149. "revision": 1308618948,
  2150. "release_candidate": 1
  2151. };