angular-mocks.js 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768
  1. /**
  2. * @license AngularJS v1.0.6
  3. * (c) 2010-2012 Google, Inc. http://angularjs.org
  4. * License: MIT
  5. *
  6. * TODO(vojta): wrap whole file into closure during build
  7. */
  8. /**
  9. * @ngdoc overview
  10. * @name angular.mock
  11. * @description
  12. *
  13. * Namespace from 'angular-mocks.js' which contains testing related code.
  14. */
  15. angular.mock = {};
  16. /**
  17. * ! This is a private undocumented service !
  18. *
  19. * @name ngMock.$browser
  20. *
  21. * @description
  22. * This service is a mock implementation of {@link ng.$browser}. It provides fake
  23. * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
  24. * cookies, etc...
  25. *
  26. * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
  27. * that there are several helper methods available which can be used in tests.
  28. */
  29. angular.mock.$BrowserProvider = function() {
  30. this.$get = function(){
  31. return new angular.mock.$Browser();
  32. };
  33. };
  34. angular.mock.$Browser = function() {
  35. var self = this;
  36. this.isMock = true;
  37. self.$$url = "http://server/";
  38. self.$$lastUrl = self.$$url; // used by url polling fn
  39. self.pollFns = [];
  40. // TODO(vojta): remove this temporary api
  41. self.$$completeOutstandingRequest = angular.noop;
  42. self.$$incOutstandingRequestCount = angular.noop;
  43. // register url polling fn
  44. self.onUrlChange = function(listener) {
  45. self.pollFns.push(
  46. function() {
  47. if (self.$$lastUrl != self.$$url) {
  48. self.$$lastUrl = self.$$url;
  49. listener(self.$$url);
  50. }
  51. }
  52. );
  53. return listener;
  54. };
  55. self.cookieHash = {};
  56. self.lastCookieHash = {};
  57. self.deferredFns = [];
  58. self.deferredNextId = 0;
  59. self.defer = function(fn, delay) {
  60. delay = delay || 0;
  61. self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
  62. self.deferredFns.sort(function(a,b){ return a.time - b.time;});
  63. return self.deferredNextId++;
  64. };
  65. self.defer.now = 0;
  66. self.defer.cancel = function(deferId) {
  67. var fnIndex;
  68. angular.forEach(self.deferredFns, function(fn, index) {
  69. if (fn.id === deferId) fnIndex = index;
  70. });
  71. if (fnIndex !== undefined) {
  72. self.deferredFns.splice(fnIndex, 1);
  73. return true;
  74. }
  75. return false;
  76. };
  77. /**
  78. * @name ngMock.$browser#defer.flush
  79. * @methodOf ngMock.$browser
  80. *
  81. * @description
  82. * Flushes all pending requests and executes the defer callbacks.
  83. *
  84. * @param {number=} number of milliseconds to flush. See {@link #defer.now}
  85. */
  86. self.defer.flush = function(delay) {
  87. if (angular.isDefined(delay)) {
  88. self.defer.now += delay;
  89. } else {
  90. if (self.deferredFns.length) {
  91. self.defer.now = self.deferredFns[self.deferredFns.length-1].time;
  92. } else {
  93. throw Error('No deferred tasks to be flushed');
  94. }
  95. }
  96. while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
  97. self.deferredFns.shift().fn();
  98. }
  99. };
  100. /**
  101. * @name ngMock.$browser#defer.now
  102. * @propertyOf ngMock.$browser
  103. *
  104. * @description
  105. * Current milliseconds mock time.
  106. */
  107. self.$$baseHref = '';
  108. self.baseHref = function() {
  109. return this.$$baseHref;
  110. };
  111. };
  112. angular.mock.$Browser.prototype = {
  113. /**
  114. * @name ngMock.$browser#poll
  115. * @methodOf ngMock.$browser
  116. *
  117. * @description
  118. * run all fns in pollFns
  119. */
  120. poll: function poll() {
  121. angular.forEach(this.pollFns, function(pollFn){
  122. pollFn();
  123. });
  124. },
  125. addPollFn: function(pollFn) {
  126. this.pollFns.push(pollFn);
  127. return pollFn;
  128. },
  129. url: function(url, replace) {
  130. if (url) {
  131. this.$$url = url;
  132. return this;
  133. }
  134. return this.$$url;
  135. },
  136. cookies: function(name, value) {
  137. if (name) {
  138. if (value == undefined) {
  139. delete this.cookieHash[name];
  140. } else {
  141. if (angular.isString(value) && //strings only
  142. value.length <= 4096) { //strict cookie storage limits
  143. this.cookieHash[name] = value;
  144. }
  145. }
  146. } else {
  147. if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
  148. this.lastCookieHash = angular.copy(this.cookieHash);
  149. this.cookieHash = angular.copy(this.cookieHash);
  150. }
  151. return this.cookieHash;
  152. }
  153. },
  154. notifyWhenNoOutstandingRequests: function(fn) {
  155. fn();
  156. }
  157. };
  158. /**
  159. * @ngdoc object
  160. * @name ngMock.$exceptionHandlerProvider
  161. *
  162. * @description
  163. * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors passed
  164. * into the `$exceptionHandler`.
  165. */
  166. /**
  167. * @ngdoc object
  168. * @name ngMock.$exceptionHandler
  169. *
  170. * @description
  171. * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
  172. * into it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
  173. * information.
  174. *
  175. *
  176. * <pre>
  177. * describe('$exceptionHandlerProvider', function() {
  178. *
  179. * it('should capture log messages and exceptions', function() {
  180. *
  181. * module(function($exceptionHandlerProvider) {
  182. * $exceptionHandlerProvider.mode('log');
  183. * });
  184. *
  185. * inject(function($log, $exceptionHandler, $timeout) {
  186. * $timeout(function() { $log.log(1); });
  187. * $timeout(function() { $log.log(2); throw 'banana peel'; });
  188. * $timeout(function() { $log.log(3); });
  189. * expect($exceptionHandler.errors).toEqual([]);
  190. * expect($log.assertEmpty());
  191. * $timeout.flush();
  192. * expect($exceptionHandler.errors).toEqual(['banana peel']);
  193. * expect($log.log.logs).toEqual([[1], [2], [3]]);
  194. * });
  195. * });
  196. * });
  197. * </pre>
  198. */
  199. angular.mock.$ExceptionHandlerProvider = function() {
  200. var handler;
  201. /**
  202. * @ngdoc method
  203. * @name ngMock.$exceptionHandlerProvider#mode
  204. * @methodOf ngMock.$exceptionHandlerProvider
  205. *
  206. * @description
  207. * Sets the logging mode.
  208. *
  209. * @param {string} mode Mode of operation, defaults to `rethrow`.
  210. *
  211. * - `rethrow`: If any errors are are passed into the handler in tests, it typically
  212. * means that there is a bug in the application or test, so this mock will
  213. * make these tests fail.
  214. * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an
  215. * array of errors in `$exceptionHandler.errors`, to allow later assertion of them.
  216. * See {@link ngMock.$log#assertEmpty assertEmpty()} and
  217. * {@link ngMock.$log#reset reset()}
  218. */
  219. this.mode = function(mode) {
  220. switch(mode) {
  221. case 'rethrow':
  222. handler = function(e) {
  223. throw e;
  224. };
  225. break;
  226. case 'log':
  227. var errors = [];
  228. handler = function(e) {
  229. if (arguments.length == 1) {
  230. errors.push(e);
  231. } else {
  232. errors.push([].slice.call(arguments, 0));
  233. }
  234. };
  235. handler.errors = errors;
  236. break;
  237. default:
  238. throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
  239. }
  240. };
  241. this.$get = function() {
  242. return handler;
  243. };
  244. this.mode('rethrow');
  245. };
  246. /**
  247. * @ngdoc service
  248. * @name ngMock.$log
  249. *
  250. * @description
  251. * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
  252. * (one array per logging level). These arrays are exposed as `logs` property of each of the
  253. * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
  254. *
  255. */
  256. angular.mock.$LogProvider = function() {
  257. function concat(array1, array2, index) {
  258. return array1.concat(Array.prototype.slice.call(array2, index));
  259. }
  260. this.$get = function () {
  261. var $log = {
  262. log: function() { $log.log.logs.push(concat([], arguments, 0)); },
  263. warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
  264. info: function() { $log.info.logs.push(concat([], arguments, 0)); },
  265. error: function() { $log.error.logs.push(concat([], arguments, 0)); }
  266. };
  267. /**
  268. * @ngdoc method
  269. * @name ngMock.$log#reset
  270. * @methodOf ngMock.$log
  271. *
  272. * @description
  273. * Reset all of the logging arrays to empty.
  274. */
  275. $log.reset = function () {
  276. /**
  277. * @ngdoc property
  278. * @name ngMock.$log#log.logs
  279. * @propertyOf ngMock.$log
  280. *
  281. * @description
  282. * Array of logged messages.
  283. */
  284. $log.log.logs = [];
  285. /**
  286. * @ngdoc property
  287. * @name ngMock.$log#warn.logs
  288. * @propertyOf ngMock.$log
  289. *
  290. * @description
  291. * Array of logged messages.
  292. */
  293. $log.warn.logs = [];
  294. /**
  295. * @ngdoc property
  296. * @name ngMock.$log#info.logs
  297. * @propertyOf ngMock.$log
  298. *
  299. * @description
  300. * Array of logged messages.
  301. */
  302. $log.info.logs = [];
  303. /**
  304. * @ngdoc property
  305. * @name ngMock.$log#error.logs
  306. * @propertyOf ngMock.$log
  307. *
  308. * @description
  309. * Array of logged messages.
  310. */
  311. $log.error.logs = [];
  312. };
  313. /**
  314. * @ngdoc method
  315. * @name ngMock.$log#assertEmpty
  316. * @methodOf ngMock.$log
  317. *
  318. * @description
  319. * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown.
  320. */
  321. $log.assertEmpty = function() {
  322. var errors = [];
  323. angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
  324. angular.forEach($log[logLevel].logs, function(log) {
  325. angular.forEach(log, function (logItem) {
  326. errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || ''));
  327. });
  328. });
  329. });
  330. if (errors.length) {
  331. errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
  332. "log message was not checked and removed:");
  333. errors.push('');
  334. throw new Error(errors.join('\n---------\n'));
  335. }
  336. };
  337. $log.reset();
  338. return $log;
  339. };
  340. };
  341. (function() {
  342. var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
  343. function jsonStringToDate(string){
  344. var match;
  345. if (match = string.match(R_ISO8061_STR)) {
  346. var date = new Date(0),
  347. tzHour = 0,
  348. tzMin = 0;
  349. if (match[9]) {
  350. tzHour = int(match[9] + match[10]);
  351. tzMin = int(match[9] + match[11]);
  352. }
  353. date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
  354. date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
  355. return date;
  356. }
  357. return string;
  358. }
  359. function int(str) {
  360. return parseInt(str, 10);
  361. }
  362. function padNumber(num, digits, trim) {
  363. var neg = '';
  364. if (num < 0) {
  365. neg = '-';
  366. num = -num;
  367. }
  368. num = '' + num;
  369. while(num.length < digits) num = '0' + num;
  370. if (trim)
  371. num = num.substr(num.length - digits);
  372. return neg + num;
  373. }
  374. /**
  375. * @ngdoc object
  376. * @name angular.mock.TzDate
  377. * @description
  378. *
  379. * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
  380. *
  381. * Mock of the Date type which has its timezone specified via constructor arg.
  382. *
  383. * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
  384. * offset, so that we can test code that depends on local timezone settings without dependency on
  385. * the time zone settings of the machine where the code is running.
  386. *
  387. * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
  388. * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
  389. *
  390. * @example
  391. * !!!! WARNING !!!!!
  392. * This is not a complete Date object so only methods that were implemented can be called safely.
  393. * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
  394. *
  395. * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
  396. * incomplete we might be missing some non-standard methods. This can result in errors like:
  397. * "Date.prototype.foo called on incompatible Object".
  398. *
  399. * <pre>
  400. * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
  401. * newYearInBratislava.getTimezoneOffset() => -60;
  402. * newYearInBratislava.getFullYear() => 2010;
  403. * newYearInBratislava.getMonth() => 0;
  404. * newYearInBratislava.getDate() => 1;
  405. * newYearInBratislava.getHours() => 0;
  406. * newYearInBratislava.getMinutes() => 0;
  407. * </pre>
  408. *
  409. */
  410. angular.mock.TzDate = function (offset, timestamp) {
  411. var self = new Date(0);
  412. if (angular.isString(timestamp)) {
  413. var tsStr = timestamp;
  414. self.origDate = jsonStringToDate(timestamp);
  415. timestamp = self.origDate.getTime();
  416. if (isNaN(timestamp))
  417. throw {
  418. name: "Illegal Argument",
  419. message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
  420. };
  421. } else {
  422. self.origDate = new Date(timestamp);
  423. }
  424. var localOffset = new Date(timestamp).getTimezoneOffset();
  425. self.offsetDiff = localOffset*60*1000 - offset*1000*60*60;
  426. self.date = new Date(timestamp + self.offsetDiff);
  427. self.getTime = function() {
  428. return self.date.getTime() - self.offsetDiff;
  429. };
  430. self.toLocaleDateString = function() {
  431. return self.date.toLocaleDateString();
  432. };
  433. self.getFullYear = function() {
  434. return self.date.getFullYear();
  435. };
  436. self.getMonth = function() {
  437. return self.date.getMonth();
  438. };
  439. self.getDate = function() {
  440. return self.date.getDate();
  441. };
  442. self.getHours = function() {
  443. return self.date.getHours();
  444. };
  445. self.getMinutes = function() {
  446. return self.date.getMinutes();
  447. };
  448. self.getSeconds = function() {
  449. return self.date.getSeconds();
  450. };
  451. self.getTimezoneOffset = function() {
  452. return offset * 60;
  453. };
  454. self.getUTCFullYear = function() {
  455. return self.origDate.getUTCFullYear();
  456. };
  457. self.getUTCMonth = function() {
  458. return self.origDate.getUTCMonth();
  459. };
  460. self.getUTCDate = function() {
  461. return self.origDate.getUTCDate();
  462. };
  463. self.getUTCHours = function() {
  464. return self.origDate.getUTCHours();
  465. };
  466. self.getUTCMinutes = function() {
  467. return self.origDate.getUTCMinutes();
  468. };
  469. self.getUTCSeconds = function() {
  470. return self.origDate.getUTCSeconds();
  471. };
  472. self.getUTCMilliseconds = function() {
  473. return self.origDate.getUTCMilliseconds();
  474. };
  475. self.getDay = function() {
  476. return self.date.getDay();
  477. };
  478. // provide this method only on browsers that already have it
  479. if (self.toISOString) {
  480. self.toISOString = function() {
  481. return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
  482. padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
  483. padNumber(self.origDate.getUTCDate(), 2) + 'T' +
  484. padNumber(self.origDate.getUTCHours(), 2) + ':' +
  485. padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
  486. padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
  487. padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'
  488. }
  489. }
  490. //hide all methods not implemented in this mock that the Date prototype exposes
  491. var unimplementedMethods = ['getMilliseconds', 'getUTCDay',
  492. 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
  493. 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
  494. 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
  495. 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
  496. 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
  497. angular.forEach(unimplementedMethods, function(methodName) {
  498. self[methodName] = function() {
  499. throw Error("Method '" + methodName + "' is not implemented in the TzDate mock");
  500. };
  501. });
  502. return self;
  503. };
  504. //make "tzDateInstance instanceof Date" return true
  505. angular.mock.TzDate.prototype = Date.prototype;
  506. })();
  507. /**
  508. * @ngdoc function
  509. * @name angular.mock.dump
  510. * @description
  511. *
  512. * *NOTE*: this is not an injectable instance, just a globally available function.
  513. *
  514. * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging.
  515. *
  516. * This method is also available on window, where it can be used to display objects on debug console.
  517. *
  518. * @param {*} object - any object to turn into string.
  519. * @return {string} a serialized string of the argument
  520. */
  521. angular.mock.dump = function(object) {
  522. return serialize(object);
  523. function serialize(object) {
  524. var out;
  525. if (angular.isElement(object)) {
  526. object = angular.element(object);
  527. out = angular.element('<div></div>');
  528. angular.forEach(object, function(element) {
  529. out.append(angular.element(element).clone());
  530. });
  531. out = out.html();
  532. } else if (angular.isArray(object)) {
  533. out = [];
  534. angular.forEach(object, function(o) {
  535. out.push(serialize(o));
  536. });
  537. out = '[ ' + out.join(', ') + ' ]';
  538. } else if (angular.isObject(object)) {
  539. if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
  540. out = serializeScope(object);
  541. } else if (object instanceof Error) {
  542. out = object.stack || ('' + object.name + ': ' + object.message);
  543. } else {
  544. out = angular.toJson(object, true);
  545. }
  546. } else {
  547. out = String(object);
  548. }
  549. return out;
  550. }
  551. function serializeScope(scope, offset) {
  552. offset = offset || ' ';
  553. var log = [offset + 'Scope(' + scope.$id + '): {'];
  554. for ( var key in scope ) {
  555. if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) {
  556. log.push(' ' + key + ': ' + angular.toJson(scope[key]));
  557. }
  558. }
  559. var child = scope.$$childHead;
  560. while(child) {
  561. log.push(serializeScope(child, offset + ' '));
  562. child = child.$$nextSibling;
  563. }
  564. log.push('}');
  565. return log.join('\n' + offset);
  566. }
  567. };
  568. /**
  569. * @ngdoc object
  570. * @name ngMock.$httpBackend
  571. * @description
  572. * Fake HTTP backend implementation suitable for unit testing application that use the
  573. * {@link ng.$http $http service}.
  574. *
  575. * *Note*: For fake http backend implementation suitable for end-to-end testing or backend-less
  576. * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
  577. *
  578. * During unit testing, we want our unit tests to run quickly and have no external dependencies so
  579. * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or
  580. * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is
  581. * to verify whether a certain request has been sent or not, or alternatively just let the
  582. * application make requests, respond with pre-trained responses and assert that the end result is
  583. * what we expect it to be.
  584. *
  585. * This mock implementation can be used to respond with static or dynamic responses via the
  586. * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
  587. *
  588. * When an Angular application needs some data from a server, it calls the $http service, which
  589. * sends the request to a real server using $httpBackend service. With dependency injection, it is
  590. * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
  591. * the requests and respond with some testing data without sending a request to real server.
  592. *
  593. * There are two ways to specify what test data should be returned as http responses by the mock
  594. * backend when the code under test makes http requests:
  595. *
  596. * - `$httpBackend.expect` - specifies a request expectation
  597. * - `$httpBackend.when` - specifies a backend definition
  598. *
  599. *
  600. * # Request Expectations vs Backend Definitions
  601. *
  602. * Request expectations provide a way to make assertions about requests made by the application and
  603. * to define responses for those requests. The test will fail if the expected requests are not made
  604. * or they are made in the wrong order.
  605. *
  606. * Backend definitions allow you to define a fake backend for your application which doesn't assert
  607. * if a particular request was made or not, it just returns a trained response if a request is made.
  608. * The test will pass whether or not the request gets made during testing.
  609. *
  610. *
  611. * <table class="table">
  612. * <tr><th width="220px"></th><th>Request expectations</th><th>Backend definitions</th></tr>
  613. * <tr>
  614. * <th>Syntax</th>
  615. * <td>.expect(...).respond(...)</td>
  616. * <td>.when(...).respond(...)</td>
  617. * </tr>
  618. * <tr>
  619. * <th>Typical usage</th>
  620. * <td>strict unit tests</td>
  621. * <td>loose (black-box) unit testing</td>
  622. * </tr>
  623. * <tr>
  624. * <th>Fulfills multiple requests</th>
  625. * <td>NO</td>
  626. * <td>YES</td>
  627. * </tr>
  628. * <tr>
  629. * <th>Order of requests matters</th>
  630. * <td>YES</td>
  631. * <td>NO</td>
  632. * </tr>
  633. * <tr>
  634. * <th>Request required</th>
  635. * <td>YES</td>
  636. * <td>NO</td>
  637. * </tr>
  638. * <tr>
  639. * <th>Response required</th>
  640. * <td>optional (see below)</td>
  641. * <td>YES</td>
  642. * </tr>
  643. * </table>
  644. *
  645. * In cases where both backend definitions and request expectations are specified during unit
  646. * testing, the request expectations are evaluated first.
  647. *
  648. * If a request expectation has no response specified, the algorithm will search your backend
  649. * definitions for an appropriate response.
  650. *
  651. * If a request didn't match any expectation or if the expectation doesn't have the response
  652. * defined, the backend definitions are evaluated in sequential order to see if any of them match
  653. * the request. The response from the first matched definition is returned.
  654. *
  655. *
  656. * # Flushing HTTP requests
  657. *
  658. * The $httpBackend used in production, always responds to requests with responses asynchronously.
  659. * If we preserved this behavior in unit testing, we'd have to create async unit tests, which are
  660. * hard to write, follow and maintain. At the same time the testing mock, can't respond
  661. * synchronously because that would change the execution of the code under test. For this reason the
  662. * mock $httpBackend has a `flush()` method, which allows the test to explicitly flush pending
  663. * requests and thus preserving the async api of the backend, while allowing the test to execute
  664. * synchronously.
  665. *
  666. *
  667. * # Unit testing with mock $httpBackend
  668. *
  669. * <pre>
  670. // controller
  671. function MyController($scope, $http) {
  672. $http.get('/auth.py').success(function(data) {
  673. $scope.user = data;
  674. });
  675. this.saveMessage = function(message) {
  676. $scope.status = 'Saving...';
  677. $http.post('/add-msg.py', message).success(function(response) {
  678. $scope.status = '';
  679. }).error(function() {
  680. $scope.status = 'ERROR!';
  681. });
  682. };
  683. }
  684. // testing controller
  685. var $httpBackend;
  686. beforeEach(inject(function($injector) {
  687. $httpBackend = $injector.get('$httpBackend');
  688. // backend definition common for all tests
  689. $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});
  690. }));
  691. afterEach(function() {
  692. $httpBackend.verifyNoOutstandingExpectation();
  693. $httpBackend.verifyNoOutstandingRequest();
  694. });
  695. it('should fetch authentication token', function() {
  696. $httpBackend.expectGET('/auth.py');
  697. var controller = scope.$new(MyController);
  698. $httpBackend.flush();
  699. });
  700. it('should send msg to server', function() {
  701. // now you don’t care about the authentication, but
  702. // the controller will still send the request and
  703. // $httpBackend will respond without you having to
  704. // specify the expectation and response for this request
  705. $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
  706. var controller = scope.$new(MyController);
  707. $httpBackend.flush();
  708. controller.saveMessage('message content');
  709. expect(controller.status).toBe('Saving...');
  710. $httpBackend.flush();
  711. expect(controller.status).toBe('');
  712. });
  713. it('should send auth header', function() {
  714. $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
  715. // check if the header was send, if it wasn't the expectation won't
  716. // match the request and the test will fail
  717. return headers['Authorization'] == 'xxx';
  718. }).respond(201, '');
  719. var controller = scope.$new(MyController);
  720. controller.saveMessage('whatever');
  721. $httpBackend.flush();
  722. });
  723. </pre>
  724. */
  725. angular.mock.$HttpBackendProvider = function() {
  726. this.$get = [createHttpBackendMock];
  727. };
  728. /**
  729. * General factory function for $httpBackend mock.
  730. * Returns instance for unit testing (when no arguments specified):
  731. * - passing through is disabled
  732. * - auto flushing is disabled
  733. *
  734. * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
  735. * - passing through (delegating request to real backend) is enabled
  736. * - auto flushing is enabled
  737. *
  738. * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
  739. * @param {Object=} $browser Auto-flushing enabled if specified
  740. * @return {Object} Instance of $httpBackend mock
  741. */
  742. function createHttpBackendMock($delegate, $browser) {
  743. var definitions = [],
  744. expectations = [],
  745. responses = [],
  746. responsesPush = angular.bind(responses, responses.push);
  747. function createResponse(status, data, headers) {
  748. if (angular.isFunction(status)) return status;
  749. return function() {
  750. return angular.isNumber(status)
  751. ? [status, data, headers]
  752. : [200, status, data];
  753. };
  754. }
  755. // TODO(vojta): change params to: method, url, data, headers, callback
  756. function $httpBackend(method, url, data, callback, headers) {
  757. var xhr = new MockXhr(),
  758. expectation = expectations[0],
  759. wasExpected = false;
  760. function prettyPrint(data) {
  761. return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
  762. ? data
  763. : angular.toJson(data);
  764. }
  765. if (expectation && expectation.match(method, url)) {
  766. if (!expectation.matchData(data))
  767. throw Error('Expected ' + expectation + ' with different data\n' +
  768. 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
  769. if (!expectation.matchHeaders(headers))
  770. throw Error('Expected ' + expectation + ' with different headers\n' +
  771. 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
  772. prettyPrint(headers));
  773. expectations.shift();
  774. if (expectation.response) {
  775. responses.push(function() {
  776. var response = expectation.response(method, url, data, headers);
  777. xhr.$$respHeaders = response[2];
  778. callback(response[0], response[1], xhr.getAllResponseHeaders());
  779. });
  780. return;
  781. }
  782. wasExpected = true;
  783. }
  784. var i = -1, definition;
  785. while ((definition = definitions[++i])) {
  786. if (definition.match(method, url, data, headers || {})) {
  787. if (definition.response) {
  788. // if $browser specified, we do auto flush all requests
  789. ($browser ? $browser.defer : responsesPush)(function() {
  790. var response = definition.response(method, url, data, headers);
  791. xhr.$$respHeaders = response[2];
  792. callback(response[0], response[1], xhr.getAllResponseHeaders());
  793. });
  794. } else if (definition.passThrough) {
  795. $delegate(method, url, data, callback, headers);
  796. } else throw Error('No response defined !');
  797. return;
  798. }
  799. }
  800. throw wasExpected ?
  801. Error('No response defined !') :
  802. Error('Unexpected request: ' + method + ' ' + url + '\n' +
  803. (expectation ? 'Expected ' + expectation : 'No more request expected'));
  804. }
  805. /**
  806. * @ngdoc method
  807. * @name ngMock.$httpBackend#when
  808. * @methodOf ngMock.$httpBackend
  809. * @description
  810. * Creates a new backend definition.
  811. *
  812. * @param {string} method HTTP method.
  813. * @param {string|RegExp} url HTTP url.
  814. * @param {(string|RegExp)=} data HTTP request body.
  815. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  816. * object and returns true if the headers match the current definition.
  817. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  818. * request is handled.
  819. *
  820. * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  821. * – The respond method takes a set of static data to be returned or a function that can return
  822. * an array containing response status (number), response data (string) and response headers
  823. * (Object).
  824. */
  825. $httpBackend.when = function(method, url, data, headers) {
  826. var definition = new MockHttpExpectation(method, url, data, headers),
  827. chain = {
  828. respond: function(status, data, headers) {
  829. definition.response = createResponse(status, data, headers);
  830. }
  831. };
  832. if ($browser) {
  833. chain.passThrough = function() {
  834. definition.passThrough = true;
  835. };
  836. }
  837. definitions.push(definition);
  838. return chain;
  839. };
  840. /**
  841. * @ngdoc method
  842. * @name ngMock.$httpBackend#whenGET
  843. * @methodOf ngMock.$httpBackend
  844. * @description
  845. * Creates a new backend definition for GET requests. For more info see `when()`.
  846. *
  847. * @param {string|RegExp} url HTTP url.
  848. * @param {(Object|function(Object))=} headers HTTP headers.
  849. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  850. * request is handled.
  851. */
  852. /**
  853. * @ngdoc method
  854. * @name ngMock.$httpBackend#whenHEAD
  855. * @methodOf ngMock.$httpBackend
  856. * @description
  857. * Creates a new backend definition for HEAD requests. For more info see `when()`.
  858. *
  859. * @param {string|RegExp} url HTTP url.
  860. * @param {(Object|function(Object))=} headers HTTP headers.
  861. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  862. * request is handled.
  863. */
  864. /**
  865. * @ngdoc method
  866. * @name ngMock.$httpBackend#whenDELETE
  867. * @methodOf ngMock.$httpBackend
  868. * @description
  869. * Creates a new backend definition for DELETE requests. For more info see `when()`.
  870. *
  871. * @param {string|RegExp} url HTTP url.
  872. * @param {(Object|function(Object))=} headers HTTP headers.
  873. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  874. * request is handled.
  875. */
  876. /**
  877. * @ngdoc method
  878. * @name ngMock.$httpBackend#whenPOST
  879. * @methodOf ngMock.$httpBackend
  880. * @description
  881. * Creates a new backend definition for POST requests. For more info see `when()`.
  882. *
  883. * @param {string|RegExp} url HTTP url.
  884. * @param {(string|RegExp)=} data HTTP request body.
  885. * @param {(Object|function(Object))=} headers HTTP headers.
  886. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  887. * request is handled.
  888. */
  889. /**
  890. * @ngdoc method
  891. * @name ngMock.$httpBackend#whenPUT
  892. * @methodOf ngMock.$httpBackend
  893. * @description
  894. * Creates a new backend definition for PUT requests. For more info see `when()`.
  895. *
  896. * @param {string|RegExp} url HTTP url.
  897. * @param {(string|RegExp)=} data HTTP request body.
  898. * @param {(Object|function(Object))=} headers HTTP headers.
  899. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  900. * request is handled.
  901. */
  902. /**
  903. * @ngdoc method
  904. * @name ngMock.$httpBackend#whenJSONP
  905. * @methodOf ngMock.$httpBackend
  906. * @description
  907. * Creates a new backend definition for JSONP requests. For more info see `when()`.
  908. *
  909. * @param {string|RegExp} url HTTP url.
  910. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  911. * request is handled.
  912. */
  913. createShortMethods('when');
  914. /**
  915. * @ngdoc method
  916. * @name ngMock.$httpBackend#expect
  917. * @methodOf ngMock.$httpBackend
  918. * @description
  919. * Creates a new request expectation.
  920. *
  921. * @param {string} method HTTP method.
  922. * @param {string|RegExp} url HTTP url.
  923. * @param {(string|RegExp)=} data HTTP request body.
  924. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  925. * object and returns true if the headers match the current expectation.
  926. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  927. * request is handled.
  928. *
  929. * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  930. * – The respond method takes a set of static data to be returned or a function that can return
  931. * an array containing response status (number), response data (string) and response headers
  932. * (Object).
  933. */
  934. $httpBackend.expect = function(method, url, data, headers) {
  935. var expectation = new MockHttpExpectation(method, url, data, headers);
  936. expectations.push(expectation);
  937. return {
  938. respond: function(status, data, headers) {
  939. expectation.response = createResponse(status, data, headers);
  940. }
  941. };
  942. };
  943. /**
  944. * @ngdoc method
  945. * @name ngMock.$httpBackend#expectGET
  946. * @methodOf ngMock.$httpBackend
  947. * @description
  948. * Creates a new request expectation for GET requests. For more info see `expect()`.
  949. *
  950. * @param {string|RegExp} url HTTP url.
  951. * @param {Object=} headers HTTP headers.
  952. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  953. * request is handled. See #expect for more info.
  954. */
  955. /**
  956. * @ngdoc method
  957. * @name ngMock.$httpBackend#expectHEAD
  958. * @methodOf ngMock.$httpBackend
  959. * @description
  960. * Creates a new request expectation for HEAD requests. For more info see `expect()`.
  961. *
  962. * @param {string|RegExp} url HTTP url.
  963. * @param {Object=} headers HTTP headers.
  964. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  965. * request is handled.
  966. */
  967. /**
  968. * @ngdoc method
  969. * @name ngMock.$httpBackend#expectDELETE
  970. * @methodOf ngMock.$httpBackend
  971. * @description
  972. * Creates a new request expectation for DELETE requests. For more info see `expect()`.
  973. *
  974. * @param {string|RegExp} url HTTP url.
  975. * @param {Object=} headers HTTP headers.
  976. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  977. * request is handled.
  978. */
  979. /**
  980. * @ngdoc method
  981. * @name ngMock.$httpBackend#expectPOST
  982. * @methodOf ngMock.$httpBackend
  983. * @description
  984. * Creates a new request expectation for POST requests. For more info see `expect()`.
  985. *
  986. * @param {string|RegExp} url HTTP url.
  987. * @param {(string|RegExp)=} data HTTP request body.
  988. * @param {Object=} headers HTTP headers.
  989. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  990. * request is handled.
  991. */
  992. /**
  993. * @ngdoc method
  994. * @name ngMock.$httpBackend#expectPUT
  995. * @methodOf ngMock.$httpBackend
  996. * @description
  997. * Creates a new request expectation for PUT requests. For more info see `expect()`.
  998. *
  999. * @param {string|RegExp} url HTTP url.
  1000. * @param {(string|RegExp)=} data HTTP request body.
  1001. * @param {Object=} headers HTTP headers.
  1002. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1003. * request is handled.
  1004. */
  1005. /**
  1006. * @ngdoc method
  1007. * @name ngMock.$httpBackend#expectPATCH
  1008. * @methodOf ngMock.$httpBackend
  1009. * @description
  1010. * Creates a new request expectation for PATCH requests. For more info see `expect()`.
  1011. *
  1012. * @param {string|RegExp} url HTTP url.
  1013. * @param {(string|RegExp)=} data HTTP request body.
  1014. * @param {Object=} headers HTTP headers.
  1015. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1016. * request is handled.
  1017. */
  1018. /**
  1019. * @ngdoc method
  1020. * @name ngMock.$httpBackend#expectJSONP
  1021. * @methodOf ngMock.$httpBackend
  1022. * @description
  1023. * Creates a new request expectation for JSONP requests. For more info see `expect()`.
  1024. *
  1025. * @param {string|RegExp} url HTTP url.
  1026. * @returns {requestHandler} Returns an object with `respond` method that control how a matched
  1027. * request is handled.
  1028. */
  1029. createShortMethods('expect');
  1030. /**
  1031. * @ngdoc method
  1032. * @name ngMock.$httpBackend#flush
  1033. * @methodOf ngMock.$httpBackend
  1034. * @description
  1035. * Flushes all pending requests using the trained responses.
  1036. *
  1037. * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
  1038. * all pending requests will be flushed. If there are no pending requests when the flush method
  1039. * is called an exception is thrown (as this typically a sign of programming error).
  1040. */
  1041. $httpBackend.flush = function(count) {
  1042. if (!responses.length) throw Error('No pending request to flush !');
  1043. if (angular.isDefined(count)) {
  1044. while (count--) {
  1045. if (!responses.length) throw Error('No more pending request to flush !');
  1046. responses.shift()();
  1047. }
  1048. } else {
  1049. while (responses.length) {
  1050. responses.shift()();
  1051. }
  1052. }
  1053. $httpBackend.verifyNoOutstandingExpectation();
  1054. };
  1055. /**
  1056. * @ngdoc method
  1057. * @name ngMock.$httpBackend#verifyNoOutstandingExpectation
  1058. * @methodOf ngMock.$httpBackend
  1059. * @description
  1060. * Verifies that all of the requests defined via the `expect` api were made. If any of the
  1061. * requests were not made, verifyNoOutstandingExpectation throws an exception.
  1062. *
  1063. * Typically, you would call this method following each test case that asserts requests using an
  1064. * "afterEach" clause.
  1065. *
  1066. * <pre>
  1067. * afterEach($httpBackend.verifyExpectations);
  1068. * </pre>
  1069. */
  1070. $httpBackend.verifyNoOutstandingExpectation = function() {
  1071. if (expectations.length) {
  1072. throw Error('Unsatisfied requests: ' + expectations.join(', '));
  1073. }
  1074. };
  1075. /**
  1076. * @ngdoc method
  1077. * @name ngMock.$httpBackend#verifyNoOutstandingRequest
  1078. * @methodOf ngMock.$httpBackend
  1079. * @description
  1080. * Verifies that there are no outstanding requests that need to be flushed.
  1081. *
  1082. * Typically, you would call this method following each test case that asserts requests using an
  1083. * "afterEach" clause.
  1084. *
  1085. * <pre>
  1086. * afterEach($httpBackend.verifyNoOutstandingRequest);
  1087. * </pre>
  1088. */
  1089. $httpBackend.verifyNoOutstandingRequest = function() {
  1090. if (responses.length) {
  1091. throw Error('Unflushed requests: ' + responses.length);
  1092. }
  1093. };
  1094. /**
  1095. * @ngdoc method
  1096. * @name ngMock.$httpBackend#resetExpectations
  1097. * @methodOf ngMock.$httpBackend
  1098. * @description
  1099. * Resets all request expectations, but preserves all backend definitions. Typically, you would
  1100. * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
  1101. * $httpBackend mock.
  1102. */
  1103. $httpBackend.resetExpectations = function() {
  1104. expectations.length = 0;
  1105. responses.length = 0;
  1106. };
  1107. return $httpBackend;
  1108. function createShortMethods(prefix) {
  1109. angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) {
  1110. $httpBackend[prefix + method] = function(url, headers) {
  1111. return $httpBackend[prefix](method, url, undefined, headers)
  1112. }
  1113. });
  1114. angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
  1115. $httpBackend[prefix + method] = function(url, data, headers) {
  1116. return $httpBackend[prefix](method, url, data, headers)
  1117. }
  1118. });
  1119. }
  1120. }
  1121. function MockHttpExpectation(method, url, data, headers) {
  1122. this.data = data;
  1123. this.headers = headers;
  1124. this.match = function(m, u, d, h) {
  1125. if (method != m) return false;
  1126. if (!this.matchUrl(u)) return false;
  1127. if (angular.isDefined(d) && !this.matchData(d)) return false;
  1128. if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
  1129. return true;
  1130. };
  1131. this.matchUrl = function(u) {
  1132. if (!url) return true;
  1133. if (angular.isFunction(url.test)) return url.test(u);
  1134. return url == u;
  1135. };
  1136. this.matchHeaders = function(h) {
  1137. if (angular.isUndefined(headers)) return true;
  1138. if (angular.isFunction(headers)) return headers(h);
  1139. return angular.equals(headers, h);
  1140. };
  1141. this.matchData = function(d) {
  1142. if (angular.isUndefined(data)) return true;
  1143. if (data && angular.isFunction(data.test)) return data.test(d);
  1144. if (data && !angular.isString(data)) return angular.toJson(data) == d;
  1145. return data == d;
  1146. };
  1147. this.toString = function() {
  1148. return method + ' ' + url;
  1149. };
  1150. }
  1151. function MockXhr() {
  1152. // hack for testing $http, $httpBackend
  1153. MockXhr.$$lastInstance = this;
  1154. this.open = function(method, url, async) {
  1155. this.$$method = method;
  1156. this.$$url = url;
  1157. this.$$async = async;
  1158. this.$$reqHeaders = {};
  1159. this.$$respHeaders = {};
  1160. };
  1161. this.send = function(data) {
  1162. this.$$data = data;
  1163. };
  1164. this.setRequestHeader = function(key, value) {
  1165. this.$$reqHeaders[key] = value;
  1166. };
  1167. this.getResponseHeader = function(name) {
  1168. // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last
  1169. var header = this.$$respHeaders[name];
  1170. if (header) return header;
  1171. name = angular.lowercase(name);
  1172. header = this.$$respHeaders[name];
  1173. if (header) return header;
  1174. header = undefined;
  1175. angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
  1176. if (!header && angular.lowercase(headerName) == name) header = headerVal;
  1177. });
  1178. return header;
  1179. };
  1180. this.getAllResponseHeaders = function() {
  1181. var lines = [];
  1182. angular.forEach(this.$$respHeaders, function(value, key) {
  1183. lines.push(key + ': ' + value);
  1184. });
  1185. return lines.join('\n');
  1186. };
  1187. this.abort = angular.noop;
  1188. }
  1189. /**
  1190. * @ngdoc function
  1191. * @name ngMock.$timeout
  1192. * @description
  1193. *
  1194. * This service is just a simple decorator for {@link ng.$timeout $timeout} service
  1195. * that adds a "flush" method.
  1196. */
  1197. /**
  1198. * @ngdoc method
  1199. * @name ngMock.$timeout#flush
  1200. * @methodOf ngMock.$timeout
  1201. * @description
  1202. *
  1203. * Flushes the queue of pending tasks.
  1204. */
  1205. /**
  1206. *
  1207. */
  1208. angular.mock.$RootElementProvider = function() {
  1209. this.$get = function() {
  1210. return angular.element('<div ng-app></div>');
  1211. }
  1212. };
  1213. /**
  1214. * @ngdoc overview
  1215. * @name ngMock
  1216. * @description
  1217. *
  1218. * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful
  1219. * mocks to the {@link AUTO.$injector $injector}.
  1220. */
  1221. angular.module('ngMock', ['ng']).provider({
  1222. $browser: angular.mock.$BrowserProvider,
  1223. $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
  1224. $log: angular.mock.$LogProvider,
  1225. $httpBackend: angular.mock.$HttpBackendProvider,
  1226. $rootElement: angular.mock.$RootElementProvider
  1227. }).config(function($provide) {
  1228. $provide.decorator('$timeout', function($delegate, $browser) {
  1229. $delegate.flush = function() {
  1230. $browser.defer.flush();
  1231. };
  1232. return $delegate;
  1233. });
  1234. });
  1235. /**
  1236. * @ngdoc overview
  1237. * @name ngMockE2E
  1238. * @description
  1239. *
  1240. * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
  1241. * Currently there is only one mock present in this module -
  1242. * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
  1243. */
  1244. angular.module('ngMockE2E', ['ng']).config(function($provide) {
  1245. $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
  1246. });
  1247. /**
  1248. * @ngdoc object
  1249. * @name ngMockE2E.$httpBackend
  1250. * @description
  1251. * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
  1252. * applications that use the {@link ng.$http $http service}.
  1253. *
  1254. * *Note*: For fake http backend implementation suitable for unit testing please see
  1255. * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
  1256. *
  1257. * This implementation can be used to respond with static or dynamic responses via the `when` api
  1258. * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
  1259. * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
  1260. * templates from a webserver).
  1261. *
  1262. * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
  1263. * is being developed with the real backend api replaced with a mock, it is often desirable for
  1264. * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
  1265. * templates or static files from the webserver). To configure the backend with this behavior
  1266. * use the `passThrough` request handler of `when` instead of `respond`.
  1267. *
  1268. * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
  1269. * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests
  1270. * automatically, closely simulating the behavior of the XMLHttpRequest object.
  1271. *
  1272. * To setup the application to run with this http backend, you have to create a module that depends
  1273. * on the `ngMockE2E` and your application modules and defines the fake backend:
  1274. *
  1275. * <pre>
  1276. * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
  1277. * myAppDev.run(function($httpBackend) {
  1278. * phones = [{name: 'phone1'}, {name: 'phone2'}];
  1279. *
  1280. * // returns the current list of phones
  1281. * $httpBackend.whenGET('/phones').respond(phones);
  1282. *
  1283. * // adds a new phone to the phones array
  1284. * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
  1285. * phones.push(angular.fromJSON(data));
  1286. * });
  1287. * $httpBackend.whenGET(/^\/templates\//).passThrough();
  1288. * //...
  1289. * });
  1290. * </pre>
  1291. *
  1292. * Afterwards, bootstrap your app with this new module.
  1293. */
  1294. /**
  1295. * @ngdoc method
  1296. * @name ngMockE2E.$httpBackend#when
  1297. * @methodOf ngMockE2E.$httpBackend
  1298. * @description
  1299. * Creates a new backend definition.
  1300. *
  1301. * @param {string} method HTTP method.
  1302. * @param {string|RegExp} url HTTP url.
  1303. * @param {(string|RegExp)=} data HTTP request body.
  1304. * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
  1305. * object and returns true if the headers match the current definition.
  1306. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1307. * control how a matched request is handled.
  1308. *
  1309. * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}`
  1310. * – The respond method takes a set of static data to be returned or a function that can return
  1311. * an array containing response status (number), response data (string) and response headers
  1312. * (Object).
  1313. * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough`
  1314. * handler, will be pass through to the real backend (an XHR request will be made to the
  1315. * server.
  1316. */
  1317. /**
  1318. * @ngdoc method
  1319. * @name ngMockE2E.$httpBackend#whenGET
  1320. * @methodOf ngMockE2E.$httpBackend
  1321. * @description
  1322. * Creates a new backend definition for GET requests. For more info see `when()`.
  1323. *
  1324. * @param {string|RegExp} url HTTP url.
  1325. * @param {(Object|function(Object))=} headers HTTP headers.
  1326. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1327. * control how a matched request is handled.
  1328. */
  1329. /**
  1330. * @ngdoc method
  1331. * @name ngMockE2E.$httpBackend#whenHEAD
  1332. * @methodOf ngMockE2E.$httpBackend
  1333. * @description
  1334. * Creates a new backend definition for HEAD requests. For more info see `when()`.
  1335. *
  1336. * @param {string|RegExp} url HTTP url.
  1337. * @param {(Object|function(Object))=} headers HTTP headers.
  1338. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1339. * control how a matched request is handled.
  1340. */
  1341. /**
  1342. * @ngdoc method
  1343. * @name ngMockE2E.$httpBackend#whenDELETE
  1344. * @methodOf ngMockE2E.$httpBackend
  1345. * @description
  1346. * Creates a new backend definition for DELETE requests. For more info see `when()`.
  1347. *
  1348. * @param {string|RegExp} url HTTP url.
  1349. * @param {(Object|function(Object))=} headers HTTP headers.
  1350. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1351. * control how a matched request is handled.
  1352. */
  1353. /**
  1354. * @ngdoc method
  1355. * @name ngMockE2E.$httpBackend#whenPOST
  1356. * @methodOf ngMockE2E.$httpBackend
  1357. * @description
  1358. * Creates a new backend definition for POST requests. For more info see `when()`.
  1359. *
  1360. * @param {string|RegExp} url HTTP url.
  1361. * @param {(string|RegExp)=} data HTTP request body.
  1362. * @param {(Object|function(Object))=} headers HTTP headers.
  1363. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1364. * control how a matched request is handled.
  1365. */
  1366. /**
  1367. * @ngdoc method
  1368. * @name ngMockE2E.$httpBackend#whenPUT
  1369. * @methodOf ngMockE2E.$httpBackend
  1370. * @description
  1371. * Creates a new backend definition for PUT requests. For more info see `when()`.
  1372. *
  1373. * @param {string|RegExp} url HTTP url.
  1374. * @param {(string|RegExp)=} data HTTP request body.
  1375. * @param {(Object|function(Object))=} headers HTTP headers.
  1376. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1377. * control how a matched request is handled.
  1378. */
  1379. /**
  1380. * @ngdoc method
  1381. * @name ngMockE2E.$httpBackend#whenPATCH
  1382. * @methodOf ngMockE2E.$httpBackend
  1383. * @description
  1384. * Creates a new backend definition for PATCH requests. For more info see `when()`.
  1385. *
  1386. * @param {string|RegExp} url HTTP url.
  1387. * @param {(string|RegExp)=} data HTTP request body.
  1388. * @param {(Object|function(Object))=} headers HTTP headers.
  1389. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1390. * control how a matched request is handled.
  1391. */
  1392. /**
  1393. * @ngdoc method
  1394. * @name ngMockE2E.$httpBackend#whenJSONP
  1395. * @methodOf ngMockE2E.$httpBackend
  1396. * @description
  1397. * Creates a new backend definition for JSONP requests. For more info see `when()`.
  1398. *
  1399. * @param {string|RegExp} url HTTP url.
  1400. * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
  1401. * control how a matched request is handled.
  1402. */
  1403. angular.mock.e2e = {};
  1404. angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$browser', createHttpBackendMock];
  1405. angular.mock.clearDataCache = function() {
  1406. var key,
  1407. cache = angular.element.cache;
  1408. for(key in cache) {
  1409. if (cache.hasOwnProperty(key)) {
  1410. var handle = cache[key].handle;
  1411. handle && angular.element(handle.elem).unbind();
  1412. delete cache[key];
  1413. }
  1414. }
  1415. };
  1416. window.jstestdriver && (function(window) {
  1417. /**
  1418. * Global method to output any number of objects into JSTD console. Useful for debugging.
  1419. */
  1420. window.dump = function() {
  1421. var args = [];
  1422. angular.forEach(arguments, function(arg) {
  1423. args.push(angular.mock.dump(arg));
  1424. });
  1425. jstestdriver.console.log.apply(jstestdriver.console, args);
  1426. if (window.console) {
  1427. window.console.log.apply(window.console, args);
  1428. }
  1429. };
  1430. })(window);
  1431. window.jasmine && (function(window) {
  1432. afterEach(function() {
  1433. var spec = getCurrentSpec();
  1434. var injector = spec.$injector;
  1435. spec.$injector = null;
  1436. spec.$modules = null;
  1437. if (injector) {
  1438. injector.get('$rootElement').unbind();
  1439. injector.get('$browser').pollFns.length = 0;
  1440. }
  1441. angular.mock.clearDataCache();
  1442. // clean up jquery's fragment cache
  1443. angular.forEach(angular.element.fragments, function(val, key) {
  1444. delete angular.element.fragments[key];
  1445. });
  1446. MockXhr.$$lastInstance = null;
  1447. angular.forEach(angular.callbacks, function(val, key) {
  1448. delete angular.callbacks[key];
  1449. });
  1450. angular.callbacks.counter = 0;
  1451. });
  1452. function getCurrentSpec() {
  1453. return jasmine.getEnv().currentSpec;
  1454. }
  1455. function isSpecRunning() {
  1456. var spec = getCurrentSpec();
  1457. return spec && spec.queue.running;
  1458. }
  1459. /**
  1460. * @ngdoc function
  1461. * @name angular.mock.module
  1462. * @description
  1463. *
  1464. * *NOTE*: This function is also published on window for easy access.<br>
  1465. * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
  1466. *
  1467. * This function registers a module configuration code. It collects the configuration information
  1468. * which will be used when the injector is created by {@link angular.mock.inject inject}.
  1469. *
  1470. * See {@link angular.mock.inject inject} for usage example
  1471. *
  1472. * @param {...(string|Function)} fns any number of modules which are represented as string
  1473. * aliases or as anonymous module initialization functions. The modules are used to
  1474. * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded.
  1475. */
  1476. window.module = angular.mock.module = function() {
  1477. var moduleFns = Array.prototype.slice.call(arguments, 0);
  1478. return isSpecRunning() ? workFn() : workFn;
  1479. /////////////////////
  1480. function workFn() {
  1481. var spec = getCurrentSpec();
  1482. if (spec.$injector) {
  1483. throw Error('Injector already created, can not register a module!');
  1484. } else {
  1485. var modules = spec.$modules || (spec.$modules = []);
  1486. angular.forEach(moduleFns, function(module) {
  1487. modules.push(module);
  1488. });
  1489. }
  1490. }
  1491. };
  1492. /**
  1493. * @ngdoc function
  1494. * @name angular.mock.inject
  1495. * @description
  1496. *
  1497. <<<<<<< HEAD
  1498. * *NOTE*: This is function is also published on window for easy access.<br>
  1499. * *NOTE*: Only available with {@link http://pivotal.github.com/jasmine/ jasmine}.
  1500. =======
  1501. * *NOTE*: This function is also published on window for easy access.<br>
  1502. >>>>>>> 8dca056... docs(mocks): fix typos
  1503. *
  1504. * The inject function wraps a function into an injectable function. The inject() creates new
  1505. * instance of {@link AUTO.$injector $injector} per test, which is then used for
  1506. * resolving references.
  1507. *
  1508. * See also {@link angular.mock.module module}
  1509. *
  1510. * Example of what a typical jasmine tests looks like with the inject method.
  1511. * <pre>
  1512. *
  1513. * angular.module('myApplicationModule', [])
  1514. * .value('mode', 'app')
  1515. * .value('version', 'v1.0.1');
  1516. *
  1517. *
  1518. * describe('MyApp', function() {
  1519. *
  1520. * // You need to load modules that you want to test,
  1521. * // it loads only the "ng" module by default.
  1522. * beforeEach(module('myApplicationModule'));
  1523. *
  1524. *
  1525. * // inject() is used to inject arguments of all given functions
  1526. * it('should provide a version', inject(function(mode, version) {
  1527. * expect(version).toEqual('v1.0.1');
  1528. * expect(mode).toEqual('app');
  1529. * }));
  1530. *
  1531. *
  1532. * // The inject and module method can also be used inside of the it or beforeEach
  1533. * it('should override a version and test the new version is injected', function() {
  1534. * // module() takes functions or strings (module aliases)
  1535. * module(function($provide) {
  1536. * $provide.value('version', 'overridden'); // override version here
  1537. * });
  1538. *
  1539. * inject(function(version) {
  1540. * expect(version).toEqual('overridden');
  1541. * });
  1542. * ));
  1543. * });
  1544. *
  1545. * </pre>
  1546. *
  1547. * @param {...Function} fns any number of functions which will be injected using the injector.
  1548. */
  1549. window.inject = angular.mock.inject = function() {
  1550. var blockFns = Array.prototype.slice.call(arguments, 0);
  1551. var errorForStack = new Error('Declaration Location');
  1552. return isSpecRunning() ? workFn() : workFn;
  1553. /////////////////////
  1554. function workFn() {
  1555. var spec = getCurrentSpec();
  1556. var modules = spec.$modules || [];
  1557. modules.unshift('ngMock');
  1558. modules.unshift('ng');
  1559. var injector = spec.$injector;
  1560. if (!injector) {
  1561. injector = spec.$injector = angular.injector(modules);
  1562. }
  1563. for(var i = 0, ii = blockFns.length; i < ii; i++) {
  1564. try {
  1565. injector.invoke(blockFns[i] || angular.noop, this);
  1566. } catch (e) {
  1567. if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
  1568. throw e;
  1569. } finally {
  1570. errorForStack = null;
  1571. }
  1572. }
  1573. }
  1574. };
  1575. })(window);