├── .editorconfig ├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── README.md ├── bower.json ├── demo └── demo.html ├── karma.conf.js ├── lib ├── angular-mocks.js ├── angular.min.js └── jquery-1.8.2.min.js ├── package.json ├── src └── ngmodel.format.js └── test └── ngmodel.format.spec.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # Howto with your editor: http://editorconfig.org/#download 4 | # Sublime: https://github.com/sindresorhus/editorconfig-sublime 5 | 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | # Unix-style newlines with a newline ending every file 10 | [**] 11 | end_of_line = lf 12 | insert_final_newline = true 13 | 14 | # Standard at: https://github.com/felixge/node-style-guide 15 | [**.js, **.json] 16 | trim_trailing_whitespace = true 17 | indent_style = space 18 | indent_size = 2 19 | quote_type = single 20 | curly_bracket_next_line = false 21 | spaces_around_operators = true 22 | space_after_control_statements = true 23 | space_after_anonymous_functions = true 24 | spaces_in_brackets = false 25 | 26 | # No Standard. Please document a standard if different from .js 27 | [**.yml, **.html, **.css] 28 | trim_trailing_whitespace = true 29 | indent_style = tab 30 | 31 | # No standard. Please document a standard if different from .js 32 | [**.md] 33 | indent_style = tab 34 | 35 | # Standard at: 36 | [Makefile] 37 | indent_style = tab 38 | 39 | # The indentation in package.json will always need to be 2 spaces 40 | # https://github.com/npm/npm/issues/4718 41 | [package.json, bower.json] 42 | indent_style = space 43 | indent_size = 2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | before_script: 5 | - 'npm install -g grunt-cli' 6 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | grunt.loadNpmTasks('grunt-karma'); 5 | 6 | grunt.initConfig({ 7 | karma: { 8 | unit: { 9 | configFile: 'karma.conf.js', 10 | singleRun: true, 11 | browsers: ["PhantomJS"] 12 | } 13 | } 14 | }); 15 | 16 | grunt.registerTask('test', [ 17 | 'karma' 18 | ]); 19 | 20 | grunt.registerTask('default', [ 21 | 'test' 22 | ]); 23 | }; 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ngmodel.format 3 | ================== 4 | 5 | [](https://travis-ci.org/greengerong/ngmodel-format) 6 | 7 | 8 | * angular format for input/select ... ng-model stuff, the model value will be not same as view value. 9 | 10 | * there are some default format: currency, digit,int,float. 11 | 12 | * You can easy to change it, just inject modelFormatConfig constant into you module config for all of you application. and you also can just set default formatter on element attribute to change this format. 13 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngmodel-format", 3 | "version": "0.0.1", 4 | "authors": [ 5 | ], 6 | "description": "angualr format for input/select", 7 | "main": "./src/ngmodel.format.js", 8 | "keywords": [ 9 | "angular", 10 | "angularjs", 11 | "currency", 12 | "field", 13 | "format" 14 | ], 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "test", 20 | "tests", 21 | "lib", 22 | "demo", 23 | "karma.conf.js" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /demo/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |208 | * describe('$exceptionHandlerProvider', function() { 209 | * 210 | * it('should capture log messages and exceptions', function() { 211 | * 212 | * module(function($exceptionHandlerProvider) { 213 | * $exceptionHandlerProvider.mode('log'); 214 | * }); 215 | * 216 | * inject(function($log, $exceptionHandler, $timeout) { 217 | * $timeout(function() { $log.log(1); }); 218 | * $timeout(function() { $log.log(2); throw 'banana peel'; }); 219 | * $timeout(function() { $log.log(3); }); 220 | * expect($exceptionHandler.errors).toEqual([]); 221 | * expect($log.assertEmpty()); 222 | * $timeout.flush(); 223 | * expect($exceptionHandler.errors).toEqual(['banana peel']); 224 | * expect($log.log.logs).toEqual([[1], [2], [3]]); 225 | * }); 226 | * }); 227 | * }); 228 | *229 | */ 230 | 231 | angular.mock.$ExceptionHandlerProvider = function() { 232 | var handler; 233 | 234 | /** 235 | * @ngdoc method 236 | * @name ngMock.$exceptionHandlerProvider#mode 237 | * @methodOf ngMock.$exceptionHandlerProvider 238 | * 239 | * @description 240 | * Sets the logging mode. 241 | * 242 | * @param {string} mode Mode of operation, defaults to `rethrow`. 243 | * 244 | * - `rethrow`: If any errors are passed into the handler in tests, it typically 245 | * means that there is a bug in the application or test, so this mock will 246 | * make these tests fail. 247 | * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log` mode stores an 248 | * array of errors in `$exceptionHandler.errors`, to allow later assertion of them. 249 | * See {@link ngMock.$log#assertEmpty assertEmpty()} and 250 | * {@link ngMock.$log#reset reset()} 251 | */ 252 | this.mode = function(mode) { 253 | switch(mode) { 254 | case 'rethrow': 255 | handler = function(e) { 256 | throw e; 257 | }; 258 | break; 259 | case 'log': 260 | var errors = []; 261 | 262 | handler = function(e) { 263 | if (arguments.length == 1) { 264 | errors.push(e); 265 | } else { 266 | errors.push([].slice.call(arguments, 0)); 267 | } 268 | }; 269 | 270 | handler.errors = errors; 271 | break; 272 | default: 273 | throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!"); 274 | } 275 | }; 276 | 277 | this.$get = function() { 278 | return handler; 279 | }; 280 | 281 | this.mode('rethrow'); 282 | }; 283 | 284 | 285 | /** 286 | * @ngdoc service 287 | * @name ngMock.$log 288 | * 289 | * @description 290 | * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays 291 | * (one array per logging level). These arrays are exposed as `logs` property of each of the 292 | * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`. 293 | * 294 | */ 295 | angular.mock.$LogProvider = function() { 296 | 297 | function concat(array1, array2, index) { 298 | return array1.concat(Array.prototype.slice.call(array2, index)); 299 | } 300 | 301 | 302 | this.$get = function () { 303 | var $log = { 304 | log: function() { $log.log.logs.push(concat([], arguments, 0)); }, 305 | warn: function() { $log.warn.logs.push(concat([], arguments, 0)); }, 306 | info: function() { $log.info.logs.push(concat([], arguments, 0)); }, 307 | error: function() { $log.error.logs.push(concat([], arguments, 0)); } 308 | }; 309 | 310 | /** 311 | * @ngdoc method 312 | * @name ngMock.$log#reset 313 | * @methodOf ngMock.$log 314 | * 315 | * @description 316 | * Reset all of the logging arrays to empty. 317 | */ 318 | $log.reset = function () { 319 | /** 320 | * @ngdoc property 321 | * @name ngMock.$log#log.logs 322 | * @propertyOf ngMock.$log 323 | * 324 | * @description 325 | * Array of messages logged using {@link ngMock.$log#log}. 326 | * 327 | * @example 328 | *
329 | * $log.log('Some Log'); 330 | * var first = $log.log.logs.unshift(); 331 | *332 | */ 333 | $log.log.logs = []; 334 | /** 335 | * @ngdoc property 336 | * @name ngMock.$log#warn.logs 337 | * @propertyOf ngMock.$log 338 | * 339 | * @description 340 | * Array of messages logged using {@link ngMock.$log#warn}. 341 | * 342 | * @example 343 | *
344 | * $log.warn('Some Warning'); 345 | * var first = $log.warn.logs.unshift(); 346 | *347 | */ 348 | $log.warn.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#error.logs 367 | * @propertyOf ngMock.$log 368 | * 369 | * @description 370 | * Array of messages logged using {@link ngMock.$log#error}. 371 | * 372 | * @example 373 | *
374 | * $log.log('Some Error'); 375 | * var first = $log.error.logs.unshift(); 376 | *377 | */ 378 | $log.error.logs = []; 379 | }; 380 | 381 | /** 382 | * @ngdoc method 383 | * @name ngMock.$log#assertEmpty 384 | * @methodOf ngMock.$log 385 | * 386 | * @description 387 | * Assert that the all of the logging methods have no logged messages. If messages present, an exception is thrown. 388 | */ 389 | $log.assertEmpty = function() { 390 | var errors = []; 391 | angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) { 392 | angular.forEach($log[logLevel].logs, function(log) { 393 | angular.forEach(log, function (logItem) { 394 | errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' + (logItem.stack || '')); 395 | }); 396 | }); 397 | }); 398 | if (errors.length) { 399 | errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " + 400 | "log message was not checked and removed:"); 401 | errors.push(''); 402 | throw new Error(errors.join('\n---------\n')); 403 | } 404 | }; 405 | 406 | $log.reset(); 407 | return $log; 408 | }; 409 | }; 410 | 411 | 412 | (function() { 413 | var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/; 414 | 415 | function jsonStringToDate(string) { 416 | var match; 417 | if (match = string.match(R_ISO8061_STR)) { 418 | var date = new Date(0), 419 | tzHour = 0, 420 | tzMin = 0; 421 | if (match[9]) { 422 | tzHour = int(match[9] + match[10]); 423 | tzMin = int(match[9] + match[11]); 424 | } 425 | date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3])); 426 | date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0)); 427 | return date; 428 | } 429 | return string; 430 | } 431 | 432 | function int(str) { 433 | return parseInt(str, 10); 434 | } 435 | 436 | function padNumber(num, digits, trim) { 437 | var neg = ''; 438 | if (num < 0) { 439 | neg = '-'; 440 | num = -num; 441 | } 442 | num = '' + num; 443 | while(num.length < digits) num = '0' + num; 444 | if (trim) 445 | num = num.substr(num.length - digits); 446 | return neg + num; 447 | } 448 | 449 | 450 | /** 451 | * @ngdoc object 452 | * @name angular.mock.TzDate 453 | * @description 454 | * 455 | * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. 456 | * 457 | * Mock of the Date type which has its timezone specified via constructor arg. 458 | * 459 | * The main purpose is to create Date-like instances with timezone fixed to the specified timezone 460 | * offset, so that we can test code that depends on local timezone settings without dependency on 461 | * the time zone settings of the machine where the code is running. 462 | * 463 | * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored) 464 | * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC* 465 | * 466 | * @example 467 | * !!!! WARNING !!!!! 468 | * This is not a complete Date object so only methods that were implemented can be called safely. 469 | * To make matters worse, TzDate instances inherit stuff from Date via a prototype. 470 | * 471 | * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is 472 | * incomplete we might be missing some non-standard methods. This can result in errors like: 473 | * "Date.prototype.foo called on incompatible Object". 474 | * 475 | *
476 | * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z'); 477 | * newYearInBratislava.getTimezoneOffset() => -60; 478 | * newYearInBratislava.getFullYear() => 2010; 479 | * newYearInBratislava.getMonth() => 0; 480 | * newYearInBratislava.getDate() => 1; 481 | * newYearInBratislava.getHours() => 0; 482 | * newYearInBratislava.getMinutes() => 0; 483 | *484 | * 485 | */ 486 | angular.mock.TzDate = function (offset, timestamp) { 487 | var self = new Date(0); 488 | if (angular.isString(timestamp)) { 489 | var tsStr = timestamp; 490 | 491 | self.origDate = jsonStringToDate(timestamp); 492 | 493 | timestamp = self.origDate.getTime(); 494 | if (isNaN(timestamp)) 495 | throw { 496 | name: "Illegal Argument", 497 | message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string" 498 | }; 499 | } else { 500 | self.origDate = new Date(timestamp); 501 | } 502 | 503 | var localOffset = new Date(timestamp).getTimezoneOffset(); 504 | self.offsetDiff = localOffset*60*1000 - offset*1000*60*60; 505 | self.date = new Date(timestamp + self.offsetDiff); 506 | 507 | self.getTime = function() { 508 | return self.date.getTime() - self.offsetDiff; 509 | }; 510 | 511 | self.toLocaleDateString = function() { 512 | return self.date.toLocaleDateString(); 513 | }; 514 | 515 | self.getFullYear = function() { 516 | return self.date.getFullYear(); 517 | }; 518 | 519 | self.getMonth = function() { 520 | return self.date.getMonth(); 521 | }; 522 | 523 | self.getDate = function() { 524 | return self.date.getDate(); 525 | }; 526 | 527 | self.getHours = function() { 528 | return self.date.getHours(); 529 | }; 530 | 531 | self.getMinutes = function() { 532 | return self.date.getMinutes(); 533 | }; 534 | 535 | self.getSeconds = function() { 536 | return self.date.getSeconds(); 537 | }; 538 | 539 | self.getTimezoneOffset = function() { 540 | return offset * 60; 541 | }; 542 | 543 | self.getUTCFullYear = function() { 544 | return self.origDate.getUTCFullYear(); 545 | }; 546 | 547 | self.getUTCMonth = function() { 548 | return self.origDate.getUTCMonth(); 549 | }; 550 | 551 | self.getUTCDate = function() { 552 | return self.origDate.getUTCDate(); 553 | }; 554 | 555 | self.getUTCHours = function() { 556 | return self.origDate.getUTCHours(); 557 | }; 558 | 559 | self.getUTCMinutes = function() { 560 | return self.origDate.getUTCMinutes(); 561 | }; 562 | 563 | self.getUTCSeconds = function() { 564 | return self.origDate.getUTCSeconds(); 565 | }; 566 | 567 | self.getUTCMilliseconds = function() { 568 | return self.origDate.getUTCMilliseconds(); 569 | }; 570 | 571 | self.getDay = function() { 572 | return self.date.getDay(); 573 | }; 574 | 575 | // provide this method only on browsers that already have it 576 | if (self.toISOString) { 577 | self.toISOString = function() { 578 | return padNumber(self.origDate.getUTCFullYear(), 4) + '-' + 579 | padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' + 580 | padNumber(self.origDate.getUTCDate(), 2) + 'T' + 581 | padNumber(self.origDate.getUTCHours(), 2) + ':' + 582 | padNumber(self.origDate.getUTCMinutes(), 2) + ':' + 583 | padNumber(self.origDate.getUTCSeconds(), 2) + '.' + 584 | padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z' 585 | } 586 | } 587 | 588 | //hide all methods not implemented in this mock that the Date prototype exposes 589 | var unimplementedMethods = ['getMilliseconds', 'getUTCDay', 590 | 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 591 | 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 592 | 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 593 | 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString', 594 | 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf']; 595 | 596 | angular.forEach(unimplementedMethods, function(methodName) { 597 | self[methodName] = function() { 598 | throw Error("Method '" + methodName + "' is not implemented in the TzDate mock"); 599 | }; 600 | }); 601 | 602 | return self; 603 | }; 604 | 605 | //make "tzDateInstance instanceof Date" return true 606 | angular.mock.TzDate.prototype = Date.prototype; 607 | })(); 608 | 609 | 610 | /** 611 | * @ngdoc function 612 | * @name angular.mock.dump 613 | * @description 614 | * 615 | * *NOTE*: this is not an injectable instance, just a globally available function. 616 | * 617 | * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for debugging. 618 | * 619 | * This method is also available on window, where it can be used to display objects on debug console. 620 | * 621 | * @param {*} object - any object to turn into string. 622 | * @return {string} a serialized string of the argument 623 | */ 624 | angular.mock.dump = function(object) { 625 | return serialize(object); 626 | 627 | function serialize(object) { 628 | var out; 629 | 630 | if (angular.isElement(object)) { 631 | object = angular.element(object); 632 | out = angular.element(''); 633 | angular.forEach(object, function(element) { 634 | out.append(angular.element(element).clone()); 635 | }); 636 | out = out.html(); 637 | } else if (angular.isArray(object)) { 638 | out = []; 639 | angular.forEach(object, function(o) { 640 | out.push(serialize(o)); 641 | }); 642 | out = '[ ' + out.join(', ') + ' ]'; 643 | } else if (angular.isObject(object)) { 644 | if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) { 645 | out = serializeScope(object); 646 | } else if (object instanceof Error) { 647 | out = object.stack || ('' + object.name + ': ' + object.message); 648 | } else { 649 | out = angular.toJson(object, true); 650 | } 651 | } else { 652 | out = String(object); 653 | } 654 | 655 | return out; 656 | } 657 | 658 | function serializeScope(scope, offset) { 659 | offset = offset || ' '; 660 | var log = [offset + 'Scope(' + scope.$id + '): {']; 661 | for ( var key in scope ) { 662 | if (scope.hasOwnProperty(key) && !key.match(/^(\$|this)/)) { 663 | log.push(' ' + key + ': ' + angular.toJson(scope[key])); 664 | } 665 | } 666 | var child = scope.$$childHead; 667 | while(child) { 668 | log.push(serializeScope(child, offset + ' ')); 669 | child = child.$$nextSibling; 670 | } 671 | log.push('}'); 672 | return log.join('\n' + offset); 673 | } 674 | }; 675 | 676 | /** 677 | * @ngdoc object 678 | * @name ngMock.$httpBackend 679 | * @description 680 | * Fake HTTP backend implementation suitable for unit testing applications that use the 681 | * {@link ng.$http $http service}. 682 | * 683 | * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less 684 | * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}. 685 | * 686 | * During unit testing, we want our unit tests to run quickly and have no external dependencies so 687 | * we don’t want to send {@link https://developer.mozilla.org/en/xmlhttprequest XHR} or 688 | * {@link http://en.wikipedia.org/wiki/JSONP JSONP} requests to a real server. All we really need is 689 | * to verify whether a certain request has been sent or not, or alternatively just let the 690 | * application make requests, respond with pre-trained responses and assert that the end result is 691 | * what we expect it to be. 692 | * 693 | * This mock implementation can be used to respond with static or dynamic responses via the 694 | * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc). 695 | * 696 | * When an Angular application needs some data from a server, it calls the $http service, which 697 | * sends the request to a real server using $httpBackend service. With dependency injection, it is 698 | * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify 699 | * the requests and respond with some testing data without sending a request to real server. 700 | * 701 | * There are two ways to specify what test data should be returned as http responses by the mock 702 | * backend when the code under test makes http requests: 703 | * 704 | * - `$httpBackend.expect` - specifies a request expectation 705 | * - `$httpBackend.when` - specifies a backend definition 706 | * 707 | * 708 | * # Request Expectations vs Backend Definitions 709 | * 710 | * Request expectations provide a way to make assertions about requests made by the application and 711 | * to define responses for those requests. The test will fail if the expected requests are not made 712 | * or they are made in the wrong order. 713 | * 714 | * Backend definitions allow you to define a fake backend for your application which doesn't assert 715 | * if a particular request was made or not, it just returns a trained response if a request is made. 716 | * The test will pass whether or not the request gets made during testing. 717 | * 718 | * 719 | *
Request expectations | Backend definitions | |
---|---|---|
Syntax | 723 | *.expect(...).respond(...) | 724 | *.when(...).respond(...) | 725 | *
Typical usage | 728 | *strict unit tests | 729 | *loose (black-box) unit testing | 730 | *
Fulfills multiple requests | 733 | *NO | 734 | *YES | 735 | *
Order of requests matters | 738 | *YES | 739 | *NO | 740 | *
Request required | 743 | *YES | 744 | *NO | 745 | *
Response required | 748 | *optional (see below) | 749 | *YES | 750 | *
780 | // The controller code 781 | function MyController($scope, $http) { 782 | var authToken; 783 | 784 | $http.get('/auth.py').success(function(data, status, headers) { 785 | authToken = headers('A-Token'); 786 | $scope.user = data; 787 | }); 788 | 789 | $scope.saveMessage = function(message) { 790 | var headers = { 'Authorization': authToken }; 791 | $scope.status = 'Saving...'; 792 | 793 | $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) { 794 | $scope.status = ''; 795 | }).error(function() { 796 | $scope.status = 'ERROR!'; 797 | }); 798 | }; 799 | } 800 |801 | * 802 | * Now we setup the mock backend and create the test specs. 803 | * 804 |
805 | // testing controller 806 | describe('MyController', function() { 807 | var $httpBackend, $rootScope, createController; 808 | 809 | beforeEach(inject(function($injector) { 810 | // Set up the mock http service responses 811 | $httpBackend = $injector.get('$httpBackend'); 812 | // backend definition common for all tests 813 | $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'}); 814 | 815 | // Get hold of a scope (i.e. the root scope) 816 | $rootScope = $injector.get('$rootScope'); 817 | // The $controller service is used to create instances of controllers 818 | var $controller = $injector.get('$controller'); 819 | 820 | createController = function() { 821 | return $controller('MyController', {'$scope' : $rootScope }); 822 | }; 823 | })); 824 | 825 | 826 | afterEach(function() { 827 | $httpBackend.verifyNoOutstandingExpectation(); 828 | $httpBackend.verifyNoOutstandingRequest(); 829 | }); 830 | 831 | 832 | it('should fetch authentication token', function() { 833 | $httpBackend.expectGET('/auth.py'); 834 | var controller = createController(); 835 | $httpBackend.flush(); 836 | }); 837 | 838 | 839 | it('should send msg to server', function() { 840 | var controller = createController(); 841 | $httpBackend.flush(); 842 | 843 | // now you don’t care about the authentication, but 844 | // the controller will still send the request and 845 | // $httpBackend will respond without you having to 846 | // specify the expectation and response for this request 847 | 848 | $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, ''); 849 | $rootScope.saveMessage('message content'); 850 | expect($rootScope.status).toBe('Saving...'); 851 | $httpBackend.flush(); 852 | expect($rootScope.status).toBe(''); 853 | }); 854 | 855 | 856 | it('should send auth header', function() { 857 | var controller = createController(); 858 | $httpBackend.flush(); 859 | 860 | $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) { 861 | // check if the header was send, if it wasn't the expectation won't 862 | // match the request and the test will fail 863 | return headers['Authorization'] == 'xxx'; 864 | }).respond(201, ''); 865 | 866 | $rootScope.saveMessage('whatever'); 867 | $httpBackend.flush(); 868 | }); 869 | }); 870 |871 | */ 872 | angular.mock.$HttpBackendProvider = function() { 873 | this.$get = [createHttpBackendMock]; 874 | }; 875 | 876 | /** 877 | * General factory function for $httpBackend mock. 878 | * Returns instance for unit testing (when no arguments specified): 879 | * - passing through is disabled 880 | * - auto flushing is disabled 881 | * 882 | * Returns instance for e2e testing (when `$delegate` and `$browser` specified): 883 | * - passing through (delegating request to real backend) is enabled 884 | * - auto flushing is enabled 885 | * 886 | * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified) 887 | * @param {Object=} $browser Auto-flushing enabled if specified 888 | * @return {Object} Instance of $httpBackend mock 889 | */ 890 | function createHttpBackendMock($delegate, $browser) { 891 | var definitions = [], 892 | expectations = [], 893 | responses = [], 894 | responsesPush = angular.bind(responses, responses.push); 895 | 896 | function createResponse(status, data, headers) { 897 | if (angular.isFunction(status)) return status; 898 | 899 | return function() { 900 | return angular.isNumber(status) 901 | ? [status, data, headers] 902 | : [200, status, data]; 903 | }; 904 | } 905 | 906 | // TODO(vojta): change params to: method, url, data, headers, callback 907 | function $httpBackend(method, url, data, callback, headers) { 908 | var xhr = new MockXhr(), 909 | expectation = expectations[0], 910 | wasExpected = false; 911 | 912 | function prettyPrint(data) { 913 | return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp) 914 | ? data 915 | : angular.toJson(data); 916 | } 917 | 918 | if (expectation && expectation.match(method, url)) { 919 | if (!expectation.matchData(data)) 920 | throw Error('Expected ' + expectation + ' with different data\n' + 921 | 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data); 922 | 923 | if (!expectation.matchHeaders(headers)) 924 | throw Error('Expected ' + expectation + ' with different headers\n' + 925 | 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' + 926 | prettyPrint(headers)); 927 | 928 | expectations.shift(); 929 | 930 | if (expectation.response) { 931 | responses.push(function() { 932 | var response = expectation.response(method, url, data, headers); 933 | xhr.$$respHeaders = response[2]; 934 | callback(response[0], response[1], xhr.getAllResponseHeaders()); 935 | }); 936 | return; 937 | } 938 | wasExpected = true; 939 | } 940 | 941 | var i = -1, definition; 942 | while ((definition = definitions[++i])) { 943 | if (definition.match(method, url, data, headers || {})) { 944 | if (definition.response) { 945 | // if $browser specified, we do auto flush all requests 946 | ($browser ? $browser.defer : responsesPush)(function() { 947 | var response = definition.response(method, url, data, headers); 948 | xhr.$$respHeaders = response[2]; 949 | callback(response[0], response[1], xhr.getAllResponseHeaders()); 950 | }); 951 | } else if (definition.passThrough) { 952 | $delegate(method, url, data, callback, headers); 953 | } else throw Error('No response defined !'); 954 | return; 955 | } 956 | } 957 | throw wasExpected ? 958 | Error('No response defined !') : 959 | Error('Unexpected request: ' + method + ' ' + url + '\n' + 960 | (expectation ? 'Expected ' + expectation : 'No more request expected')); 961 | } 962 | 963 | /** 964 | * @ngdoc method 965 | * @name ngMock.$httpBackend#when 966 | * @methodOf ngMock.$httpBackend 967 | * @description 968 | * Creates a new backend definition. 969 | * 970 | * @param {string} method HTTP method. 971 | * @param {string|RegExp} url HTTP url. 972 | * @param {(string|RegExp)=} data HTTP request body. 973 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 974 | * object and returns true if the headers match the current definition. 975 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 976 | * request is handled. 977 | * 978 | * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 979 | * – The respond method takes a set of static data to be returned or a function that can return 980 | * an array containing response status (number), response data (string) and response headers 981 | * (Object). 982 | */ 983 | $httpBackend.when = function(method, url, data, headers) { 984 | var definition = new MockHttpExpectation(method, url, data, headers), 985 | chain = { 986 | respond: function(status, data, headers) { 987 | definition.response = createResponse(status, data, headers); 988 | } 989 | }; 990 | 991 | if ($browser) { 992 | chain.passThrough = function() { 993 | definition.passThrough = true; 994 | }; 995 | } 996 | 997 | definitions.push(definition); 998 | return chain; 999 | }; 1000 | 1001 | /** 1002 | * @ngdoc method 1003 | * @name ngMock.$httpBackend#whenGET 1004 | * @methodOf ngMock.$httpBackend 1005 | * @description 1006 | * Creates a new backend definition for GET requests. For more info see `when()`. 1007 | * 1008 | * @param {string|RegExp} url HTTP url. 1009 | * @param {(Object|function(Object))=} headers HTTP headers. 1010 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1011 | * request is handled. 1012 | */ 1013 | 1014 | /** 1015 | * @ngdoc method 1016 | * @name ngMock.$httpBackend#whenHEAD 1017 | * @methodOf ngMock.$httpBackend 1018 | * @description 1019 | * Creates a new backend definition for HEAD requests. For more info see `when()`. 1020 | * 1021 | * @param {string|RegExp} url HTTP url. 1022 | * @param {(Object|function(Object))=} headers HTTP headers. 1023 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1024 | * request is handled. 1025 | */ 1026 | 1027 | /** 1028 | * @ngdoc method 1029 | * @name ngMock.$httpBackend#whenDELETE 1030 | * @methodOf ngMock.$httpBackend 1031 | * @description 1032 | * Creates a new backend definition for DELETE requests. For more info see `when()`. 1033 | * 1034 | * @param {string|RegExp} url HTTP url. 1035 | * @param {(Object|function(Object))=} headers HTTP headers. 1036 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1037 | * request is handled. 1038 | */ 1039 | 1040 | /** 1041 | * @ngdoc method 1042 | * @name ngMock.$httpBackend#whenPOST 1043 | * @methodOf ngMock.$httpBackend 1044 | * @description 1045 | * Creates a new backend definition for POST requests. For more info see `when()`. 1046 | * 1047 | * @param {string|RegExp} url HTTP url. 1048 | * @param {(string|RegExp)=} data HTTP request body. 1049 | * @param {(Object|function(Object))=} headers HTTP headers. 1050 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1051 | * request is handled. 1052 | */ 1053 | 1054 | /** 1055 | * @ngdoc method 1056 | * @name ngMock.$httpBackend#whenPUT 1057 | * @methodOf ngMock.$httpBackend 1058 | * @description 1059 | * Creates a new backend definition for PUT requests. For more info see `when()`. 1060 | * 1061 | * @param {string|RegExp} url HTTP url. 1062 | * @param {(string|RegExp)=} data HTTP request body. 1063 | * @param {(Object|function(Object))=} headers HTTP headers. 1064 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1065 | * request is handled. 1066 | */ 1067 | 1068 | /** 1069 | * @ngdoc method 1070 | * @name ngMock.$httpBackend#whenJSONP 1071 | * @methodOf ngMock.$httpBackend 1072 | * @description 1073 | * Creates a new backend definition for JSONP requests. For more info see `when()`. 1074 | * 1075 | * @param {string|RegExp} url HTTP url. 1076 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1077 | * request is handled. 1078 | */ 1079 | createShortMethods('when'); 1080 | 1081 | 1082 | /** 1083 | * @ngdoc method 1084 | * @name ngMock.$httpBackend#expect 1085 | * @methodOf ngMock.$httpBackend 1086 | * @description 1087 | * Creates a new request expectation. 1088 | * 1089 | * @param {string} method HTTP method. 1090 | * @param {string|RegExp} url HTTP url. 1091 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1092 | * receives data string and returns true if the data is as expected, or Object if request body 1093 | * is in JSON format. 1094 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 1095 | * object and returns true if the headers match the current expectation. 1096 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1097 | * request is handled. 1098 | * 1099 | * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 1100 | * – The respond method takes a set of static data to be returned or a function that can return 1101 | * an array containing response status (number), response data (string) and response headers 1102 | * (Object). 1103 | */ 1104 | $httpBackend.expect = function(method, url, data, headers) { 1105 | var expectation = new MockHttpExpectation(method, url, data, headers); 1106 | expectations.push(expectation); 1107 | return { 1108 | respond: function(status, data, headers) { 1109 | expectation.response = createResponse(status, data, headers); 1110 | } 1111 | }; 1112 | }; 1113 | 1114 | 1115 | /** 1116 | * @ngdoc method 1117 | * @name ngMock.$httpBackend#expectGET 1118 | * @methodOf ngMock.$httpBackend 1119 | * @description 1120 | * Creates a new request expectation for GET requests. For more info see `expect()`. 1121 | * 1122 | * @param {string|RegExp} url HTTP url. 1123 | * @param {Object=} headers HTTP headers. 1124 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1125 | * request is handled. See #expect for more info. 1126 | */ 1127 | 1128 | /** 1129 | * @ngdoc method 1130 | * @name ngMock.$httpBackend#expectHEAD 1131 | * @methodOf ngMock.$httpBackend 1132 | * @description 1133 | * Creates a new request expectation for HEAD requests. For more info see `expect()`. 1134 | * 1135 | * @param {string|RegExp} url HTTP url. 1136 | * @param {Object=} headers HTTP headers. 1137 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1138 | * request is handled. 1139 | */ 1140 | 1141 | /** 1142 | * @ngdoc method 1143 | * @name ngMock.$httpBackend#expectDELETE 1144 | * @methodOf ngMock.$httpBackend 1145 | * @description 1146 | * Creates a new request expectation for DELETE requests. For more info see `expect()`. 1147 | * 1148 | * @param {string|RegExp} url HTTP url. 1149 | * @param {Object=} headers HTTP headers. 1150 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1151 | * request is handled. 1152 | */ 1153 | 1154 | /** 1155 | * @ngdoc method 1156 | * @name ngMock.$httpBackend#expectPOST 1157 | * @methodOf ngMock.$httpBackend 1158 | * @description 1159 | * Creates a new request expectation for POST requests. For more info see `expect()`. 1160 | * 1161 | * @param {string|RegExp} url HTTP url. 1162 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1163 | * receives data string and returns true if the data is as expected, or Object if request body 1164 | * is in JSON format. 1165 | * @param {Object=} headers HTTP headers. 1166 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1167 | * request is handled. 1168 | */ 1169 | 1170 | /** 1171 | * @ngdoc method 1172 | * @name ngMock.$httpBackend#expectPUT 1173 | * @methodOf ngMock.$httpBackend 1174 | * @description 1175 | * Creates a new request expectation for PUT requests. For more info see `expect()`. 1176 | * 1177 | * @param {string|RegExp} url HTTP url. 1178 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1179 | * receives data string and returns true if the data is as expected, or Object if request body 1180 | * is in JSON format. 1181 | * @param {Object=} headers HTTP headers. 1182 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1183 | * request is handled. 1184 | */ 1185 | 1186 | /** 1187 | * @ngdoc method 1188 | * @name ngMock.$httpBackend#expectPATCH 1189 | * @methodOf ngMock.$httpBackend 1190 | * @description 1191 | * Creates a new request expectation for PATCH requests. For more info see `expect()`. 1192 | * 1193 | * @param {string|RegExp} url HTTP url. 1194 | * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that 1195 | * receives data string and returns true if the data is as expected, or Object if request body 1196 | * is in JSON format. 1197 | * @param {Object=} headers HTTP headers. 1198 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1199 | * request is handled. 1200 | */ 1201 | 1202 | /** 1203 | * @ngdoc method 1204 | * @name ngMock.$httpBackend#expectJSONP 1205 | * @methodOf ngMock.$httpBackend 1206 | * @description 1207 | * Creates a new request expectation for JSONP requests. For more info see `expect()`. 1208 | * 1209 | * @param {string|RegExp} url HTTP url. 1210 | * @returns {requestHandler} Returns an object with `respond` method that control how a matched 1211 | * request is handled. 1212 | */ 1213 | createShortMethods('expect'); 1214 | 1215 | 1216 | /** 1217 | * @ngdoc method 1218 | * @name ngMock.$httpBackend#flush 1219 | * @methodOf ngMock.$httpBackend 1220 | * @description 1221 | * Flushes all pending requests using the trained responses. 1222 | * 1223 | * @param {number=} count Number of responses to flush (in the order they arrived). If undefined, 1224 | * all pending requests will be flushed. If there are no pending requests when the flush method 1225 | * is called an exception is thrown (as this typically a sign of programming error). 1226 | */ 1227 | $httpBackend.flush = function(count) { 1228 | if (!responses.length) throw Error('No pending request to flush !'); 1229 | 1230 | if (angular.isDefined(count)) { 1231 | while (count--) { 1232 | if (!responses.length) throw Error('No more pending request to flush !'); 1233 | responses.shift()(); 1234 | } 1235 | } else { 1236 | while (responses.length) { 1237 | responses.shift()(); 1238 | } 1239 | } 1240 | $httpBackend.verifyNoOutstandingExpectation(); 1241 | }; 1242 | 1243 | 1244 | /** 1245 | * @ngdoc method 1246 | * @name ngMock.$httpBackend#verifyNoOutstandingExpectation 1247 | * @methodOf ngMock.$httpBackend 1248 | * @description 1249 | * Verifies that all of the requests defined via the `expect` api were made. If any of the 1250 | * requests were not made, verifyNoOutstandingExpectation throws an exception. 1251 | * 1252 | * Typically, you would call this method following each test case that asserts requests using an 1253 | * "afterEach" clause. 1254 | * 1255 | *
1256 | * afterEach($httpBackend.verifyNoOutstandingExpectation); 1257 | *1258 | */ 1259 | $httpBackend.verifyNoOutstandingExpectation = function() { 1260 | if (expectations.length) { 1261 | throw Error('Unsatisfied requests: ' + expectations.join(', ')); 1262 | } 1263 | }; 1264 | 1265 | 1266 | /** 1267 | * @ngdoc method 1268 | * @name ngMock.$httpBackend#verifyNoOutstandingRequest 1269 | * @methodOf ngMock.$httpBackend 1270 | * @description 1271 | * Verifies that there are no outstanding requests that need to be flushed. 1272 | * 1273 | * Typically, you would call this method following each test case that asserts requests using an 1274 | * "afterEach" clause. 1275 | * 1276 | *
1277 | * afterEach($httpBackend.verifyNoOutstandingRequest); 1278 | *1279 | */ 1280 | $httpBackend.verifyNoOutstandingRequest = function() { 1281 | if (responses.length) { 1282 | throw Error('Unflushed requests: ' + responses.length); 1283 | } 1284 | }; 1285 | 1286 | 1287 | /** 1288 | * @ngdoc method 1289 | * @name ngMock.$httpBackend#resetExpectations 1290 | * @methodOf ngMock.$httpBackend 1291 | * @description 1292 | * Resets all request expectations, but preserves all backend definitions. Typically, you would 1293 | * call resetExpectations during a multiple-phase test when you want to reuse the same instance of 1294 | * $httpBackend mock. 1295 | */ 1296 | $httpBackend.resetExpectations = function() { 1297 | expectations.length = 0; 1298 | responses.length = 0; 1299 | }; 1300 | 1301 | return $httpBackend; 1302 | 1303 | 1304 | function createShortMethods(prefix) { 1305 | angular.forEach(['GET', 'DELETE', 'JSONP'], function(method) { 1306 | $httpBackend[prefix + method] = function(url, headers) { 1307 | return $httpBackend[prefix](method, url, undefined, headers) 1308 | } 1309 | }); 1310 | 1311 | angular.forEach(['PUT', 'POST', 'PATCH'], function(method) { 1312 | $httpBackend[prefix + method] = function(url, data, headers) { 1313 | return $httpBackend[prefix](method, url, data, headers) 1314 | } 1315 | }); 1316 | } 1317 | } 1318 | 1319 | function MockHttpExpectation(method, url, data, headers) { 1320 | 1321 | this.data = data; 1322 | this.headers = headers; 1323 | 1324 | this.match = function(m, u, d, h) { 1325 | if (method != m) return false; 1326 | if (!this.matchUrl(u)) return false; 1327 | if (angular.isDefined(d) && !this.matchData(d)) return false; 1328 | if (angular.isDefined(h) && !this.matchHeaders(h)) return false; 1329 | return true; 1330 | }; 1331 | 1332 | this.matchUrl = function(u) { 1333 | if (!url) return true; 1334 | if (angular.isFunction(url.test)) return url.test(u); 1335 | return url == u; 1336 | }; 1337 | 1338 | this.matchHeaders = function(h) { 1339 | if (angular.isUndefined(headers)) return true; 1340 | if (angular.isFunction(headers)) return headers(h); 1341 | return angular.equals(headers, h); 1342 | }; 1343 | 1344 | this.matchData = function(d) { 1345 | if (angular.isUndefined(data)) return true; 1346 | if (data && angular.isFunction(data.test)) return data.test(d); 1347 | if (data && !angular.isString(data)) return angular.toJson(data) == d; 1348 | return data == d; 1349 | }; 1350 | 1351 | this.toString = function() { 1352 | return method + ' ' + url; 1353 | }; 1354 | } 1355 | 1356 | function MockXhr() { 1357 | 1358 | // hack for testing $http, $httpBackend 1359 | MockXhr.$$lastInstance = this; 1360 | 1361 | this.open = function(method, url, async) { 1362 | this.$$method = method; 1363 | this.$$url = url; 1364 | this.$$async = async; 1365 | this.$$reqHeaders = {}; 1366 | this.$$respHeaders = {}; 1367 | }; 1368 | 1369 | this.send = function(data) { 1370 | this.$$data = data; 1371 | }; 1372 | 1373 | this.setRequestHeader = function(key, value) { 1374 | this.$$reqHeaders[key] = value; 1375 | }; 1376 | 1377 | this.getResponseHeader = function(name) { 1378 | // the lookup must be case insensitive, that's why we try two quick lookups and full scan at last 1379 | var header = this.$$respHeaders[name]; 1380 | if (header) return header; 1381 | 1382 | name = angular.lowercase(name); 1383 | header = this.$$respHeaders[name]; 1384 | if (header) return header; 1385 | 1386 | header = undefined; 1387 | angular.forEach(this.$$respHeaders, function(headerVal, headerName) { 1388 | if (!header && angular.lowercase(headerName) == name) header = headerVal; 1389 | }); 1390 | return header; 1391 | }; 1392 | 1393 | this.getAllResponseHeaders = function() { 1394 | var lines = []; 1395 | 1396 | angular.forEach(this.$$respHeaders, function(value, key) { 1397 | lines.push(key + ': ' + value); 1398 | }); 1399 | return lines.join('\n'); 1400 | }; 1401 | 1402 | this.abort = angular.noop; 1403 | } 1404 | 1405 | 1406 | /** 1407 | * @ngdoc function 1408 | * @name ngMock.$timeout 1409 | * @description 1410 | * 1411 | * This service is just a simple decorator for {@link ng.$timeout $timeout} service 1412 | * that adds a "flush" method. 1413 | */ 1414 | 1415 | /** 1416 | * @ngdoc method 1417 | * @name ngMock.$timeout#flush 1418 | * @methodOf ngMock.$timeout 1419 | * @description 1420 | * 1421 | * Flushes the queue of pending tasks. 1422 | */ 1423 | 1424 | /** 1425 | * 1426 | */ 1427 | angular.mock.$RootElementProvider = function() { 1428 | this.$get = function() { 1429 | return angular.element(''); 1430 | } 1431 | }; 1432 | 1433 | /** 1434 | * @ngdoc overview 1435 | * @name ngMock 1436 | * @description 1437 | * 1438 | * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful 1439 | * mocks to the {@link AUTO.$injector $injector}. 1440 | */ 1441 | angular.module('ngMock', ['ng']).provider({ 1442 | $browser: angular.mock.$BrowserProvider, 1443 | $exceptionHandler: angular.mock.$ExceptionHandlerProvider, 1444 | $log: angular.mock.$LogProvider, 1445 | $httpBackend: angular.mock.$HttpBackendProvider, 1446 | $rootElement: angular.mock.$RootElementProvider 1447 | }).config(function($provide) { 1448 | $provide.decorator('$timeout', function($delegate, $browser) { 1449 | $delegate.flush = function(delay) { 1450 | $browser.defer.flush(delay); 1451 | }; 1452 | return $delegate; 1453 | }); 1454 | }); 1455 | 1456 | 1457 | /** 1458 | * @ngdoc overview 1459 | * @name ngMockE2E 1460 | * @description 1461 | * 1462 | * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing. 1463 | * Currently there is only one mock present in this module - 1464 | * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock. 1465 | */ 1466 | angular.module('ngMockE2E', ['ng']).config(function($provide) { 1467 | $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator); 1468 | }); 1469 | 1470 | /** 1471 | * @ngdoc object 1472 | * @name ngMockE2E.$httpBackend 1473 | * @description 1474 | * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of 1475 | * applications that use the {@link ng.$http $http service}. 1476 | * 1477 | * *Note*: For fake http backend implementation suitable for unit testing please see 1478 | * {@link ngMock.$httpBackend unit-testing $httpBackend mock}. 1479 | * 1480 | * This implementation can be used to respond with static or dynamic responses via the `when` api 1481 | * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the 1482 | * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch 1483 | * templates from a webserver). 1484 | * 1485 | * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application 1486 | * is being developed with the real backend api replaced with a mock, it is often desirable for 1487 | * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch 1488 | * templates or static files from the webserver). To configure the backend with this behavior 1489 | * use the `passThrough` request handler of `when` instead of `respond`. 1490 | * 1491 | * Additionally, we don't want to manually have to flush mocked out requests like we do during unit 1492 | * testing. For this reason the e2e $httpBackend automatically flushes mocked out requests 1493 | * automatically, closely simulating the behavior of the XMLHttpRequest object. 1494 | * 1495 | * To setup the application to run with this http backend, you have to create a module that depends 1496 | * on the `ngMockE2E` and your application modules and defines the fake backend: 1497 | * 1498 | *
1499 | * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']); 1500 | * myAppDev.run(function($httpBackend) { 1501 | * phones = [{name: 'phone1'}, {name: 'phone2'}]; 1502 | * 1503 | * // returns the current list of phones 1504 | * $httpBackend.whenGET('/phones').respond(phones); 1505 | * 1506 | * // adds a new phone to the phones array 1507 | * $httpBackend.whenPOST('/phones').respond(function(method, url, data) { 1508 | * phones.push(angular.fromJson(data)); 1509 | * }); 1510 | * $httpBackend.whenGET(/^\/templates\//).passThrough(); 1511 | * //... 1512 | * }); 1513 | *1514 | * 1515 | * Afterwards, bootstrap your app with this new module. 1516 | */ 1517 | 1518 | /** 1519 | * @ngdoc method 1520 | * @name ngMockE2E.$httpBackend#when 1521 | * @methodOf ngMockE2E.$httpBackend 1522 | * @description 1523 | * Creates a new backend definition. 1524 | * 1525 | * @param {string} method HTTP method. 1526 | * @param {string|RegExp} url HTTP url. 1527 | * @param {(string|RegExp)=} data HTTP request body. 1528 | * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header 1529 | * object and returns true if the headers match the current definition. 1530 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1531 | * control how a matched request is handled. 1532 | * 1533 | * - respond – `{function([status,] data[, headers])|function(function(method, url, data, headers)}` 1534 | * – The respond method takes a set of static data to be returned or a function that can return 1535 | * an array containing response status (number), response data (string) and response headers 1536 | * (Object). 1537 | * - passThrough – `{function()}` – Any request matching a backend definition with `passThrough` 1538 | * handler, will be pass through to the real backend (an XHR request will be made to the 1539 | * server. 1540 | */ 1541 | 1542 | /** 1543 | * @ngdoc method 1544 | * @name ngMockE2E.$httpBackend#whenGET 1545 | * @methodOf ngMockE2E.$httpBackend 1546 | * @description 1547 | * Creates a new backend definition for GET requests. For more info see `when()`. 1548 | * 1549 | * @param {string|RegExp} url HTTP url. 1550 | * @param {(Object|function(Object))=} headers HTTP headers. 1551 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1552 | * control how a matched request is handled. 1553 | */ 1554 | 1555 | /** 1556 | * @ngdoc method 1557 | * @name ngMockE2E.$httpBackend#whenHEAD 1558 | * @methodOf ngMockE2E.$httpBackend 1559 | * @description 1560 | * Creates a new backend definition for HEAD requests. For more info see `when()`. 1561 | * 1562 | * @param {string|RegExp} url HTTP url. 1563 | * @param {(Object|function(Object))=} headers HTTP headers. 1564 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1565 | * control how a matched request is handled. 1566 | */ 1567 | 1568 | /** 1569 | * @ngdoc method 1570 | * @name ngMockE2E.$httpBackend#whenDELETE 1571 | * @methodOf ngMockE2E.$httpBackend 1572 | * @description 1573 | * Creates a new backend definition for DELETE requests. For more info see `when()`. 1574 | * 1575 | * @param {string|RegExp} url HTTP url. 1576 | * @param {(Object|function(Object))=} headers HTTP headers. 1577 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1578 | * control how a matched request is handled. 1579 | */ 1580 | 1581 | /** 1582 | * @ngdoc method 1583 | * @name ngMockE2E.$httpBackend#whenPOST 1584 | * @methodOf ngMockE2E.$httpBackend 1585 | * @description 1586 | * Creates a new backend definition for POST requests. For more info see `when()`. 1587 | * 1588 | * @param {string|RegExp} url HTTP url. 1589 | * @param {(string|RegExp)=} data HTTP request body. 1590 | * @param {(Object|function(Object))=} headers HTTP headers. 1591 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1592 | * control how a matched request is handled. 1593 | */ 1594 | 1595 | /** 1596 | * @ngdoc method 1597 | * @name ngMockE2E.$httpBackend#whenPUT 1598 | * @methodOf ngMockE2E.$httpBackend 1599 | * @description 1600 | * Creates a new backend definition for PUT requests. For more info see `when()`. 1601 | * 1602 | * @param {string|RegExp} url HTTP url. 1603 | * @param {(string|RegExp)=} data HTTP request body. 1604 | * @param {(Object|function(Object))=} headers HTTP headers. 1605 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1606 | * control how a matched request is handled. 1607 | */ 1608 | 1609 | /** 1610 | * @ngdoc method 1611 | * @name ngMockE2E.$httpBackend#whenPATCH 1612 | * @methodOf ngMockE2E.$httpBackend 1613 | * @description 1614 | * Creates a new backend definition for PATCH requests. For more info see `when()`. 1615 | * 1616 | * @param {string|RegExp} url HTTP url. 1617 | * @param {(string|RegExp)=} data HTTP request body. 1618 | * @param {(Object|function(Object))=} headers HTTP headers. 1619 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1620 | * control how a matched request is handled. 1621 | */ 1622 | 1623 | /** 1624 | * @ngdoc method 1625 | * @name ngMockE2E.$httpBackend#whenJSONP 1626 | * @methodOf ngMockE2E.$httpBackend 1627 | * @description 1628 | * Creates a new backend definition for JSONP requests. For more info see `when()`. 1629 | * 1630 | * @param {string|RegExp} url HTTP url. 1631 | * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that 1632 | * control how a matched request is handled. 1633 | */ 1634 | angular.mock.e2e = {}; 1635 | angular.mock.e2e.$httpBackendDecorator = ['$delegate', '$browser', createHttpBackendMock]; 1636 | 1637 | 1638 | angular.mock.clearDataCache = function() { 1639 | var key, 1640 | cache = angular.element.cache; 1641 | 1642 | for(key in cache) { 1643 | if (cache.hasOwnProperty(key)) { 1644 | var handle = cache[key].handle; 1645 | 1646 | handle && angular.element(handle.elem).unbind(); 1647 | delete cache[key]; 1648 | } 1649 | } 1650 | }; 1651 | 1652 | 1653 | 1654 | window.jasmine && (function(window) { 1655 | 1656 | afterEach(function() { 1657 | var spec = getCurrentSpec(); 1658 | var injector = spec.$injector; 1659 | 1660 | spec.$injector = null; 1661 | spec.$modules = null; 1662 | 1663 | if (injector) { 1664 | injector.get('$rootElement').unbind(); 1665 | injector.get('$browser').pollFns.length = 0; 1666 | } 1667 | 1668 | angular.mock.clearDataCache(); 1669 | 1670 | // clean up jquery's fragment cache 1671 | angular.forEach(angular.element.fragments, function(val, key) { 1672 | delete angular.element.fragments[key]; 1673 | }); 1674 | 1675 | MockXhr.$$lastInstance = null; 1676 | 1677 | angular.forEach(angular.callbacks, function(val, key) { 1678 | delete angular.callbacks[key]; 1679 | }); 1680 | angular.callbacks.counter = 0; 1681 | }); 1682 | 1683 | function getCurrentSpec() { 1684 | return jasmine.getEnv().currentSpec; 1685 | } 1686 | 1687 | function isSpecRunning() { 1688 | var spec = getCurrentSpec(); 1689 | return spec && spec.queue.running; 1690 | } 1691 | 1692 | /** 1693 | * @ngdoc function 1694 | * @name angular.mock.module 1695 | * @description 1696 | * 1697 | * *NOTE*: This function is also published on window for easy access.
1742 | * 1743 | * angular.module('myApplicationModule', []) 1744 | * .value('mode', 'app') 1745 | * .value('version', 'v1.0.1'); 1746 | * 1747 | * 1748 | * describe('MyApp', function() { 1749 | * 1750 | * // You need to load modules that you want to test, 1751 | * // it loads only the "ng" module by default. 1752 | * beforeEach(module('myApplicationModule')); 1753 | * 1754 | * 1755 | * // inject() is used to inject arguments of all given functions 1756 | * it('should provide a version', inject(function(mode, version) { 1757 | * expect(version).toEqual('v1.0.1'); 1758 | * expect(mode).toEqual('app'); 1759 | * })); 1760 | * 1761 | * 1762 | * // The inject and module method can also be used inside of the it or beforeEach 1763 | * it('should override a version and test the new version is injected', function() { 1764 | * // module() takes functions or strings (module aliases) 1765 | * module(function($provide) { 1766 | * $provide.value('version', 'overridden'); // override version here 1767 | * }); 1768 | * 1769 | * inject(function(version) { 1770 | * expect(version).toEqual('overridden'); 1771 | * }); 1772 | * )); 1773 | * }); 1774 | * 1775 | *1776 | * 1777 | * @param {...Function} fns any number of functions which will be injected using the injector. 1778 | */ 1779 | window.inject = angular.mock.inject = function() { 1780 | var blockFns = Array.prototype.slice.call(arguments, 0); 1781 | var errorForStack = new Error('Declaration Location'); 1782 | return isSpecRunning() ? workFn() : workFn; 1783 | ///////////////////// 1784 | function workFn() { 1785 | var spec = getCurrentSpec(); 1786 | var modules = spec.$modules || []; 1787 | modules.unshift('ngMock'); 1788 | modules.unshift('ng'); 1789 | var injector = spec.$injector; 1790 | if (!injector) { 1791 | injector = spec.$injector = angular.injector(modules); 1792 | } 1793 | for(var i = 0, ii = blockFns.length; i < ii; i++) { 1794 | try { 1795 | injector.invoke(blockFns[i] || angular.noop, this); 1796 | } catch (e) { 1797 | if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack; 1798 | throw e; 1799 | } finally { 1800 | errorForStack = null; 1801 | } 1802 | } 1803 | } 1804 | }; 1805 | })(window); 1806 | -------------------------------------------------------------------------------- /lib/angular.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.0.7 3 | (c) 2010-2012 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(P,T,q){'use strict';function m(b,a,c){var d;if(b)if(H(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==m)b.forEach(a,c);else if(!b||typeof b.length!=="number"?0:typeof b.hasOwnProperty!="function"&&typeof b.constructor!="function"||b instanceof K||ca&&b instanceof ca||wa.call(b)!=="[object Object]"||typeof b.callee==="function")for(d=0;d
o.priority)&&o.restrict.indexOf(g)!=-1)d.push(o),h=!0}catch(n){k(n)}return h}function $(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b, 47 | function(b,g){g=="class"?(M(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):g=="style"?e.attr("style",e.attr("style")+";"+b):g.charAt(0)!="$"&&!a.hasOwnProperty(g)&&(a[g]=b,d[g]=c[g])})}function R(a,b,c,d,e,j,h){var i=[],k,o,p=c[0],t=a.shift(),s=v({},t,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");l.get(t.templateUrl,{cache:n}).success(function(l){var n,t,l=Fb(l);if(j){t=u("