├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── index.html ├── js │ ├── app.js │ ├── directives.js │ └── services.js └── partials │ ├── .gitkeep │ ├── lorem-image.html │ └── partial1.html ├── bower.json ├── config ├── karma-e2e.conf.js └── karma.conf.js ├── logs └── .gitkeep ├── package.json ├── scripts ├── e2e-test.bat ├── e2e-test.sh ├── test.bat ├── test.sh ├── watchr.rb └── web-server.js └── test ├── e2e ├── runner.html └── scenarios.js ├── lib └── angular │ ├── angular-mocks.js │ ├── angular-scenario.js │ └── version.txt └── unit ├── controllersSpec.js ├── directivesSpec.js ├── filtersSpec.js └── servicesSpec.js /.gitignore: -------------------------------------------------------------------------------- 1 | logs/* 2 | !.gitkeep 3 | node_modules/ 4 | tmp 5 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | 5 | before_script: 6 | - export DISPLAY=:99.0 7 | - sh -e /etc/init.d/xvfb start 8 | - npm install --quiet -g karma 9 | - ./scripts/web-server.js > /dev/null & 10 | - sleep 1 # give server time to start 11 | 12 | script: 13 | - karma start config/karma.conf.js --no-auto-watch --single-run --reporters=dots --browsers=Firefox 14 | - karma start config/karma-e2e.conf.js --reporters=dots --browsers=Firefox 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 matthieu-D 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-lorem-image 2 | 3 | ```html 4 | bower install angular-lorem-image 5 | ``` 6 | This directive provides lorem image generation for your website by using the great lorempixel service to generate images. 7 | Options: 8 |
' + escapeHtml(util.inspect(error)) + ''); 113 | util.puts('500 Internal Server Error'); 114 | util.puts(util.inspect(error)); 115 | }; 116 | 117 | StaticServlet.prototype.sendMissing_ = function(req, res, path) { 118 | path = path.substring(1); 119 | res.writeHead(404, { 120 | 'Content-Type': 'text/html' 121 | }); 122 | res.write('\n'); 123 | res.write('
The requested URL ' + 127 | escapeHtml(path) + 128 | ' was not found on this server.
' 129 | ); 130 | res.end(); 131 | util.puts('404 Not Found: ' + path); 132 | }; 133 | 134 | StaticServlet.prototype.sendForbidden_ = function(req, res, path) { 135 | path = path.substring(1); 136 | res.writeHead(403, { 137 | 'Content-Type': 'text/html' 138 | }); 139 | res.write('\n'); 140 | res.write('You do not have permission to access ' + 144 | escapeHtml(path) + ' on this server.
' 145 | ); 146 | res.end(); 147 | util.puts('403 Forbidden: ' + path); 148 | }; 149 | 150 | StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) { 151 | res.writeHead(301, { 152 | 'Content-Type': 'text/html', 153 | 'Location': redirectUrl 154 | }); 155 | res.write('\n'); 156 | res.write('The document has moved here.
' 162 | ); 163 | res.end(); 164 | util.puts('301 Moved Permanently: ' + redirectUrl); 165 | }; 166 | 167 | StaticServlet.prototype.sendFile_ = function(req, res, path) { 168 | var self = this; 169 | var file = fs.createReadStream(path); 170 | res.writeHead(200, { 171 | 'Content-Type': StaticServlet. 172 | MimeMap[path.split('.').pop()] || 'text/plain' 173 | }); 174 | if (req.method === 'HEAD') { 175 | res.end(); 176 | } else { 177 | file.on('data', res.write.bind(res)); 178 | file.on('close', function() { 179 | res.end(); 180 | }); 181 | file.on('error', function(error) { 182 | self.sendError_(req, res, error); 183 | }); 184 | } 185 | }; 186 | 187 | StaticServlet.prototype.sendDirectory_ = function(req, res, path) { 188 | var self = this; 189 | if (path.match(/[^\/]$/)) { 190 | req.url.pathname += '/'; 191 | var redirectUrl = url.format(url.parse(url.format(req.url))); 192 | return self.sendRedirect_(req, res, redirectUrl); 193 | } 194 | fs.readdir(path, function(err, files) { 195 | if (err) 196 | return self.sendError_(req, res, error); 197 | 198 | if (!files.length) 199 | return self.writeDirectoryIndex_(req, res, path, []); 200 | 201 | var remaining = files.length; 202 | files.forEach(function(fileName, index) { 203 | fs.stat(path + '/' + fileName, function(err, stat) { 204 | if (err) 205 | return self.sendError_(req, res, err); 206 | if (stat.isDirectory()) { 207 | files[index] = fileName + '/'; 208 | } 209 | if (!(--remaining)) 210 | return self.writeDirectoryIndex_(req, res, path, files); 211 | }); 212 | }); 213 | }); 214 | }; 215 | 216 | StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) { 217 | path = path.substring(1); 218 | res.writeHead(200, { 219 | 'Content-Type': 'text/html' 220 | }); 221 | if (req.method === 'HEAD') { 222 | res.end(); 223 | return; 224 | } 225 | res.write('\n'); 226 | res.write('209 | * describe('$exceptionHandlerProvider', function() { 210 | * 211 | * it('should capture log messages and exceptions', function() { 212 | * 213 | * module(function($exceptionHandlerProvider) { 214 | * $exceptionHandlerProvider.mode('log'); 215 | * }); 216 | * 217 | * inject(function($log, $exceptionHandler, $timeout) { 218 | * $timeout(function() { $log.log(1); }); 219 | * $timeout(function() { $log.log(2); throw 'banana peel'; }); 220 | * $timeout(function() { $log.log(3); }); 221 | * expect($exceptionHandler.errors).toEqual([]); 222 | * expect($log.assertEmpty()); 223 | * $timeout.flush(); 224 | * expect($exceptionHandler.errors).toEqual(['banana peel']); 225 | * expect($log.log.logs).toEqual([[1], [2], [3]]); 226 | * }); 227 | * }); 228 | * }); 229 | *230 | */ 231 | 232 | angular.mock.$ExceptionHandlerProvider = function() { 233 | var handler; 234 | 235 | /** 236 | * @ngdoc method 237 | * @name ngMock.$exceptionHandlerProvider#mode 238 | * @methodOf ngMock.$exceptionHandlerProvider 239 | * 240 | * @description 241 | * Sets the logging mode. 242 | * 243 | * @param {string} mode Mode of operation, defaults to `rethrow`. 244 | * 245 | * - `rethrow`: If any errors are passed into the handler in tests, it typically 246 | * means that there is a bug in the application or test, so this mock will 247 | * make these tests fail. 248 | * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` 249 | * mode stores an array of errors in `$exceptionHandler.errors`, to allow later 250 | * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and 251 | * {@link ngMock.$log#reset reset()} 252 | */ 253 | this.mode = function(mode) { 254 | switch(mode) { 255 | case 'rethrow': 256 | handler = function(e) { 257 | throw e; 258 | }; 259 | break; 260 | case 'log': 261 | var errors = []; 262 | 263 | handler = function(e) { 264 | if (arguments.length == 1) { 265 | errors.push(e); 266 | } else { 267 | errors.push([].slice.call(arguments, 0)); 268 | } 269 | }; 270 | 271 | handler.errors = errors; 272 | break; 273 | default: 274 | throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!"); 275 | } 276 | }; 277 | 278 | this.$get = function() { 279 | return handler; 280 | }; 281 | 282 | this.mode('rethrow'); 283 | }; 284 | 285 | 286 | /** 287 | * @ngdoc service 288 | * @name ngMock.$log 289 | * 290 | * @description 291 | * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays 292 | * (one array per logging level). These arrays are exposed as `logs` property of each of the 293 | * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`. 294 | * 295 | */ 296 | angular.mock.$LogProvider = function() { 297 | var debug = true; 298 | 299 | function concat(array1, array2, index) { 300 | return array1.concat(Array.prototype.slice.call(array2, index)); 301 | } 302 | 303 | this.debugEnabled = function(flag) { 304 | if (angular.isDefined(flag)) { 305 | debug = flag; 306 | return this; 307 | } else { 308 | return debug; 309 | } 310 | }; 311 | 312 | this.$get = function () { 313 | var $log = { 314 | log: function() { $log.log.logs.push(concat([], arguments, 0)); }, 315 | warn: function() { $log.warn.logs.push(concat([], arguments, 0)); }, 316 | info: function() { $log.info.logs.push(concat([], arguments, 0)); }, 317 | error: function() { $log.error.logs.push(concat([], arguments, 0)); }, 318 | debug: function() { 319 | if (debug) { 320 | $log.debug.logs.push(concat([], arguments, 0)); 321 | } 322 | } 323 | }; 324 | 325 | /** 326 | * @ngdoc method 327 | * @name ngMock.$log#reset 328 | * @methodOf ngMock.$log 329 | * 330 | * @description 331 | * Reset all of the logging arrays to empty. 332 | */ 333 | $log.reset = function () { 334 | /** 335 | * @ngdoc property 336 | * @name ngMock.$log#log.logs 337 | * @propertyOf ngMock.$log 338 | * 339 | * @description 340 | * Array of messages logged using {@link ngMock.$log#log}. 341 | * 342 | * @example 343 | *
344 | * $log.log('Some Log'); 345 | * var first = $log.log.logs.unshift(); 346 | *347 | */ 348 | $log.log.logs = []; 349 | /** 350 | * @ngdoc property 351 | * @name ngMock.$log#info.logs 352 | * @propertyOf ngMock.$log 353 | * 354 | * @description 355 | * Array of messages logged using {@link ngMock.$log#info}. 356 | * 357 | * @example 358 | *
359 | * $log.info('Some Info'); 360 | * var first = $log.info.logs.unshift(); 361 | *362 | */ 363 | $log.info.logs = []; 364 | /** 365 | * @ngdoc property 366 | * @name ngMock.$log#warn.logs 367 | * @propertyOf ngMock.$log 368 | * 369 | * @description 370 | * Array of messages logged using {@link ngMock.$log#warn}. 371 | * 372 | * @example 373 | *
374 | * $log.warn('Some Warning'); 375 | * var first = $log.warn.logs.unshift(); 376 | *377 | */ 378 | $log.warn.logs = []; 379 | /** 380 | * @ngdoc property 381 | * @name ngMock.$log#error.logs 382 | * @propertyOf ngMock.$log 383 | * 384 | * @description 385 | * Array of messages logged using {@link ngMock.$log#error}. 386 | * 387 | * @example 388 | *
389 | * $log.log('Some Error'); 390 | * var first = $log.error.logs.unshift(); 391 | *392 | */ 393 | $log.error.logs = []; 394 | /** 395 | * @ngdoc property 396 | * @name ngMock.$log#debug.logs 397 | * @propertyOf ngMock.$log 398 | * 399 | * @description 400 | * Array of messages logged using {@link ngMock.$log#debug}. 401 | * 402 | * @example 403 | *
404 | * $log.debug('Some Error'); 405 | * var first = $log.debug.logs.unshift(); 406 | *407 | */ 408 | $log.debug.logs = []; 409 | }; 410 | 411 | /** 412 | * @ngdoc method 413 | * @name ngMock.$log#assertEmpty 414 | * @methodOf ngMock.$log 415 | * 416 | * @description 417 | * Assert that the all of the logging methods have no logged messages. If messages present, an 418 | * exception is thrown. 419 | */ 420 | $log.assertEmpty = function() { 421 | var errors = []; 422 | angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) { 423 | angular.forEach($log[logLevel].logs, function(log) { 424 | angular.forEach(log, function (logItem) { 425 | errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + 426 | (logItem.stack || '')); 427 | }); 428 | }); 429 | }); 430 | if (errors.length) { 431 | errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or "+ 432 | "an expected log message was not checked and removed:"); 433 | errors.push(''); 434 | throw new Error(errors.join('\n---------\n')); 435 | } 436 | }; 437 | 438 | $log.reset(); 439 | return $log; 440 | }; 441 | }; 442 | 443 | 444 | /** 445 | * @ngdoc service 446 | * @name ngMock.$interval 447 | * 448 | * @description 449 | * Mock implementation of the $interval service. 450 | * 451 | * Use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to 452 | * move forward by `millis` milliseconds and trigger any functions scheduled to run in that 453 | * time. 454 | * 455 | * @param {function()} fn A function that should be called repeatedly. 456 | * @param {number} delay Number of milliseconds between each function call. 457 | * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat 458 | * indefinitely. 459 | * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise 460 | * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block. 461 | * @returns {promise} A promise which will be notified on each iteration. 462 | */ 463 | angular.mock.$IntervalProvider = function() { 464 | this.$get = ['$rootScope', '$q', 465 | function($rootScope, $q) { 466 | var repeatFns = [], 467 | nextRepeatId = 0, 468 | now = 0; 469 | 470 | var $interval = function(fn, delay, count, invokeApply) { 471 | var deferred = $q.defer(), 472 | promise = deferred.promise, 473 | iteration = 0, 474 | skipApply = (angular.isDefined(invokeApply) && !invokeApply); 475 | 476 | count = (angular.isDefined(count)) ? count : 0, 477 | promise.then(null, null, fn); 478 | 479 | promise.$$intervalId = nextRepeatId; 480 | 481 | function tick() { 482 | deferred.notify(iteration++); 483 | 484 | if (count > 0 && iteration >= count) { 485 | var fnIndex; 486 | deferred.resolve(iteration); 487 | 488 | angular.forEach(repeatFns, function(fn, index) { 489 | if (fn.id === promise.$$intervalId) fnIndex = index; 490 | }); 491 | 492 | if (fnIndex !== undefined) { 493 | repeatFns.splice(fnIndex, 1); 494 | } 495 | } 496 | 497 | if (!skipApply) $rootScope.$apply(); 498 | } 499 | 500 | repeatFns.push({ 501 | nextTime:(now + delay), 502 | delay: delay, 503 | fn: tick, 504 | id: nextRepeatId, 505 | deferred: deferred 506 | }); 507 | repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;}); 508 | 509 | nextRepeatId++; 510 | return promise; 511 | }; 512 | 513 | $interval.cancel = function(promise) { 514 | var fnIndex; 515 | 516 | angular.forEach(repeatFns, function(fn, index) { 517 | if (fn.id === promise.$$intervalId) fnIndex = index; 518 | }); 519 | 520 | if (fnIndex !== undefined) { 521 | repeatFns[fnIndex].deferred.reject('canceled'); 522 | repeatFns.splice(fnIndex, 1); 523 | return true; 524 | } 525 | 526 | return false; 527 | }; 528 | 529 | /** 530 | * @ngdoc method 531 | * @name ngMock.$interval#flush 532 | * @methodOf ngMock.$interval 533 | * @description 534 | * 535 | * Runs interval tasks scheduled to be run in the next `millis` milliseconds. 536 | * 537 | * @param {number=} millis maximum timeout amount to flush up until. 538 | * 539 | * @return {number} The amount of time moved forward. 540 | */ 541 | $interval.flush = function(millis) { 542 | now += millis; 543 | while (repeatFns.length && repeatFns[0].nextTime <= now) { 544 | var task = repeatFns[0]; 545 | task.fn(); 546 | task.nextTime += task.delay; 547 | repeatFns.sort(function(a,b){ return a.nextTime - b.nextTime;}); 548 | } 549 | return millis; 550 | }; 551 | 552 | return $interval; 553 | }]; 554 | }; 555 | 556 | 557 | /* jshint -W101 */ 558 | /* The R_ISO8061_STR regex is never going to fit into the 100 char limit! 559 | * This directive should go inside the anonymous function but a bug in JSHint means that it would 560 | * not be enacted early enough to prevent the warning. 561 | */ 562 | var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/; 563 | 564 | function jsonStringToDate(string) { 565 | var match; 566 | if (match = string.match(R_ISO8061_STR)) { 567 | var date = new Date(0), 568 | tzHour = 0, 569 | tzMin = 0; 570 | if (match[9]) { 571 | tzHour = int(match[9] + match[10]); 572 | tzMin = int(match[9] + match[11]); 573 | } 574 | date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3])); 575 | date.setUTCHours(int(match[4]||0) - tzHour, 576 | int(match[5]||0) - tzMin, 577 | int(match[6]||0), 578 | int(match[7]||0)); 579 | return date; 580 | } 581 | return string; 582 | } 583 | 584 | function int(str) { 585 | return parseInt(str, 10); 586 | } 587 | 588 | function padNumber(num, digits, trim) { 589 | var neg = ''; 590 | if (num < 0) { 591 | neg = '-'; 592 | num = -num; 593 | } 594 | num = '' + num; 595 | while(num.length < digits) num = '0' + num; 596 | if (trim) 597 | num = num.substr(num.length - digits); 598 | return neg + num; 599 | } 600 | 601 | 602 | /** 603 | * @ngdoc object 604 | * @name angular.mock.TzDate 605 | * @description 606 | * 607 | * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. 608 | * 609 | * Mock of the Date type which has its timezone specified via constructor arg. 610 | * 611 | * The main purpose is to create Date-like instances with timezone fixed to the specified timezone 612 | * offset, so that we can test code that depends on local timezone settings without dependency on 613 | * the time zone settings of the machine where the code is running. 614 | * 615 | * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) 616 | * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* 617 | * 618 | * @example 619 | * !!!! WARNING !!!!! 620 | * This is not a complete Date object so only methods that were implemented can be called safely. 621 | * To make matters worse, TzDate instances inherit stuff from Date via a prototype. 622 | * 623 | * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is 624 | * incomplete we might be missing some non-standard methods. This can result in errors like: 625 | * "Date.prototype.foo called on incompatible Object". 626 | * 627 | *
628 | * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); 629 | * newYearInBratislava.getTimezoneOffset() => -60; 630 | * newYearInBratislava.getFullYear() => 2010; 631 | * newYearInBratislava.getMonth() => 0; 632 | * newYearInBratislava.getDate() => 1; 633 | * newYearInBratislava.getHours() => 0; 634 | * newYearInBratislava.getMinutes() => 0; 635 | * newYearInBratislava.getSeconds() => 0; 636 | *637 | * 638 | */ 639 | angular.mock.TzDate = function (offset, timestamp) { 640 | var self = new Date(0); 641 | if (angular.isString(timestamp)) { 642 | var tsStr = timestamp; 643 | 644 | self.origDate = jsonStringToDate(timestamp); 645 | 646 | timestamp = self.origDate.getTime(); 647 | if (isNaN(timestamp)) 648 | throw { 649 | name: "Illegal Argument", 650 | message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" 651 | }; 652 | } else { 653 | self.origDate = new Date(timestamp); 654 | } 655 | 656 | var localOffset = new Date(timestamp).getTimezoneOffset(); 657 | self.offsetDiff = localOffset*60*1000 - offset*1000*60*60; 658 | self.date = new Date(timestamp + self.offsetDiff); 659 | 660 | self.getTime = function() { 661 | return self.date.getTime() - self.offsetDiff; 662 | }; 663 | 664 | self.toLocaleDateString = function() { 665 | return self.date.toLocaleDateString(); 666 | }; 667 | 668 | self.getFullYear = function() { 669 | return self.date.getFullYear(); 670 | }; 671 | 672 | self.getMonth = function() { 673 | return self.date.getMonth(); 674 | }; 675 | 676 | self.getDate = function() { 677 | return self.date.getDate(); 678 | }; 679 | 680 | self.getHours = function() { 681 | return self.date.getHours(); 682 | }; 683 | 684 | self.getMinutes = function() { 685 | return self.date.getMinutes(); 686 | }; 687 | 688 | self.getSeconds = function() { 689 | return self.date.getSeconds(); 690 | }; 691 | 692 | self.getMilliseconds = function() { 693 | return self.date.getMilliseconds(); 694 | }; 695 | 696 | self.getTimezoneOffset = function() { 697 | return offset * 60; 698 | }; 699 | 700 | self.getUTCFullYear = function() { 701 | return self.origDate.getUTCFullYear(); 702 | }; 703 | 704 | self.getUTCMonth = function() { 705 | return self.origDate.getUTCMonth(); 706 | }; 707 | 708 | self.getUTCDate = function() { 709 | return self.origDate.getUTCDate(); 710 | }; 711 | 712 | self.getUTCHours = function() { 713 | return self.origDate.getUTCHours(); 714 | }; 715 | 716 | self.getUTCMinutes = function() { 717 | return self.origDate.getUTCMinutes(); 718 | }; 719 | 720 | self.getUTCSeconds = function() { 721 | return self.origDate.getUTCSeconds(); 722 | }; 723 | 724 | self.getUTCMilliseconds = function() { 725 | return self.origDate.getUTCMilliseconds(); 726 | }; 727 | 728 | self.getDay = function() { 729 | return self.date.getDay(); 730 | }; 731 | 732 | // provide this method only on browsers that already have it 733 | if (self.toISOString) { 734 | self.toISOString = function() { 735 | return padNumber(self.origDate.getUTCFullYear(), 4) + '-' + 736 | padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' + 737 | padNumber(self.origDate.getUTCDate(), 2) + 'T' + 738 | padNumber(self.origDate.getUTCHours(), 2) + ':' + 739 | padNumber(self.origDate.getUTCMinutes(), 2) + ':' + 740 | padNumber(self.origDate.getUTCSeconds(), 2) + '.' + 741 | padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z'; 742 | }; 743 | } 744 | 745 | //hide all methods not implemented in this mock that the Date prototype exposes 746 | var unimplementedMethods = ['getUTCDay', 747 | 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 748 | 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 749 | 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 750 | 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString', 751 | 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; 752 | 753 | angular.forEach(unimplementedMethods, function(methodName) { 754 | self[methodName] = function() { 755 | throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock"); 756 | }; 757 | }); 758 | 759 | return self; 760 | }; 761 | 762 | //make "tzDateInstance instanceof Date" return true 763 | angular.mock.TzDate.prototype = Date.prototype; 764 | /* jshint +W101 */ 765 | 766 | angular.mock.animate = angular.module('mock.animate', ['ng']) 767 | 768 | .config(['$provide', function($provide) { 769 | 770 | $provide.decorator('$animate', function($delegate) { 771 | var animate = { 772 | queue : [], 773 | enabled : $delegate.enabled, 774 | flushNext : function(name) { 775 | var tick = animate.queue.shift(); 776 | 777 | if (!tick) throw new Error('No animation to be flushed'); 778 | if(tick.method !== name) { 779 | throw new Error('The next animation is not "' + name + 780 | '", but is "' + tick.method + '"'); 781 | } 782 | tick.fn(); 783 | return tick; 784 | } 785 | }; 786 | 787 | angular.forEach(['enter','leave','move','addClass','removeClass'], function(method) { 788 | animate[method] = function() { 789 | var params = arguments; 790 | animate.queue.push({ 791 | method : method, 792 | params : params, 793 | element : angular.isElement(params[0]) && params[0], 794 | parent : angular.isElement(params[1]) && params[1], 795 | after : angular.isElement(params[2]) && params[2], 796 | fn : function() { 797 | $delegate[method].apply($delegate, params); 798 | } 799 | }); 800 | }; 801 | }); 802 | 803 | return animate; 804 | }); 805 | 806 | }]); 807 | 808 | 809 | /** 810 | * @ngdoc function 811 | * @name angular.mock.dump 812 | * @description 813 | * 814 | * *NOTE*: this is not an injectable instance, just a globally available function. 815 | * 816 | * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for 817 | * debugging. 818 | * 819 | * This method is also available on window, where it can be used to display objects on debug 820 | * console. 821 | * 822 | * @param {*} object - any object to turn into string. 823 | * @return {string} a serialized string of the argument 824 | */ 825 | angular.mock.dump = function(object) { 826 | return serialize(object); 827 | 828 | function serialize(object) { 829 | var out; 830 | 831 | if (angular.isElement(object)) { 832 | object = angular.element(object); 833 | out = angular.element(''); 834 | angular.forEach(object, function(element) { 835 | out.append(angular.element(element).clone()); 836 | }); 837 | out = out.html(); 838 | } else if (angular.isArray(object)) { 839 | out = []; 840 | angular.forEach(object, function(o) { 841 | out.push(serialize(o)); 842 | }); 843 | out = '[ ' + out.join(', ') + ' ]'; 844 | } else if (angular.isObject(object)) { 845 | if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) { 846 | out = serializeScope(object); 847 | } else if (object instanceof Error) { 848 | out = object.stack || ('' + object.name + ': ' + object.message); 849 | } else { 850 | // TODO(i): this prevents methods being logged, 851 | // we should have a better way to serialize objects 852 | out = angular.toJson(object, true); 853 | } 854 | } else { 855 | out = String(object); 856 | } 857 | 858 | return out; 859 | } 860 | 861 | function serializeScope(scope, offset) { 862 | offset = offset || ' '; 863 | var log = [offset + 'Scope(' + scope.$id + '): {']; 864 | for ( var key in scope ) { 865 | if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) { 866 | log.push(' ' + key + ': ' + angular.toJson(scope[key])); 867 | } 868 | } 869 | var child = scope.$$childHead; 870 | while(child) { 871 | log.push(serializeScope(child, offset + ' ')); 872 | child = child.$$nextSibling; 873 | } 874 | log.push('}'); 875 | return log.join('\n' + offset); 876 | } 877 | }; 878 | 879 | /** 880 | * @ngdoc object 881 | * @name ngMock.$httpBackend 882 | * @description 883 | * Fake HTTP backend implementation suitable for unit testing applications that use the 884 | * {@link ng.$http $http service}. 885 | * 886 | * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less 887 | * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}. 888 | * 889 | * During unit testing, we want our unit tests to run quickly and have no external dependencies so 890 | * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or 891 | * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is 892 | * to verify whether a certain request has been sent or not, or alternatively just let the 893 | * application make requests, respond with pre-trained responses and assert that the end result is 894 | * what we expect it to be. 895 | * 896 | * This mock implementation can be used to respond with static or dynamic responses via the 897 | * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc). 898 | * 899 | * When an Angular application needs some data from a server, it calls the $http service, which 900 | * sends the request to a real server using $httpBackend service. With dependency injection, it is 901 | * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify 902 | * the requests and respond with some testing data without sending a request to real server. 903 | * 904 | * There are two ways to specify what test data should be returned as http responses by the mock 905 | * backend when the code under test makes http requests: 906 | * 907 | * - `$httpBackend.expect` - specifies a request expectation 908 | * - `$httpBackend.when` - specifies a backend definition 909 | * 910 | * 911 | * # Request Expectations vs Backend Definitions 912 | * 913 | * Request expectations provide a way to make assertions about requests made by the application and 914 | * to define responses for those requests. The test will fail if the expected requests are not made 915 | * or they are made in the wrong order. 916 | * 917 | * Backend definitions allow you to define a fake backend for your application which doesn't assert 918 | * if a particular request was made or not, it just returns a trained response if a request is made. 919 | * The test will pass whether or not the request gets made during testing. 920 | * 921 | * 922 | *
Request expectations | Backend definitions | |
---|---|---|
Syntax | 926 | *.expect(...).respond(...) | 927 | *.when(...).respond(...) | 928 | *
Typical usage | 931 | *strict unit tests | 932 | *loose (black-box) unit testing | 933 | *
Fulfills multiple requests | 936 | *NO | 937 | *YES | 938 | *
Order of requests matters | 941 | *YES | 942 | *NO | 943 | *
Request required | 946 | *YES | 947 | *NO | 948 | *
Response required | 951 | *optional (see below) | 952 | *YES | 953 | *
983 | // The controller code 984 | function MyController($scope, $http) { 985 | var authToken; 986 | 987 | $http.get('/auth.py').success(function(data, status, headers) { 988 | authToken = headers('A-Token'); 989 | $scope.user = data; 990 | }); 991 | 992 | $scope.saveMessage = function(message) { 993 | var headers = { 'Authorization': authToken }; 994 | $scope.status = 'Saving...'; 995 | 996 | $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) { 997 | $scope.status = ''; 998 | }).error(function() { 999 | $scope.status = 'ERROR!'; 1000 | }); 1001 | }; 1002 | } 1003 |1004 | * 1005 | * Now we setup the mock backend and create the test specs. 1006 | * 1007 |
1008 | // testing controller 1009 | describe('MyController', function() { 1010 | var $httpBackend, $rootScope, createController; 1011 | 1012 | beforeEach(inject(function($injector) { 1013 | // Set up the mock http service responses 1014 | $httpBackend = $injector.get('$httpBackend'); 1015 | // backend definition common for all tests 1016 | $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'}); 1017 | 1018 | // Get hold of a scope (i.e. the root scope) 1019 | $rootScope = $injector.get('$rootScope'); 1020 | // The $controller service is used to create instances of controllers 1021 | var $controller = $injector.get('$controller'); 1022 | 1023 | createController = function() { 1024 | return $controller('MyController', {'$scope' : $rootScope }); 1025 | }; 1026 | })); 1027 | 1028 | 1029 | afterEach(function() { 1030 | $httpBackend.verifyNoOutstandingExpectation(); 1031 | $httpBackend.verifyNoOutstandingRequest(); 1032 | }); 1033 | 1034 | 1035 | it('should fetch authentication token', function() { 1036 | $httpBackend.expectGET('/auth.py'); 1037 | var controller = createController(); 1038 | $httpBackend.flush(); 1039 | }); 1040 | 1041 | 1042 | it('should send msg to server', function() { 1043 | var controller = createController(); 1044 | $httpBackend.flush(); 1045 | 1046 | // now you don’t care about the authentication, but 1047 | // the controller will still send the request and 1048 | // $httpBackend will respond without you having to 1049 | // specify the expectation and response for this request 1050 | 1051 | $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, ''); 1052 | $rootScope.saveMessage('message content'); 1053 | expect($rootScope.status).toBe('Saving...'); 1054 | $httpBackend.flush(); 1055 | expect($rootScope.status).toBe(''); 1056 | }); 1057 | 1058 | 1059 | it('should send auth header', function() { 1060 | var controller = createController(); 1061 | $httpBackend.flush(); 1062 | 1063 | $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) { 1064 | // check if the header was send, if it wasn't the expectation won't 1065 | // match the request and the test will fail 1066 | return headers['Authorization'] == 'xxx'; 1067 | }).respond(201, ''); 1068 | 1069 | $rootScope.saveMessage('whatever'); 1070 | $httpBackend.flush(); 1071 | }); 1072 | }); 1073 |1074 | */ 1075 | angular.mock.$HttpBackendProvider = function() { 1076 | this.$get = ['$rootScope', createHttpBackendMock]; 1077 | }; 1078 | 1079 | /** 1080 | * General factory function for $httpBackend mock. 1081 | * Returns instance for unit testing (when no arguments specified): 1082 | * - passing through is disabled 1083 | * - auto flushing is disabled 1084 | * 1085 | * Returns instance for e2e testing (when `$delegate` and `$browser` specified): 1086 | * - passing through (delegating request to real backend) is enabled 1087 | * - auto flushing is enabled 1088 | * 1089 | * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified) 1090 | * @param {Object=} $browser Auto-flushing enabled if specified 1091 | * @return {Object} Instance of $httpBackend mock 1092 | */ 1093 | function createHttpBackendMock($rootScope, $delegate, $browser) { 1094 | var definitions = [], 1095 | expectations = [], 1096 | responses = [], 1097 | responsesPush = angular.bind(responses, responses.push); 1098 | 1099 | function createResponse(status, data, headers) { 1100 | if (angular.isFunction(status)) return status; 1101 | 1102 | return function() { 1103 | return angular.isNumber(status) 1104 | ? [status, data, headers] 1105 | : [200, status, data]; 1106 | }; 1107 | } 1108 | 1109 | // TODO(vojta): change params to: method, url, data, headers, callback 1110 | function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) { 1111 | var xhr = new MockXhr(), 1112 | expectation = expectations[0], 1113 | wasExpected = false; 1114 | 1115 | function prettyPrint(data) { 1116 | return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp) 1117 | ? data 1118 | : angular.toJson(data); 1119 | } 1120 | 1121 | function wrapResponse(wrapped) { 1122 | if (!$browser && timeout && timeout.then) timeout.then(handleTimeout); 1123 | 1124 | return handleResponse; 1125 | 1126 | function handleResponse() { 1127 | var response = wrapped.response(method, url, data, headers); 1128 | xhr.$$respHeaders = response[2]; 1129 | callback(response[0], response[1], xhr.getAllResponseHeaders()); 1130 | } 1131 | 1132 | function handleTimeout() { 1133 | for (var i = 0, ii = responses.length; i < ii; i++) { 1134 | if (responses[i] === handleResponse) { 1135 | responses.splice(i, 1); 1136 | callback(-1, undefined, ''); 1137 | break; 1138 | } 1139 | } 1140 | } 1141 | } 1142 | 1143 | if (expectation && expectation.match(method, url)) { 1144 | if (!expectation.matchData(data)) 1145 | throw new Error('Expected ' + expectation + ' with different data\n' + 1146 | 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data); 1147 | 1148 | if (!expectation.matchHeaders(headers)) 1149 | throw new Error('Expected ' + expectation + ' with different headers\n' + 1150 | 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + 1151 | prettyPrint(headers)); 1152 | 1153 | expectations.shift(); 1154 | 1155 | if (expectation.response) { 1156 | responses.push(wrapResponse(expectation)); 1157 | return; 1158 | } 1159 | wasExpected = true; 1160 | } 1161 | 1162 | var i = -1, definition; 1163 | while ((definition = definitions[++i])) { 1164 | if (definition.match(method, url, data, headers || {})) { 1165 | if (definition.response) { 1166 | // if $browser specified, we do auto flush all requests 1167 | ($browser ? $browser.defer : responsesPush)(wrapResponse(definition)); 1168 | } else if (definition.passThrough) { 1169 | $delegate(method, url, data, callback, headers, timeout, withCredentials); 1170 | } else throw new Error('No response defined !'); 1171 | return; 1172 | } 1173 | } 1174 | throw wasExpected ? 1175 | new Error('No response defined !') : 1176 | new Error('Unexpected request: ' + method + ' ' + url + '\n' + 1177 | (expectation ? 'Expected ' + expectation : 'No more request expected')); 1178 | } 1179 | 1180 | /** 1181 | * @ngdoc method 1182 | * @name ngMock.$httpBackend#when 1183 | * @methodOf ngMock.$httpBackend 1184 | * @description 1185 | * Creates a new backend definition. 1186 | * 1187 | * @param {string} method HTTP method. 1188 | * @param {string|RegExp} url HTTP url. 1189 | * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives 1190 | * data string and returns true if the data is as expected. 1191 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 1192 | * object and returns true if the headers match the current definition. 1193 | * @returns {requestHandler} Returns an object with `respond` method that controls how a matched 1194 | * request is handled. 1195 | * 1196 | * - respond – 1197 | * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 1198 | * – The respond method takes a set of static data to be returned or a function that can return 1199 | * an array containing response status (number), response data (string) and response headers 1200 | * (Object). 1201 | */ 1202 | $httpBackend.when = function(method, url, data, headers) { 1203 | var definition = new MockHttpExpectation(method, url, data, headers), 1204 | chain = { 1205 | respond: function(status, data, headers) { 1206 | definition.response = createResponse(status, data, headers); 1207 | } 1208 | }; 1209 | 1210 | if ($browser) { 1211 | chain.passThrough = function() { 1212 | definition.passThrough = true; 1213 | }; 1214 | } 1215 | 1216 | definitions.push(definition); 1217 | return chain; 1218 | }; 1219 | 1220 | /** 1221 | * @ngdoc method 1222 | * @name ngMock.$httpBackend#whenGET 1223 | * @methodOf ngMock.$httpBackend 1224 | * @description 1225 | * Creates a new backend definition for GET requests. For more info see `when()`. 1226 | * 1227 | * @param {string|RegExp} url HTTP url. 1228 | * @param {(Object|function(Object))=} headers HTTP headers. 1229 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1230 | * request is handled. 1231 | */ 1232 | 1233 | /** 1234 | * @ngdoc method 1235 | * @name ngMock.$httpBackend#whenHEAD 1236 | * @methodOf ngMock.$httpBackend 1237 | * @description 1238 | * Creates a new backend definition for HEAD requests. For more info see `when()`. 1239 | * 1240 | * @param {string|RegExp} url HTTP url. 1241 | * @param {(Object|function(Object))=} headers HTTP headers. 1242 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1243 | * request is handled. 1244 | */ 1245 | 1246 | /** 1247 | * @ngdoc method 1248 | * @name ngMock.$httpBackend#whenDELETE 1249 | * @methodOf ngMock.$httpBackend 1250 | * @description 1251 | * Creates a new backend definition for DELETE requests. For more info see `when()`. 1252 | * 1253 | * @param {string|RegExp} url HTTP url. 1254 | * @param {(Object|function(Object))=} headers HTTP headers. 1255 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1256 | * request is handled. 1257 | */ 1258 | 1259 | /** 1260 | * @ngdoc method 1261 | * @name ngMock.$httpBackend#whenPOST 1262 | * @methodOf ngMock.$httpBackend 1263 | * @description 1264 | * Creates a new backend definition for POST requests. For more info see `when()`. 1265 | * 1266 | * @param {string|RegExp} url HTTP url. 1267 | * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives 1268 | * data string and returns true if the data is as expected. 1269 | * @param {(Object|function(Object))=} headers HTTP headers. 1270 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1271 | * request is handled. 1272 | */ 1273 | 1274 | /** 1275 | * @ngdoc method 1276 | * @name ngMock.$httpBackend#whenPUT 1277 | * @methodOf ngMock.$httpBackend 1278 | * @description 1279 | * Creates a new backend definition for PUT requests. For more info see `when()`. 1280 | * 1281 | * @param {string|RegExp} url HTTP url. 1282 | * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives 1283 | * data string and returns true if the data is as expected. 1284 | * @param {(Object|function(Object))=} headers HTTP headers. 1285 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1286 | * request is handled. 1287 | */ 1288 | 1289 | /** 1290 | * @ngdoc method 1291 | * @name ngMock.$httpBackend#whenJSONP 1292 | * @methodOf ngMock.$httpBackend 1293 | * @description 1294 | * Creates a new backend definition for JSONP requests. For more info see `when()`. 1295 | * 1296 | * @param {string|RegExp} url HTTP url. 1297 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1298 | * request is handled. 1299 | */ 1300 | createShortMethods('when'); 1301 | 1302 | 1303 | /** 1304 | * @ngdoc method 1305 | * @name ngMock.$httpBackend#expect 1306 | * @methodOf ngMock.$httpBackend 1307 | * @description 1308 | * Creates a new request expectation. 1309 | * 1310 | * @param {string} method HTTP method. 1311 | * @param {string|RegExp} url HTTP url. 1312 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1313 | * receives data string and returns true if the data is as expected, or Object if request body 1314 | * is in JSON format. 1315 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 1316 | * object and returns true if the headers match the current expectation. 1317 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1318 | * request is handled. 1319 | * 1320 | * - respond – 1321 | * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 1322 | * – The respond method takes a set of static data to be returned or a function that can return 1323 | * an array containing response status (number), response data (string) and response headers 1324 | * (Object). 1325 | */ 1326 | $httpBackend.expect = function(method, url, data, headers) { 1327 | var expectation = new MockHttpExpectation(method, url, data, headers); 1328 | expectations.push(expectation); 1329 | return { 1330 | respond: function(status, data, headers) { 1331 | expectation.response = createResponse(status, data, headers); 1332 | } 1333 | }; 1334 | }; 1335 | 1336 | 1337 | /** 1338 | * @ngdoc method 1339 | * @name ngMock.$httpBackend#expectGET 1340 | * @methodOf ngMock.$httpBackend 1341 | * @description 1342 | * Creates a new request expectation for GET requests. For more info see `expect()`. 1343 | * 1344 | * @param {string|RegExp} url HTTP url. 1345 | * @param {Object=} headers HTTP headers. 1346 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1347 | * request is handled. See #expect for more info. 1348 | */ 1349 | 1350 | /** 1351 | * @ngdoc method 1352 | * @name ngMock.$httpBackend#expectHEAD 1353 | * @methodOf ngMock.$httpBackend 1354 | * @description 1355 | * Creates a new request expectation for HEAD requests. For more info see `expect()`. 1356 | * 1357 | * @param {string|RegExp} url HTTP url. 1358 | * @param {Object=} headers HTTP headers. 1359 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1360 | * request is handled. 1361 | */ 1362 | 1363 | /** 1364 | * @ngdoc method 1365 | * @name ngMock.$httpBackend#expectDELETE 1366 | * @methodOf ngMock.$httpBackend 1367 | * @description 1368 | * Creates a new request expectation for DELETE requests. For more info see `expect()`. 1369 | * 1370 | * @param {string|RegExp} url HTTP url. 1371 | * @param {Object=} headers HTTP headers. 1372 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1373 | * request is handled. 1374 | */ 1375 | 1376 | /** 1377 | * @ngdoc method 1378 | * @name ngMock.$httpBackend#expectPOST 1379 | * @methodOf ngMock.$httpBackend 1380 | * @description 1381 | * Creates a new request expectation for POST requests. For more info see `expect()`. 1382 | * 1383 | * @param {string|RegExp} url HTTP url. 1384 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1385 | * receives data string and returns true if the data is as expected, or Object if request body 1386 | * is in JSON format. 1387 | * @param {Object=} headers HTTP headers. 1388 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1389 | * request is handled. 1390 | */ 1391 | 1392 | /** 1393 | * @ngdoc method 1394 | * @name ngMock.$httpBackend#expectPUT 1395 | * @methodOf ngMock.$httpBackend 1396 | * @description 1397 | * Creates a new request expectation for PUT requests. For more info see `expect()`. 1398 | * 1399 | * @param {string|RegExp} url HTTP url. 1400 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1401 | * receives data string and returns true if the data is as expected, or Object if request body 1402 | * is in JSON format. 1403 | * @param {Object=} headers HTTP headers. 1404 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1405 | * request is handled. 1406 | */ 1407 | 1408 | /** 1409 | * @ngdoc method 1410 | * @name ngMock.$httpBackend#expectPATCH 1411 | * @methodOf ngMock.$httpBackend 1412 | * @description 1413 | * Creates a new request expectation for PATCH requests. For more info see `expect()`. 1414 | * 1415 | * @param {string|RegExp} url HTTP url. 1416 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1417 | * receives data string and returns true if the data is as expected, or Object if request body 1418 | * is in JSON format. 1419 | * @param {Object=} headers HTTP headers. 1420 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1421 | * request is handled. 1422 | */ 1423 | 1424 | /** 1425 | * @ngdoc method 1426 | * @name ngMock.$httpBackend#expectJSONP 1427 | * @methodOf ngMock.$httpBackend 1428 | * @description 1429 | * Creates a new request expectation for JSONP requests. For more info see `expect()`. 1430 | * 1431 | * @param {string|RegExp} url HTTP url. 1432 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1433 | * request is handled. 1434 | */ 1435 | createShortMethods('expect'); 1436 | 1437 | 1438 | /** 1439 | * @ngdoc method 1440 | * @name ngMock.$httpBackend#flush 1441 | * @methodOf ngMock.$httpBackend 1442 | * @description 1443 | * Flushes all pending requests using the trained responses. 1444 | * 1445 | * @param {number=} count Number of responses to flush (in the order they arrived). If undefined, 1446 | * all pending requests will be flushed. If there are no pending requests when the flush method 1447 | * is called an exception is thrown (as this typically a sign of programming error). 1448 | */ 1449 | $httpBackend.flush = function(count) { 1450 | $rootScope.$digest(); 1451 | if (!responses.length) throw new Error('No pending request to flush !'); 1452 | 1453 | if (angular.isDefined(count)) { 1454 | while (count--) { 1455 | if (!responses.length) throw new Error('No more pending request to flush !'); 1456 | responses.shift()(); 1457 | } 1458 | } else { 1459 | while (responses.length) { 1460 | responses.shift()(); 1461 | } 1462 | } 1463 | $httpBackend.verifyNoOutstandingExpectation(); 1464 | }; 1465 | 1466 | 1467 | /** 1468 | * @ngdoc method 1469 | * @name ngMock.$httpBackend#verifyNoOutstandingExpectation 1470 | * @methodOf ngMock.$httpBackend 1471 | * @description 1472 | * Verifies that all of the requests defined via the `expect` api were made. If any of the 1473 | * requests were not made, verifyNoOutstandingExpectation throws an exception. 1474 | * 1475 | * Typically, you would call this method following each test case that asserts requests using an 1476 | * "afterEach" clause. 1477 | * 1478 | *
1479 | * afterEach($httpBackend.verifyNoOutstandingExpectation); 1480 | *1481 | */ 1482 | $httpBackend.verifyNoOutstandingExpectation = function() { 1483 | $rootScope.$digest(); 1484 | if (expectations.length) { 1485 | throw new Error('Unsatisfied requests: ' + expectations.join(', ')); 1486 | } 1487 | }; 1488 | 1489 | 1490 | /** 1491 | * @ngdoc method 1492 | * @name ngMock.$httpBackend#verifyNoOutstandingRequest 1493 | * @methodOf ngMock.$httpBackend 1494 | * @description 1495 | * Verifies that there are no outstanding requests that need to be flushed. 1496 | * 1497 | * Typically, you would call this method following each test case that asserts requests using an 1498 | * "afterEach" clause. 1499 | * 1500 | *
1501 | * afterEach($httpBackend.verifyNoOutstandingRequest); 1502 | *1503 | */ 1504 | $httpBackend.verifyNoOutstandingRequest = function() { 1505 | if (responses.length) { 1506 | throw new Error('Unflushed requests: ' + responses.length); 1507 | } 1508 | }; 1509 | 1510 | 1511 | /** 1512 | * @ngdoc method 1513 | * @name ngMock.$httpBackend#resetExpectations 1514 | * @methodOf ngMock.$httpBackend 1515 | * @description 1516 | * Resets all request expectations, but preserves all backend definitions. Typically, you would 1517 | * call resetExpectations during a multiple-phase test when you want to reuse the same instance of 1518 | * $httpBackend mock. 1519 | */ 1520 | $httpBackend.resetExpectations = function() { 1521 | expectations.length = 0; 1522 | responses.length = 0; 1523 | }; 1524 | 1525 | return $httpBackend; 1526 | 1527 | 1528 | function createShortMethods(prefix) { 1529 | angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) { 1530 | $httpBackend[prefix + method] = function(url, headers) { 1531 | return $httpBackend[prefix](method, url, undefined, headers); 1532 | }; 1533 | }); 1534 | 1535 | angular.forEach(['PUT', 'POST', 'PATCH'], function(method) { 1536 | $httpBackend[prefix + method] = function(url, data, headers) { 1537 | return $httpBackend[prefix](method, url, data, headers); 1538 | }; 1539 | }); 1540 | } 1541 | } 1542 | 1543 | function MockHttpExpectation(method, url, data, headers) { 1544 | 1545 | this.data = data; 1546 | this.headers = headers; 1547 | 1548 | this.match = function(m, u, d, h) { 1549 | if (method != m) return false; 1550 | if (!this.matchUrl(u)) return false; 1551 | if (angular.isDefined(d) && !this.matchData(d)) return false; 1552 | if (angular.isDefined(h) && !this.matchHeaders(h)) return false; 1553 | return true; 1554 | }; 1555 | 1556 | this.matchUrl = function(u) { 1557 | if (!url) return true; 1558 | if (angular.isFunction(url.test)) return url.test(u); 1559 | return url == u; 1560 | }; 1561 | 1562 | this.matchHeaders = function(h) { 1563 | if (angular.isUndefined(headers)) return true; 1564 | if (angular.isFunction(headers)) return headers(h); 1565 | return angular.equals(headers, h); 1566 | }; 1567 | 1568 | this.matchData = function(d) { 1569 | if (angular.isUndefined(data)) return true; 1570 | if (data && angular.isFunction(data.test)) return data.test(d); 1571 | if (data && angular.isFunction(data)) return data(d); 1572 | if (data && !angular.isString(data)) return angular.equals(data, angular.fromJson(d)); 1573 | return data == d; 1574 | }; 1575 | 1576 | this.toString = function() { 1577 | return method + ' ' + url; 1578 | }; 1579 | } 1580 | 1581 | function MockXhr() { 1582 | 1583 | // hack for testing $http, $httpBackend 1584 | MockXhr.$$lastInstance = this; 1585 | 1586 | this.open = function(method, url, async) { 1587 | this.$$method = method; 1588 | this.$$url = url; 1589 | this.$$async = async; 1590 | this.$$reqHeaders = {}; 1591 | this.$$respHeaders = {}; 1592 | }; 1593 | 1594 | this.send = function(data) { 1595 | this.$$data = data; 1596 | }; 1597 | 1598 | this.setRequestHeader = function(key, value) { 1599 | this.$$reqHeaders[key] = value; 1600 | }; 1601 | 1602 | this.getResponseHeader = function(name) { 1603 | // the lookup must be case insensitive, 1604 | // that's why we try two quick lookups first and full scan last 1605 | var header = this.$$respHeaders[name]; 1606 | if (header) return header; 1607 | 1608 | name = angular.lowercase(name); 1609 | header = this.$$respHeaders[name]; 1610 | if (header) return header; 1611 | 1612 | header = undefined; 1613 | angular.forEach(this.$$respHeaders, function(headerVal, headerName) { 1614 | if (!header && angular.lowercase(headerName) == name) header = headerVal; 1615 | }); 1616 | return header; 1617 | }; 1618 | 1619 | this.getAllResponseHeaders = function() { 1620 | var lines = []; 1621 | 1622 | angular.forEach(this.$$respHeaders, function(value, key) { 1623 | lines.push(key + ': ' + value); 1624 | }); 1625 | return lines.join('\n'); 1626 | }; 1627 | 1628 | this.abort = angular.noop; 1629 | } 1630 | 1631 | 1632 | /** 1633 | * @ngdoc function 1634 | * @name ngMock.$timeout 1635 | * @description 1636 | * 1637 | * This service is just a simple decorator for {@link ng.$timeout $timeout} service 1638 | * that adds a "flush" and "verifyNoPendingTasks" methods. 1639 | */ 1640 | 1641 | angular.mock.$TimeoutDecorator = function($delegate, $browser) { 1642 | 1643 | /** 1644 | * @ngdoc method 1645 | * @name ngMock.$timeout#flush 1646 | * @methodOf ngMock.$timeout 1647 | * @description 1648 | * 1649 | * Flushes the queue of pending tasks. 1650 | * 1651 | * @param {number=} delay maximum timeout amount to flush up until 1652 | */ 1653 | $delegate.flush = function(delay) { 1654 | $browser.defer.flush(delay); 1655 | }; 1656 | 1657 | /** 1658 | * @ngdoc method 1659 | * @name ngMock.$timeout#verifyNoPendingTasks 1660 | * @methodOf ngMock.$timeout 1661 | * @description 1662 | * 1663 | * Verifies that there are no pending tasks that need to be flushed. 1664 | */ 1665 | $delegate.verifyNoPendingTasks = function() { 1666 | if ($browser.deferredFns.length) { 1667 | throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' + 1668 | formatPendingTasksAsString($browser.deferredFns)); 1669 | } 1670 | }; 1671 | 1672 | function formatPendingTasksAsString(tasks) { 1673 | var result = []; 1674 | angular.forEach(tasks, function(task) { 1675 | result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}'); 1676 | }); 1677 | 1678 | return result.join(', '); 1679 | } 1680 | 1681 | return $delegate; 1682 | }; 1683 | 1684 | /** 1685 | * 1686 | */ 1687 | angular.mock.$RootElementProvider = function() { 1688 | this.$get = function() { 1689 | return angular.element(''); 1690 | }; 1691 | }; 1692 | 1693 | /** 1694 | * @ngdoc overview 1695 | * @name ngMock 1696 | * @description 1697 | * 1698 | * # ngMock 1699 | * 1700 | * The `ngMock` module providers support to inject and mock Angular services into unit tests. 1701 | * In addition, ngMock also extends various core ng services such that they can be 1702 | * inspected and controlled in a synchronous manner within test code. 1703 | * 1704 | * {@installModule mocks} 1705 | * 1706 | * 1707 | * 1708 | */ 1709 | angular.module('ngMock', ['ng']).provider({ 1710 | $browser: angular.mock.$BrowserProvider, 1711 | $exceptionHandler: angular.mock.$ExceptionHandlerProvider, 1712 | $log: angular.mock.$LogProvider, 1713 | $interval: angular.mock.$IntervalProvider, 1714 | $httpBackend: angular.mock.$HttpBackendProvider, 1715 | $rootElement: angular.mock.$RootElementProvider 1716 | }).config(['$provide', function($provide) { 1717 | $provide.decorator('$timeout', angular.mock.$TimeoutDecorator); 1718 | }]); 1719 | 1720 | /** 1721 | * @ngdoc overview 1722 | * @name ngMockE2E 1723 | * @description 1724 | * 1725 | * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing. 1726 | * Currently there is only one mock present in this module - 1727 | * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock. 1728 | */ 1729 | angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { 1730 | $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); 1731 | }]); 1732 | 1733 | /** 1734 | * @ngdoc object 1735 | * @name ngMockE2E.$httpBackend 1736 | * @description 1737 | * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of 1738 | * applications that use the {@link ng.$http $http service}. 1739 | * 1740 | * *Note*: For fake http backend implementation suitable for unit testing please see 1741 | * {@link ngMock.$httpBackend unit-testing $httpBackend mock}. 1742 | * 1743 | * This implementation can be used to respond with static or dynamic responses via the `when` api 1744 | * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the 1745 | * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch 1746 | * templates from a webserver). 1747 | * 1748 | * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application 1749 | * is being developed with the real backend api replaced with a mock, it is often desirable for 1750 | * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch 1751 | * templates or static files from the webserver). To configure the backend with this behavior 1752 | * use the `passThrough` request handler of `when` instead of `respond`. 1753 | * 1754 | * Additionally, we don't want to manually have to flush mocked out requests like we do during unit 1755 | * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests 1756 | * automatically, closely simulating the behavior of the XMLHttpRequest object. 1757 | * 1758 | * To setup the application to run with this http backend, you have to create a module that depends 1759 | * on the `ngMockE2E` and your application modules and defines the fake backend: 1760 | * 1761 | *
1762 | * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']); 1763 | * myAppDev.run(function($httpBackend) { 1764 | * phones = [{name: 'phone1'}, {name: 'phone2'}]; 1765 | * 1766 | * // returns the current list of phones 1767 | * $httpBackend.whenGET('/phones').respond(phones); 1768 | * 1769 | * // adds a new phone to the phones array 1770 | * $httpBackend.whenPOST('/phones').respond(function(method, url, data) { 1771 | * phones.push(angular.fromJson(data)); 1772 | * }); 1773 | * $httpBackend.whenGET(/^\/templates\//).passThrough(); 1774 | * //... 1775 | * }); 1776 | *1777 | * 1778 | * Afterwards, bootstrap your app with this new module. 1779 | */ 1780 | 1781 | /** 1782 | * @ngdoc method 1783 | * @name ngMockE2E.$httpBackend#when 1784 | * @methodOf ngMockE2E.$httpBackend 1785 | * @description 1786 | * Creates a new backend definition. 1787 | * 1788 | * @param {string} method HTTP method. 1789 | * @param {string|RegExp} url HTTP url. 1790 | * @param {(string|RegExp)=} data HTTP request body. 1791 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 1792 | * object and returns true if the headers match the current definition. 1793 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1794 | * control how a matched request is handled. 1795 | * 1796 | * - respond – 1797 | * `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 1798 | * – The respond method takes a set of static data to be returned or a function that can return 1799 | * an array containing response status (number), response data (string) and response headers 1800 | * (Object). 1801 | * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough` 1802 | * handler, will be pass through to the real backend (an XHR request will be made to the 1803 | * server. 1804 | */ 1805 | 1806 | /** 1807 | * @ngdoc method 1808 | * @name ngMockE2E.$httpBackend#whenGET 1809 | * @methodOf ngMockE2E.$httpBackend 1810 | * @description 1811 | * Creates a new backend definition for GET requests. For more info see `when()`. 1812 | * 1813 | * @param {string|RegExp} url HTTP url. 1814 | * @param {(Object|function(Object))=} headers HTTP headers. 1815 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1816 | * control how a matched request is handled. 1817 | */ 1818 | 1819 | /** 1820 | * @ngdoc method 1821 | * @name ngMockE2E.$httpBackend#whenHEAD 1822 | * @methodOf ngMockE2E.$httpBackend 1823 | * @description 1824 | * Creates a new backend definition for HEAD requests. For more info see `when()`. 1825 | * 1826 | * @param {string|RegExp} url HTTP url. 1827 | * @param {(Object|function(Object))=} headers HTTP headers. 1828 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1829 | * control how a matched request is handled. 1830 | */ 1831 | 1832 | /** 1833 | * @ngdoc method 1834 | * @name ngMockE2E.$httpBackend#whenDELETE 1835 | * @methodOf ngMockE2E.$httpBackend 1836 | * @description 1837 | * Creates a new backend definition for DELETE requests. For more info see `when()`. 1838 | * 1839 | * @param {string|RegExp} url HTTP url. 1840 | * @param {(Object|function(Object))=} headers HTTP headers. 1841 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1842 | * control how a matched request is handled. 1843 | */ 1844 | 1845 | /** 1846 | * @ngdoc method 1847 | * @name ngMockE2E.$httpBackend#whenPOST 1848 | * @methodOf ngMockE2E.$httpBackend 1849 | * @description 1850 | * Creates a new backend definition for POST requests. For more info see `when()`. 1851 | * 1852 | * @param {string|RegExp} url HTTP url. 1853 | * @param {(string|RegExp)=} data HTTP request body. 1854 | * @param {(Object|function(Object))=} headers HTTP headers. 1855 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1856 | * control how a matched request is handled. 1857 | */ 1858 | 1859 | /** 1860 | * @ngdoc method 1861 | * @name ngMockE2E.$httpBackend#whenPUT 1862 | * @methodOf ngMockE2E.$httpBackend 1863 | * @description 1864 | * Creates a new backend definition for PUT requests. For more info see `when()`. 1865 | * 1866 | * @param {string|RegExp} url HTTP url. 1867 | * @param {(string|RegExp)=} data HTTP request body. 1868 | * @param {(Object|function(Object))=} headers HTTP headers. 1869 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1870 | * control how a matched request is handled. 1871 | */ 1872 | 1873 | /** 1874 | * @ngdoc method 1875 | * @name ngMockE2E.$httpBackend#whenPATCH 1876 | * @methodOf ngMockE2E.$httpBackend 1877 | * @description 1878 | * Creates a new backend definition for PATCH requests. For more info see `when()`. 1879 | * 1880 | * @param {string|RegExp} url HTTP url. 1881 | * @param {(string|RegExp)=} data HTTP request body. 1882 | * @param {(Object|function(Object))=} headers HTTP headers. 1883 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1884 | * control how a matched request is handled. 1885 | */ 1886 | 1887 | /** 1888 | * @ngdoc method 1889 | * @name ngMockE2E.$httpBackend#whenJSONP 1890 | * @methodOf ngMockE2E.$httpBackend 1891 | * @description 1892 | * Creates a new backend definition for JSONP requests. For more info see `when()`. 1893 | * 1894 | * @param {string|RegExp} url HTTP url. 1895 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1896 | * control how a matched request is handled. 1897 | */ 1898 | angular.mock.e2e = {}; 1899 | angular.mock.e2e.$httpBackendDecorator = 1900 | ['$rootScope', '$delegate', '$browser', createHttpBackendMock]; 1901 | 1902 | 1903 | angular.mock.clearDataCache = function() { 1904 | var key, 1905 | cache = angular.element.cache; 1906 | 1907 | for(key in cache) { 1908 | if (Object.prototype.hasOwnProperty.call(cache,key)) { 1909 | var handle = cache[key].handle; 1910 | 1911 | handle && angular.element(handle.elem).off(); 1912 | delete cache[key]; 1913 | } 1914 | } 1915 | }; 1916 | 1917 | 1918 | 1919 | if(window.jasmine || window.mocha) { 1920 | 1921 | var currentSpec = null, 1922 | isSpecRunning = function() { 1923 | return currentSpec && (window.mocha || currentSpec.queue.running); 1924 | }; 1925 | 1926 | 1927 | beforeEach(function() { 1928 | currentSpec = this; 1929 | }); 1930 | 1931 | afterEach(function() { 1932 | var injector = currentSpec.$injector; 1933 | 1934 | currentSpec.$injector = null; 1935 | currentSpec.$modules = null; 1936 | currentSpec = null; 1937 | 1938 | if (injector) { 1939 | injector.get('$rootElement').off(); 1940 | injector.get('$browser').pollFns.length = 0; 1941 | } 1942 | 1943 | angular.mock.clearDataCache(); 1944 | 1945 | // clean up jquery's fragment cache 1946 | angular.forEach(angular.element.fragments, function(val, key) { 1947 | delete angular.element.fragments[key]; 1948 | }); 1949 | 1950 | MockXhr.$$lastInstance = null; 1951 | 1952 | angular.forEach(angular.callbacks, function(val, key) { 1953 | delete angular.callbacks[key]; 1954 | }); 1955 | angular.callbacks.counter = 0; 1956 | }); 1957 | 1958 | /** 1959 | * @ngdoc function 1960 | * @name angular.mock.module 1961 | * @description 1962 | * 1963 | * *NOTE*: This function is also published on window for easy access.
2047 | * 2048 | * angular.module('myApplicationModule', []) 2049 | * .value('mode', 'app') 2050 | * .value('version', 'v1.0.1'); 2051 | * 2052 | * 2053 | * describe('MyApp', function() { 2054 | * 2055 | * // You need to load modules that you want to test, 2056 | * // it loads only the "ng" module by default. 2057 | * beforeEach(module('myApplicationModule')); 2058 | * 2059 | * 2060 | * // inject() is used to inject arguments of all given functions 2061 | * it('should provide a version', inject(function(mode, version) { 2062 | * expect(version).toEqual('v1.0.1'); 2063 | * expect(mode).toEqual('app'); 2064 | * })); 2065 | * 2066 | * 2067 | * // The inject and module method can also be used inside of the it or beforeEach 2068 | * it('should override a version and test the new version is injected', function() { 2069 | * // module() takes functions or strings (module aliases) 2070 | * module(function($provide) { 2071 | * $provide.value('version', 'overridden'); // override version here 2072 | * }); 2073 | * 2074 | * inject(function(version) { 2075 | * expect(version).toEqual('overridden'); 2076 | * }); 2077 | * }); 2078 | * }); 2079 | * 2080 | *2081 | * 2082 | * @param {...Function} fns any number of functions which will be injected using the injector. 2083 | */ 2084 | window.inject = angular.mock.inject = function() { 2085 | var blockFns = Array.prototype.slice.call(arguments, 0); 2086 | var errorForStack = new Error('Declaration Location'); 2087 | return isSpecRunning() ? workFn() : workFn; 2088 | ///////////////////// 2089 | function workFn() { 2090 | var modules = currentSpec.$modules || []; 2091 | 2092 | modules.unshift('ngMock'); 2093 | modules.unshift('ng'); 2094 | var injector = currentSpec.$injector; 2095 | if (!injector) { 2096 | injector = currentSpec.$injector = angular.injector(modules); 2097 | } 2098 | for(var i = 0, ii = blockFns.length; i < ii; i++) { 2099 | try { 2100 | /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */ 2101 | injector.invoke(blockFns[i] || angular.noop, this); 2102 | /* jshint +W040 */ 2103 | } catch (e) { 2104 | if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack; 2105 | throw e; 2106 | } finally { 2107 | errorForStack = null; 2108 | } 2109 | } 2110 | } 2111 | }; 2112 | } 2113 | 2114 | 2115 | })(window, window.angular); 2116 | -------------------------------------------------------------------------------- /test/lib/angular/version.txt: -------------------------------------------------------------------------------- 1 | 1.2.3 -------------------------------------------------------------------------------- /test/unit/controllersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for controllers go here */ 4 | 5 | describe('controllers', function(){ 6 | beforeEach(module('myApp.controllers')); 7 | 8 | 9 | it('should ....', inject(function() { 10 | //spec body 11 | })); 12 | 13 | it('should ....', inject(function() { 14 | //spec body 15 | })); 16 | }); 17 | -------------------------------------------------------------------------------- /test/unit/directivesSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for directives go here */ 4 | 5 | describe('directives', function() { 6 | beforeEach(module('myApp.directives')); 7 | 8 | describe('app-version', function() { 9 | it('should print current version', function() { 10 | module(function($provide) { 11 | $provide.value('version', 'TEST_VER'); 12 | }); 13 | inject(function($compile, $rootScope) { 14 | var element = $compile('')($rootScope); 15 | expect(element.text()).toEqual('TEST_VER'); 16 | }); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/filtersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for filters go here */ 4 | 5 | describe('filter', function() { 6 | beforeEach(module('myApp.filters')); 7 | 8 | 9 | describe('interpolate', function() { 10 | beforeEach(module(function($provide) { 11 | $provide.value('version', 'TEST_VER'); 12 | })); 13 | 14 | 15 | it('should replace VERSION', inject(function(interpolateFilter) { 16 | expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after'); 17 | })); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/servicesSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for services go here */ 4 | 5 | describe('service', function() { 6 | beforeEach(module('myApp.services')); 7 | 8 | 9 | describe('version', function() { 10 | it('should return current version', inject(function(version) { 11 | expect(version).toEqual('0.1'); 12 | })); 13 | }); 14 | }); 15 | --------------------------------------------------------------------------------