ember-data-factory-guy 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c2abf7589fecda0e42120d5c2e9bf8efc2caef7
4
- data.tar.gz: 93fb335e1e15c4ad91be1b1716b7b30c71483f03
3
+ metadata.gz: 0c363f00f4ebb7fb8180ca566590bc388b72088a
4
+ data.tar.gz: 48aef40535b00c54b9c593c12a3b795452d7e8f2
5
5
  SHA512:
6
- metadata.gz: 0b84a2d29390fd35426e6eb4e5fa5b04338999f5e2c859bebc8a76f53a24ad5b1487a18bacb2d0d110fc482b1211fdf6b4d412d91df557913eea1af496ce438a
7
- data.tar.gz: 4f707a3a8702fb5ab142bf97c1e5a9dbb94ee709989e929d3b4356ba847b6798c86c571dba925c8412678bc926024df409438078f4034a041148e6d2d710fefc
6
+ metadata.gz: c6f5c33236bbeee62b5a61dcf321ad535af9f3e7af1677b7cc4e0ffcecf2ae1996ff4af4e352956d7d644e931e974e4aec4bc8c91d36f29297b6fd04216d7f3e
7
+ data.tar.gz: c3280a7223574403a20cd4cc34b8bb47ca4ffbb4c044a6249a33370e61ee55dac5e441438cc460eeae006a46dce8b32bd321ce4f7c26635556f8f6bc5d466619
data/Gruntfile.js CHANGED
@@ -11,7 +11,8 @@ module.exports = function(grunt) {
11
11
  'src/model_definition.js',
12
12
  'src/factory_guy.js',
13
13
  'src/store.js',
14
- 'src/factory_guy_test_mixin.js'],
14
+ 'src/factory_guy_test_mixin.js',
15
+ 'bower_components/jquery-mockjax/jquery.mockjax.js'],
15
16
  dest: "dist/ember-data-factory-guy.js"
16
17
  },
17
18
  extra: {
@@ -25,7 +26,8 @@ module.exports = function(grunt) {
25
26
  'src/model_definition.js',
26
27
  'src/factory_guy.js',
27
28
  'src/store.js',
28
- 'src/factory_guy_test_mixin.js'],
29
+ 'src/factory_guy_test_mixin.js',
30
+ 'bower_components/jquery-mockjax/jquery.mockjax.js'],
29
31
  "vendor/assets/javascripts/factory_guy_has_many.js": ['src/has_many.js']
30
32
  }
31
33
  },
data/README.md CHANGED
@@ -7,12 +7,12 @@ so, if you are using ember-data-1.0.0-beta.8 and earlier, then be sure to use ve
7
7
  ( or below ) of ember-data-factory-guy.
8
8
 
9
9
  - Versions:
10
- - 0.6.4 -> ember-data-1.0.0-beta.8 and under
11
- - 0.7.1 -> ember-data-1.0.0-beta.10
12
- - 0.7.3 -> ember-data-1.0.0-beta.11
13
- - 0.7.3 -> ember-data-1.0.0-beta.12
10
+ - 0.6.4 -> ember-data-1.0.0-beta.8 and under
11
+ - 0.7.1.1 -> ember-data-1.0.0-beta.10
12
+ - 0.7.5 -> ember-data-1.0.0-beta.11
13
+ - 0.7.5 -> ember-data-1.0.0-beta.12
14
14
 
15
- **For versions ( 0.7.1 -> 0.7.3 ), support for the fixture adapter is currently broken.**
15
+ **For versions ( 0.7.1 -> 0.7.5 ), support for the fixture adapter is currently broken.**
16
16
 
17
17
  ## Using as Gem
18
18
 
@@ -517,7 +517,7 @@ the reverse 'user' belongsTo association is being setup for you on the project
517
517
  ```
518
518
 
519
519
 
520
- ###Testing models, controllers, views
520
+ ### Testing models, controllers, views
521
521
 
522
522
  - Testing the models, controllers and views in isolation
523
523
  - Use FactoryGuyTestMixin to help with testing
@@ -563,17 +563,17 @@ test("make a user using your applications default adapter", function() {
563
563
  ```
564
564
 
565
565
 
566
- ###Integration Tests
566
+ ### Integration Tests
567
567
 
568
568
 
569
- ##### Using FactoryGuyTestMixin
569
+ #### Using FactoryGuyTestMixin
570
570
 
571
571
  - Uses mockjax
572
572
  - Has helper methods
573
- - handleFind
573
+ - handleFindMany
574
574
  - handleCreate
575
- - handleUpdate
576
- - handleDelete
575
+ - handleUpdate ( can mock success or failure )
576
+ - handleDelete ( can mock success or failure )
577
577
 
578
578
  Since it is recommended to use your normal adapter ( which is usually a subclass of RESTAdapter, )
579
579
  FactoryGuyTestMixin assumes you will want to use that adapter to do your integration tests.
@@ -584,8 +584,55 @@ If you put models into the store ( with store#makeFixture ), the http GET call d
584
584
  since that model is already in the store.
585
585
 
586
586
  But what if you want to handle create, update or delete?
587
+
587
588
  FactoryGuy assumes you want to mock ajax calls with the mockjax library,
588
- and you will need to download and include that library to use the following feature.
589
+ and this is already bundled for you when you use the ember-data-factory-guy library.
590
+
591
+
592
+ ##### handleUpdate
593
+
594
+ *success case is the default*
595
+
596
+ ```javascript
597
+ var profile = store.makeFixture('profile');
598
+ testHelper.handleUpdate('profile', profile.id);
599
+
600
+ profile.set('description', 'good value');
601
+ profile.save() //=> will succeed
602
+ ````
603
+
604
+ *mocking failed update*
605
+
606
+ ```javascript
607
+ var profile = store.makeFixture('profile');
608
+ testHelper.handleUpdate('profile', profile.id, false);
609
+
610
+ profile.set('description', 'bad value');
611
+ profile.save() //=> will fail
612
+ ````
613
+
614
+
615
+ ##### handleDelete
616
+
617
+ *success case is the default*
618
+
619
+ ```javascript
620
+ var profile = store.makeFixture('profile');
621
+ testHelper.handleDelete('profile', profile.id);
622
+
623
+ profile.destroyRecord() // => will succeed
624
+ ````
625
+
626
+ *mocking failed delete*
627
+
628
+ ```javascript
629
+ var profile = store.makeFixture('profile');
630
+ // set the succeed flag to 'false'
631
+ testHelper.handleDelete('profile', profile.id, false);
632
+
633
+ profile.destroyRecord() // => will fail
634
+ ````
635
+
589
636
 
590
637
  Here is a sample of what you could do in a view test:
591
638
 
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-data-factory-guy",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "authors": [
5
5
  "Daniel Sudol <dansudol@yahoo.com>",
6
6
  "Opak Alex <opak.alexandr@gmail.com>"
@@ -21,7 +21,8 @@
21
21
  "ember": "1.7.0",
22
22
  "ember-data": "1.0.0-beta.11",
23
23
  "chance": "latest",
24
- "qunit": "latest"
24
+ "qunit": "latest",
25
+ "jquery-mockjax": "latest"
25
26
  },
26
27
 
27
28
  "ignore": [
@@ -328,9 +328,9 @@ FactoryGuy = {
328
328
  Given a fixture name like 'person' or 'dude' determine what model this name
329
329
  refers to. In this case it's 'person' for each one.
330
330
 
331
- @param {String} name a fixture name could be model name like 'person'
331
+ @param {String} name a fixture name could be model name like 'person'
332
332
  or a named person in model definition like 'dude'
333
- @returns {String} model name associated with fixture name or undefined if not found
333
+ @returns {String} model name associated with fixture name or undefined if not found
334
334
  */
335
335
  lookupModelForFixtureName: function (name) {
336
336
  var definition = this.lookupDefinitionForFixtureName(name);
@@ -360,11 +360,11 @@ FactoryGuy = {
360
360
  FactoryGuy.build('bob') for a 'bob' User
361
361
  FactoryGuy.build('bob', 'dude') for a 'bob' User with dude traits
362
362
  FactoryGuy.build('bob', 'dude', 'funny') for a 'bob' User with dude and funny traits
363
- FactoryGuy.build('bob', 'dude', name: 'wombat') for a 'bob' User with dude trait and custom attribute name of 'wombat'
363
+ FactoryGuy.build('bob', 'dude', {name: 'wombat'}) for a 'bob' User with dude trait and custom attribute name of 'wombat'
364
364
 
365
- @param {String} name Fixture name
366
- @param {String} trait trait name ( can be more than one )
367
- @param {Object} opts Options that will override default fixture values
365
+ @param {String} name fixture name
366
+ @param {String} trait optional trait names ( one or more )
367
+ @param {Object} opts optional fixture options that will override default fixture values
368
368
  @returns {Object} json fixture
369
369
  */
370
370
  build: function () {
@@ -378,6 +378,7 @@ FactoryGuy = {
378
378
  opts = args.pop();
379
379
  }
380
380
  var traits = args; // whatever is left are traits
381
+
381
382
  var definition = this.lookupDefinitionForFixtureName(name);
382
383
  if (!definition) {
383
384
  throw new Error("Can't find that factory named [" + name + "]");
@@ -391,10 +392,10 @@ FactoryGuy = {
391
392
  FactoryGuy.buildList('user', 2) for 2 User models
392
393
  FactoryGuy.build('bob', 2) for 2 User model with bob attributes
393
394
 
394
- @param {String} name fixture name
395
- @param {Number} number number of fixtures to create
396
- @param {String} trait (one or more)
397
- @param {Object} opts options that will override default fixture values
395
+ @param {String} name fixture name
396
+ @param {Number} number number of fixtures to create
397
+ @param {String} trait optional traits (one or more)
398
+ @param {Object} opts optional fixture options that will override default fixture values
398
399
  @returns {Array} list of fixtures
399
400
  */
400
401
  buildList: function () {
@@ -478,40 +479,47 @@ DS.Store.reopen({
478
479
 
479
480
  /**
480
481
  Make new fixture and save to store. If the store is using FixtureAdapter,
481
- will push to FIXTURE array, otherwise will use push method on adapter.
482
+ will push to FIXTURE array, otherwise will use push method on adapter to load
483
+ the record into the store
482
484
 
483
- @param {String} name name of fixture
484
- @param {Object} options fixture options
485
+ @param {String} name fixture name
486
+ @param {String} trait optional trait names ( one or more )
487
+ @param {Object} opts optional fixture options that will override default fixture values
485
488
  @returns {Object|DS.Model} json or record depending on the adapter type
486
489
  */
487
- makeFixture: function (name, options) {
490
+ makeFixture: function () {
488
491
  var store = this;
492
+ var fixture = FactoryGuy.build.apply(FactoryGuy,arguments);
493
+ var name = arguments[0];
489
494
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
490
- var fixture = FactoryGuy.build(name, options);
491
495
  var modelType = store.modelFor(modelName);
492
496
 
493
497
  if (this.usingFixtureAdapter()) {
494
498
  this.setAssociationsForFixtureAdapter(modelType, modelName, fixture);
495
499
  return FactoryGuy.pushFixture(modelType, fixture);
496
500
  } else {
497
- var store = this;
498
-
499
- var model;
500
- Em.run(function () {
501
- store.findEmbeddedAssociationsForRESTAdapter(modelType, fixture);
502
- if (fixture.type) {
503
- // assuming its polymorphic if there is a type attribute
504
- // is this too bold an assumption?
505
- modelName = fixture.type.underscore();
506
- modelType = store.modelFor(modelName);
507
- }
508
- model = store.push(modelName, fixture);
509
- store.setAssociationsForRESTAdapter(modelType, modelName, model);
510
- });
511
- return model;
501
+ return store.makeModel(modelType, fixture)
512
502
  }
513
503
  },
514
504
 
505
+ makeModel: function (modelType, fixture) {
506
+ var store = this,
507
+ modelName = store.modelFor(modelType).typeKey,
508
+ model;
509
+ Em.run(function () {
510
+ store.findEmbeddedAssociationsForRESTAdapter(modelType, fixture);
511
+ if (fixture.type) {
512
+ // assuming its polymorphic if there is a type attribute
513
+ // is this too bold an assumption?
514
+ modelName = fixture.type.underscore();
515
+ modelType = store.modelFor(modelName);
516
+ }
517
+ model = store.push(modelName, fixture);
518
+ store.setAssociationsForRESTAdapter(modelType, modelName, model);
519
+ });
520
+ return model;
521
+ },
522
+
515
523
  /**
516
524
  Make a list of Fixtures
517
525
 
@@ -520,10 +528,11 @@ DS.Store.reopen({
520
528
  @param {Object} options fixture options
521
529
  @returns {Array} list of json fixtures or records depending on the adapter type
522
530
  */
523
- makeList: function (name, number, options) {
531
+ makeList: function () {
524
532
  var arr = [];
533
+ var number = arguments[1];
525
534
  for (var i = 0; i < number; i++) {
526
- arr.push(this.makeFixture(name, options))
535
+ arr.push(this.makeFixture.apply(this,arguments));
527
536
  }
528
537
  return arr;
529
538
  },
@@ -597,7 +606,8 @@ DS.Store.reopen({
597
606
  },
598
607
 
599
608
  /**
600
- Before pushing the fixture to the store, do some preprocessing.
609
+ Before pushing the fixture to the store, do some preprocessing. Descend into the tree
610
+ of object data, and convert child objects to record instances recursively.
601
611
 
602
612
  If its a belongs to association, and the fixture has an object there,
603
613
  then push that model to the store and set the id of that new model
@@ -619,12 +629,11 @@ DS.Store.reopen({
619
629
  }
620
630
  if (relationship.kind == 'hasMany') {
621
631
  var hasManyRecords = fixture[relationship.key];
622
- // if the records are objects and not instances they need to be converted to
623
- // instances
624
632
  if (Ember.typeOf(hasManyRecords) == 'array') {
625
633
  if (Ember.typeOf(hasManyRecords[0]) == 'object') {
626
634
  var records = Em.A()
627
635
  hasManyRecords.map(function (object) {
636
+ store.findEmbeddedAssociationsForRESTAdapter(relationship.type, object);
628
637
  var record = store.push(relationship.type, object);
629
638
  records.push(record);
630
639
  return record;
@@ -681,7 +690,6 @@ DS.Store.reopen({
681
690
  }
682
691
  })
683
692
  }
684
-
685
693
  })
686
694
  },
687
695
 
@@ -812,15 +820,15 @@ FactoryGuyTestMixin = Em.Mixin.create({
812
820
  $.mockjax(request);
813
821
  },
814
822
 
823
+
815
824
  /**
816
825
  Build the json used for creating or finding a record.
817
826
 
818
- @param {String} name of the fixture ( or model ) to create/find
819
- @param {Object} opts fixture options
827
+ @param {String} modelName model name like 'user'
828
+ @param {String} fixture the fixture data
829
+ @return {Object} json response used for mocking a request
820
830
  */
821
- buildAjaxHttpResponse: function (name, opts) {
822
- var fixture = FactoryGuy.build(name, opts);
823
- var modelName = FactoryGuy.lookupModelForFixtureName(name);
831
+ buildAjaxHttpResponse: function (modelName, fixture) {
824
832
  if (this.usingActiveModelSerializer(modelName)) {
825
833
  this.toSnakeCase(fixture);
826
834
  }
@@ -829,6 +837,26 @@ FactoryGuyTestMixin = Em.Mixin.create({
829
837
  return hash;
830
838
  },
831
839
 
840
+
841
+ _collectArgs: function (args, fromMethod) {
842
+ var args = Array.prototype.slice.call(arguments);
843
+ var name = args.shift();
844
+ if (!name) {
845
+ throw new Error(fromMethod + " needs a factory name to build");
846
+ }
847
+ var succeed = true;
848
+ if (Ember.typeOf(args[args.length-1]) == 'boolean') {
849
+ succeed = args.pop();
850
+ }
851
+ var opts = {}
852
+ if (Ember.typeOf(args[args.length-1]) == 'object') {
853
+ opts = args.pop();
854
+ }
855
+ var traits = args; // whatever is left are traits
856
+
857
+ return {name: name, traits: traits, opts: opts, succeed: succeed}
858
+ },
859
+
832
860
  /**
833
861
  Convert Object's keys to snake case
834
862
 
@@ -856,95 +884,796 @@ FactoryGuyTestMixin = Em.Mixin.create({
856
884
  },
857
885
 
858
886
 
859
- handleSideloadFind: function (modelName, json, sideload) {
860
- var id = json.id
861
- var url = this.buildURL(modelName, id);
862
- var responseJson = {};
863
- responseJson[modelName] = json;
864
- $.extend(responseJson, sideload)
865
-
866
- this.stubEndpointForHttpRequest(
867
- url,
868
- responseJson,
869
- {type: 'GET', status: (status || 200)}
870
- )
871
- },
872
-
873
-
874
887
  /**
875
- Handling ajax GET ( find record ) for a model. You can mock
876
- failed find by passing in status of 500.
888
+ Handling ajax GET for finding all records for a type of model.
889
+ You can mock failed find by passing in success argument as false.
890
+
891
+ @param {String} name name of the fixture ( or model ) to find
892
+ @param {Number} number number of fixtures to create
893
+ @param {String} trait optional traits (one or more)
894
+ @param {Object} opts optional fixture options
895
+ @return {Object} json response
896
+ */
897
+ handleFindMany: function () {
898
+ var store = this.getStore();
899
+ // make the records and load them in the store
900
+ store.makeList.apply(store,arguments);
877
901
 
878
- @param {String} name of the fixture ( or model ) to find
879
- @param {Object} opts fixture options
880
- @param {Integer} status Optional HTTP status response code
881
- */
882
- handleFind: function (name, opts, status) {
902
+ var name = arguments[0];
883
903
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
884
- var responseJson = this.buildAjaxHttpResponse(name, opts);
885
- var id = responseJson[modelName].id
886
- var url = this.buildURL(modelName, id);
887
- this.stubEndpointForHttpRequest(
888
- url,
889
- responseJson,
890
- {type: 'GET', status: (status || 200)}
891
- )
892
- return responseJson;
904
+ var responseJson = {};
905
+ responseJson[modelName]=[];
906
+ var url = this.buildURL(modelName);
907
+ // mock the ajax call, but return nothing, since the records will be
908
+ // retrieved since they are already in the store
909
+ this.stubEndpointForHttpRequest(url, responseJson, {type: 'GET'})
893
910
  },
894
911
 
895
912
  /**
896
913
  Handling ajax POST ( create record ) for a model. You can mock
897
- failed create by passing in status of 500.
914
+ failed create by passing in success argument as false.
898
915
 
899
- @param {String} name of the fixture ( or model ) to create
900
- @param {Object} opts fixture options
901
- @param {Integer} status Optional HTTP status response code
916
+ @param {String} name name of the fixture ( or model ) to create
917
+ @param {String} trait optional traits ( one or more )
918
+ @param {Object} opts optional fixture options
919
+ @return {Object} json response
902
920
  */
903
- handleCreate: function (name, opts, status) {
921
+ handleCreate: function () {
922
+ var args = Array.prototype.slice.call(arguments);
923
+
924
+ var succeed = true;
925
+ if (Ember.typeOf(args[args.length-1]) == 'boolean') {
926
+ succeed = args.pop();
927
+ }
928
+
929
+ var name = args[0];
904
930
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
905
- var responseJson = this.buildAjaxHttpResponse(name, opts);
906
931
  var url = this.buildURL(modelName);
907
- this.stubEndpointForHttpRequest(
908
- url,
909
- responseJson,
910
- {type: 'POST', status: (status || 200)}
911
- )
912
- return responseJson;
932
+ var responseJson = {};
933
+ var httpOptions = {type: 'POST'}
934
+
935
+ if (succeed) {
936
+ var store = this.getStore();
937
+ // make the records and load them in the store
938
+ var model = store.makeFixture.apply(store,args);
939
+ responseJson[modelName]=model;
940
+ } else {
941
+ httpOptions.status = 500;
942
+ }
943
+ this.stubEndpointForHttpRequest(url, responseJson, httpOptions)
913
944
  },
914
945
 
915
946
  /**
916
947
  Handling ajax PUT ( update record ) for a model type. You can mock
917
- failed update by passing in status of 500.
948
+ failed update by passing in success argument as false.
918
949
 
919
- @param {String} type model type like 'user' for User model
920
- @param {String} id id of record to update
921
- @param {Integer} status Optional HTTP status response code
950
+ @param {String} type model type like 'user' for User model
951
+ @param {String} id id of record to update
952
+ @param {Boolean} succeed optional flag to indicate if the request
953
+ should succeed ( default is true )
922
954
  */
923
- handleUpdate: function (type, id, status) {
955
+ handleUpdate: function (type, id, succeed) {
956
+ succeed = succeed === undefined ? true : succeed;
957
+
924
958
  this.stubEndpointForHttpRequest(
925
959
  this.buildURL(type, id),
926
960
  {},
927
- {type: 'PUT', status: (status || 200)}
961
+ {type: 'PUT', status: (succeed ? 200 : 500)}
928
962
  )
929
963
  },
930
964
 
931
965
  /**
932
966
  Handling ajax DELETE ( delete record ) for a model type. You can mock
933
- failed delete by passing in status of 500.
967
+ failed delete by passing in success argument as false.
934
968
 
935
- @param {String} type model type like 'user' for User model
936
- @param {String} id id of record to update
937
- @param {Integer} status Optional HTTP status response code
969
+ @param {String} type model type like 'user' for User model
970
+ @param {String} id id of record to update
971
+ @param {Boolean} succeed optional flag to indicate if the request
972
+ should succeed ( default is true )
938
973
  */
939
- handleDelete: function (type, id, status) {
974
+ handleDelete: function (type, id, succeed) {
975
+ succeed = succeed === undefined ? true : succeed;
976
+
940
977
  this.stubEndpointForHttpRequest(
941
978
  this.buildURL(type, id),
942
979
  {},
943
- {type: 'DELETE', status: (status || 200)}
980
+ {type: 'DELETE', status: (succeed ? 200 : 500)}
944
981
  )
945
982
  },
946
983
 
947
984
  teardown: function () {
948
985
  FactoryGuy.resetModels(this.getStore());
949
986
  }
950
- })
987
+ });
988
+ /*!
989
+ * MockJax - jQuery Plugin to Mock Ajax requests
990
+ *
991
+ * Version: 1.6.1
992
+ * Released:
993
+ * Home: https://github.com/jakerella/jquery-mockjax
994
+ * Author: Jonathan Sharp (http://jdsharp.com)
995
+ * License: MIT,GPL
996
+ *
997
+ * Copyright (c) 2014 appendTo, Jordan Kasper
998
+ * NOTE: This repository was taken over by Jordan Kasper (@jakerella) October, 2014
999
+ *
1000
+ * Dual licensed under the MIT or GPL licenses.
1001
+ * http://opensource.org/licenses/MIT OR http://www.gnu.org/licenses/gpl-2.0.html
1002
+ */
1003
+ (function($) {
1004
+ var _ajax = $.ajax,
1005
+ mockHandlers = [],
1006
+ mockedAjaxCalls = [],
1007
+ unmockedAjaxCalls = [],
1008
+ CALLBACK_REGEX = /=\?(&|$)/,
1009
+ jsc = (new Date()).getTime();
1010
+
1011
+
1012
+ // Parse the given XML string.
1013
+ function parseXML(xml) {
1014
+ if ( window.DOMParser == undefined && window.ActiveXObject ) {
1015
+ DOMParser = function() { };
1016
+ DOMParser.prototype.parseFromString = function( xmlString ) {
1017
+ var doc = new ActiveXObject('Microsoft.XMLDOM');
1018
+ doc.async = 'false';
1019
+ doc.loadXML( xmlString );
1020
+ return doc;
1021
+ };
1022
+ }
1023
+
1024
+ try {
1025
+ var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' );
1026
+ if ( $.isXMLDoc( xmlDoc ) ) {
1027
+ var err = $('parsererror', xmlDoc);
1028
+ if ( err.length == 1 ) {
1029
+ throw new Error('Error: ' + $(xmlDoc).text() );
1030
+ }
1031
+ } else {
1032
+ throw new Error('Unable to parse XML');
1033
+ }
1034
+ return xmlDoc;
1035
+ } catch( e ) {
1036
+ var msg = ( e.name == undefined ? e : e.name + ': ' + e.message );
1037
+ $(document).trigger('xmlParseError', [ msg ]);
1038
+ return undefined;
1039
+ }
1040
+ }
1041
+
1042
+ // Check if the data field on the mock handler and the request match. This
1043
+ // can be used to restrict a mock handler to being used only when a certain
1044
+ // set of data is passed to it.
1045
+ function isMockDataEqual( mock, live ) {
1046
+ var identical = true;
1047
+ // Test for situations where the data is a querystring (not an object)
1048
+ if (typeof live === 'string') {
1049
+ // Querystring may be a regex
1050
+ return $.isFunction( mock.test ) ? mock.test(live) : mock == live;
1051
+ }
1052
+ $.each(mock, function(k) {
1053
+ if ( live[k] === undefined ) {
1054
+ identical = false;
1055
+ return identical;
1056
+ } else {
1057
+ if ( typeof live[k] === 'object' && live[k] !== null ) {
1058
+ if ( identical && $.isArray( live[k] ) ) {
1059
+ identical = $.isArray( mock[k] ) && live[k].length === mock[k].length;
1060
+ }
1061
+ identical = identical && isMockDataEqual(mock[k], live[k]);
1062
+ } else {
1063
+ if ( mock[k] && $.isFunction( mock[k].test ) ) {
1064
+ identical = identical && mock[k].test(live[k]);
1065
+ } else {
1066
+ identical = identical && ( mock[k] == live[k] );
1067
+ }
1068
+ }
1069
+ }
1070
+ });
1071
+
1072
+ return identical;
1073
+ }
1074
+
1075
+ // See if a mock handler property matches the default settings
1076
+ function isDefaultSetting(handler, property) {
1077
+ return handler[property] === $.mockjaxSettings[property];
1078
+ }
1079
+
1080
+ // Check the given handler should mock the given request
1081
+ function getMockForRequest( handler, requestSettings ) {
1082
+ // If the mock was registered with a function, let the function decide if we
1083
+ // want to mock this request
1084
+ if ( $.isFunction(handler) ) {
1085
+ return handler( requestSettings );
1086
+ }
1087
+
1088
+ // Inspect the URL of the request and check if the mock handler's url
1089
+ // matches the url for this ajax request
1090
+ if ( $.isFunction(handler.url.test) ) {
1091
+ // The user provided a regex for the url, test it
1092
+ if ( !handler.url.test( requestSettings.url ) ) {
1093
+ return null;
1094
+ }
1095
+ } else {
1096
+ // Look for a simple wildcard '*' or a direct URL match
1097
+ var star = handler.url.indexOf('*');
1098
+ if (handler.url !== requestSettings.url && star === -1 ||
1099
+ !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace(/\*/g, '.+')).test(requestSettings.url)) {
1100
+ return null;
1101
+ }
1102
+ }
1103
+
1104
+ // Inspect the data submitted in the request (either POST body or GET query string)
1105
+ if ( handler.data ) {
1106
+ if ( ! requestSettings.data || !isMockDataEqual(handler.data, requestSettings.data) ) {
1107
+ // They're not identical, do not mock this request
1108
+ return null;
1109
+ }
1110
+ }
1111
+ // Inspect the request type
1112
+ if ( handler && handler.type &&
1113
+ handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) {
1114
+ // The request type doesn't match (GET vs. POST)
1115
+ return null;
1116
+ }
1117
+
1118
+ return handler;
1119
+ }
1120
+
1121
+ function parseResponseTimeOpt(responseTime) {
1122
+ if ($.isArray(responseTime)) {
1123
+ var min = responseTime[0];
1124
+ var max = responseTime[1];
1125
+ return (typeof min === 'number' && typeof max === 'number') ? Math.floor(Math.random() * (max - min)) + min : null;
1126
+ } else {
1127
+ return (typeof responseTime === 'number') ? responseTime: null;
1128
+ }
1129
+ }
1130
+
1131
+ // Process the xhr objects send operation
1132
+ function _xhrSend(mockHandler, requestSettings, origSettings) {
1133
+
1134
+ // This is a substitute for < 1.4 which lacks $.proxy
1135
+ var process = (function(that) {
1136
+ return function() {
1137
+ return (function() {
1138
+ // The request has returned
1139
+ this.status = mockHandler.status;
1140
+ this.statusText = mockHandler.statusText;
1141
+ this.readyState = 1;
1142
+
1143
+ var finishRequest = function () {
1144
+ this.readyState = 4;
1145
+
1146
+ var onReady;
1147
+ // Copy over our mock to our xhr object before passing control back to
1148
+ // jQuery's onreadystatechange callback
1149
+ if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) {
1150
+ this.responseText = JSON.stringify(mockHandler.responseText);
1151
+ } else if ( requestSettings.dataType == 'xml' ) {
1152
+ if ( typeof mockHandler.responseXML == 'string' ) {
1153
+ this.responseXML = parseXML(mockHandler.responseXML);
1154
+ //in jQuery 1.9.1+, responseXML is processed differently and relies on responseText
1155
+ this.responseText = mockHandler.responseXML;
1156
+ } else {
1157
+ this.responseXML = mockHandler.responseXML;
1158
+ }
1159
+ } else if (typeof mockHandler.responseText === 'object' && mockHandler.responseText !== null) {
1160
+ // since jQuery 1.9 responseText type has to match contentType
1161
+ mockHandler.contentType = 'application/json';
1162
+ this.responseText = JSON.stringify(mockHandler.responseText);
1163
+ } else {
1164
+ this.responseText = mockHandler.responseText;
1165
+ }
1166
+ if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) {
1167
+ this.status = mockHandler.status;
1168
+ }
1169
+ if( typeof mockHandler.statusText === "string") {
1170
+ this.statusText = mockHandler.statusText;
1171
+ }
1172
+ // jQuery 2.0 renamed onreadystatechange to onload
1173
+ onReady = this.onreadystatechange || this.onload;
1174
+
1175
+ // jQuery < 1.4 doesn't have onreadystate change for xhr
1176
+ if ( $.isFunction( onReady ) ) {
1177
+ if( mockHandler.isTimeout) {
1178
+ this.status = -1;
1179
+ }
1180
+ onReady.call( this, mockHandler.isTimeout ? 'timeout' : undefined );
1181
+ } else if ( mockHandler.isTimeout ) {
1182
+ // Fix for 1.3.2 timeout to keep success from firing.
1183
+ this.status = -1;
1184
+ }
1185
+ };
1186
+
1187
+ // We have an executable function, call it to give
1188
+ // the mock handler a chance to update it's data
1189
+ if ( $.isFunction(mockHandler.response) ) {
1190
+ // Wait for it to finish
1191
+ if ( mockHandler.response.length === 2 ) {
1192
+ mockHandler.response(origSettings, function () {
1193
+ finishRequest.call(that);
1194
+ });
1195
+ return;
1196
+ } else {
1197
+ mockHandler.response(origSettings);
1198
+ }
1199
+ }
1200
+
1201
+ finishRequest.call(that);
1202
+ }).apply(that);
1203
+ };
1204
+ })(this);
1205
+
1206
+ if ( mockHandler.proxy ) {
1207
+ // We're proxying this request and loading in an external file instead
1208
+ _ajax({
1209
+ global: false,
1210
+ url: mockHandler.proxy,
1211
+ type: mockHandler.proxyType,
1212
+ data: mockHandler.data,
1213
+ dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType,
1214
+ complete: function(xhr) {
1215
+ mockHandler.responseXML = xhr.responseXML;
1216
+ mockHandler.responseText = xhr.responseText;
1217
+ // Don't override the handler status/statusText if it's specified by the config
1218
+ if (isDefaultSetting(mockHandler, 'status')) {
1219
+ mockHandler.status = xhr.status;
1220
+ }
1221
+ if (isDefaultSetting(mockHandler, 'statusText')) {
1222
+ mockHandler.statusText = xhr.statusText;
1223
+ }
1224
+ this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime) || 0);
1225
+ }
1226
+ });
1227
+ } else {
1228
+ // type == 'POST' || 'GET' || 'DELETE'
1229
+ if ( requestSettings.async === false ) {
1230
+ // TODO: Blocking delay
1231
+ process();
1232
+ } else {
1233
+ this.responseTimer = setTimeout(process, parseResponseTimeOpt(mockHandler.responseTime) || 50);
1234
+ }
1235
+ }
1236
+ }
1237
+
1238
+ // Construct a mocked XHR Object
1239
+ function xhr(mockHandler, requestSettings, origSettings, origHandler) {
1240
+ // Extend with our default mockjax settings
1241
+ mockHandler = $.extend(true, {}, $.mockjaxSettings, mockHandler);
1242
+
1243
+ if (typeof mockHandler.headers === 'undefined') {
1244
+ mockHandler.headers = {};
1245
+ }
1246
+ if (typeof requestSettings.headers === 'undefined') {
1247
+ requestSettings.headers = {};
1248
+ }
1249
+ if ( mockHandler.contentType ) {
1250
+ mockHandler.headers['content-type'] = mockHandler.contentType;
1251
+ }
1252
+
1253
+ return {
1254
+ status: mockHandler.status,
1255
+ statusText: mockHandler.statusText,
1256
+ readyState: 1,
1257
+ open: function() { },
1258
+ send: function() {
1259
+ origHandler.fired = true;
1260
+ _xhrSend.call(this, mockHandler, requestSettings, origSettings);
1261
+ },
1262
+ abort: function() {
1263
+ clearTimeout(this.responseTimer);
1264
+ },
1265
+ setRequestHeader: function(header, value) {
1266
+ requestSettings.headers[header] = value;
1267
+ },
1268
+ getResponseHeader: function(header) {
1269
+ // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery
1270
+ if ( mockHandler.headers && mockHandler.headers[header] ) {
1271
+ // Return arbitrary headers
1272
+ return mockHandler.headers[header];
1273
+ } else if ( header.toLowerCase() == 'last-modified' ) {
1274
+ return mockHandler.lastModified || (new Date()).toString();
1275
+ } else if ( header.toLowerCase() == 'etag' ) {
1276
+ return mockHandler.etag || '';
1277
+ } else if ( header.toLowerCase() == 'content-type' ) {
1278
+ return mockHandler.contentType || 'text/plain';
1279
+ }
1280
+ },
1281
+ getAllResponseHeaders: function() {
1282
+ var headers = '';
1283
+ // since jQuery 1.9 responseText type has to match contentType
1284
+ if (mockHandler.contentType) {
1285
+ mockHandler.headers['Content-Type'] = mockHandler.contentType;
1286
+ }
1287
+ $.each(mockHandler.headers, function(k, v) {
1288
+ headers += k + ': ' + v + "\n";
1289
+ });
1290
+ return headers;
1291
+ }
1292
+ };
1293
+ }
1294
+
1295
+ // Process a JSONP mock request.
1296
+ function processJsonpMock( requestSettings, mockHandler, origSettings ) {
1297
+ // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here
1298
+ // because there isn't an easy hook for the cross domain script tag of jsonp
1299
+
1300
+ processJsonpUrl( requestSettings );
1301
+
1302
+ requestSettings.dataType = "json";
1303
+ if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) {
1304
+ createJsonpCallback(requestSettings, mockHandler, origSettings);
1305
+
1306
+ // We need to make sure
1307
+ // that a JSONP style response is executed properly
1308
+
1309
+ var rurl = /^(\w+:)?\/\/([^\/?#]+)/,
1310
+ parts = rurl.exec( requestSettings.url ),
1311
+ remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
1312
+
1313
+ requestSettings.dataType = "script";
1314
+ if(requestSettings.type.toUpperCase() === "GET" && remote ) {
1315
+ var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings );
1316
+
1317
+ // Check if we are supposed to return a Deferred back to the mock call, or just
1318
+ // signal success
1319
+ if(newMockReturn) {
1320
+ return newMockReturn;
1321
+ } else {
1322
+ return true;
1323
+ }
1324
+ }
1325
+ }
1326
+ return null;
1327
+ }
1328
+
1329
+ // Append the required callback parameter to the end of the request URL, for a JSONP request
1330
+ function processJsonpUrl( requestSettings ) {
1331
+ if ( requestSettings.type.toUpperCase() === "GET" ) {
1332
+ if ( !CALLBACK_REGEX.test( requestSettings.url ) ) {
1333
+ requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") +
1334
+ (requestSettings.jsonp || "callback") + "=?";
1335
+ }
1336
+ } else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) {
1337
+ requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?";
1338
+ }
1339
+ }
1340
+
1341
+ // Process a JSONP request by evaluating the mocked response text
1342
+ function processJsonpRequest( requestSettings, mockHandler, origSettings ) {
1343
+ // Synthesize the mock request for adding a script tag
1344
+ var callbackContext = origSettings && origSettings.context || requestSettings,
1345
+ newMock = null;
1346
+
1347
+
1348
+ // If the response handler on the moock is a function, call it
1349
+ if ( mockHandler.response && $.isFunction(mockHandler.response) ) {
1350
+ mockHandler.response(origSettings);
1351
+ } else {
1352
+
1353
+ // Evaluate the responseText javascript in a global context
1354
+ if( typeof mockHandler.responseText === 'object' ) {
1355
+ $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')');
1356
+ } else {
1357
+ $.globalEval( '(' + mockHandler.responseText + ')');
1358
+ }
1359
+ }
1360
+
1361
+ // Successful response
1362
+ setTimeout(function() {
1363
+ jsonpSuccess( requestSettings, callbackContext, mockHandler );
1364
+ jsonpComplete( requestSettings, callbackContext, mockHandler );
1365
+ }, parseResponseTimeOpt(mockHandler.responseTime) || 0);
1366
+
1367
+ // If we are running under jQuery 1.5+, return a deferred object
1368
+ if($.Deferred){
1369
+ newMock = new $.Deferred();
1370
+ if(typeof mockHandler.responseText == "object"){
1371
+ newMock.resolveWith( callbackContext, [mockHandler.responseText] );
1372
+ }
1373
+ else{
1374
+ newMock.resolveWith( callbackContext, [$.parseJSON( mockHandler.responseText )] );
1375
+ }
1376
+ }
1377
+ return newMock;
1378
+ }
1379
+
1380
+
1381
+ // Create the required JSONP callback function for the request
1382
+ function createJsonpCallback( requestSettings, mockHandler, origSettings ) {
1383
+ var callbackContext = origSettings && origSettings.context || requestSettings;
1384
+ var jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++);
1385
+
1386
+ // Replace the =? sequence both in the query string and the data
1387
+ if ( requestSettings.data ) {
1388
+ requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1");
1389
+ }
1390
+
1391
+ requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1");
1392
+
1393
+
1394
+ // Handle JSONP-style loading
1395
+ window[ jsonp ] = window[ jsonp ] || function( tmp ) {
1396
+ data = tmp;
1397
+ jsonpSuccess( requestSettings, callbackContext, mockHandler );
1398
+ jsonpComplete( requestSettings, callbackContext, mockHandler );
1399
+ // Garbage collect
1400
+ window[ jsonp ] = undefined;
1401
+
1402
+ try {
1403
+ delete window[ jsonp ];
1404
+ } catch(e) {}
1405
+
1406
+ if ( head ) {
1407
+ head.removeChild( script );
1408
+ }
1409
+ };
1410
+ }
1411
+
1412
+ // The JSONP request was successful
1413
+ function jsonpSuccess(requestSettings, callbackContext, mockHandler) {
1414
+ // If a local callback was specified, fire it and pass it the data
1415
+ if ( requestSettings.success ) {
1416
+ requestSettings.success.call( callbackContext, mockHandler.responseText || "", status, {} );
1417
+ }
1418
+
1419
+ // Fire the global callback
1420
+ if ( requestSettings.global ) {
1421
+ (requestSettings.context ? $(requestSettings.context) : $.event).trigger("ajaxSuccess", [{}, requestSettings]);
1422
+ }
1423
+ }
1424
+
1425
+ // The JSONP request was completed
1426
+ function jsonpComplete(requestSettings, callbackContext) {
1427
+ // Process result
1428
+ if ( requestSettings.complete ) {
1429
+ requestSettings.complete.call( callbackContext, {} , status );
1430
+ }
1431
+
1432
+ // The request was completed
1433
+ if ( requestSettings.global ) {
1434
+ (requestSettings.context ? $(requestSettings.context) : $.event).trigger("ajaxComplete", [{}, requestSettings]);
1435
+ }
1436
+
1437
+ // Handle the global AJAX counter
1438
+ if ( requestSettings.global && ! --$.active ) {
1439
+ $.event.trigger( "ajaxStop" );
1440
+ }
1441
+ }
1442
+
1443
+
1444
+ // The core $.ajax replacement.
1445
+ function handleAjax( url, origSettings ) {
1446
+ var mockRequest, requestSettings, mockHandler, overrideCallback;
1447
+
1448
+ // If url is an object, simulate pre-1.5 signature
1449
+ if ( typeof url === "object" ) {
1450
+ origSettings = url;
1451
+ url = undefined;
1452
+ } else {
1453
+ // work around to support 1.5 signature
1454
+ origSettings = origSettings || {};
1455
+ origSettings.url = url;
1456
+ }
1457
+
1458
+ // Extend the original settings for the request
1459
+ requestSettings = $.extend(true, {}, $.ajaxSettings, origSettings);
1460
+
1461
+ // Generic function to override callback methods for use with
1462
+ // callback options (onAfterSuccess, onAfterError, onAfterComplete)
1463
+ overrideCallback = function(action, mockHandler) {
1464
+ var origHandler = origSettings[action.toLowerCase()];
1465
+ return function() {
1466
+ if ( $.isFunction(origHandler) ) {
1467
+ origHandler.apply(this, [].slice.call(arguments));
1468
+ }
1469
+ mockHandler['onAfter' + action]();
1470
+ };
1471
+ };
1472
+
1473
+ // Iterate over our mock handlers (in registration order) until we find
1474
+ // one that is willing to intercept the request
1475
+ for(var k = 0; k < mockHandlers.length; k++) {
1476
+ if ( !mockHandlers[k] ) {
1477
+ continue;
1478
+ }
1479
+
1480
+ mockHandler = getMockForRequest( mockHandlers[k], requestSettings );
1481
+ if(!mockHandler) {
1482
+ // No valid mock found for this request
1483
+ continue;
1484
+ }
1485
+
1486
+ mockedAjaxCalls.push(requestSettings);
1487
+
1488
+ // If logging is enabled, log the mock to the console
1489
+ $.mockjaxSettings.log( mockHandler, requestSettings );
1490
+
1491
+
1492
+ if ( requestSettings.dataType && requestSettings.dataType.toUpperCase() === 'JSONP' ) {
1493
+ if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) {
1494
+ // This mock will handle the JSONP request
1495
+ return mockRequest;
1496
+ }
1497
+ }
1498
+
1499
+
1500
+ // Removed to fix #54 - keep the mocking data object intact
1501
+ //mockHandler.data = requestSettings.data;
1502
+
1503
+ mockHandler.cache = requestSettings.cache;
1504
+ mockHandler.timeout = requestSettings.timeout;
1505
+ mockHandler.global = requestSettings.global;
1506
+
1507
+ // In the case of a timeout, we just need to ensure
1508
+ // an actual jQuery timeout (That is, our reponse won't)
1509
+ // return faster than the timeout setting.
1510
+ if ( mockHandler.isTimeout ) {
1511
+ if ( mockHandler.responseTime > 1 ) {
1512
+ origSettings.timeout = mockHandler.responseTime - 1;
1513
+ } else {
1514
+ mockHandler.responseTime = 2;
1515
+ origSettings.timeout = 1;
1516
+ }
1517
+ mockHandler.isTimeout = false;
1518
+ }
1519
+
1520
+ // Set up onAfter[X] callback functions
1521
+ if ( $.isFunction( mockHandler.onAfterSuccess ) ) {
1522
+ origSettings.success = overrideCallback('Success', mockHandler);
1523
+ }
1524
+ if ( $.isFunction( mockHandler.onAfterError ) ) {
1525
+ origSettings.error = overrideCallback('Error', mockHandler);
1526
+ }
1527
+ if ( $.isFunction( mockHandler.onAfterComplete ) ) {
1528
+ origSettings.complete = overrideCallback('Complete', mockHandler);
1529
+ }
1530
+
1531
+ copyUrlParameters(mockHandler, origSettings);
1532
+
1533
+ (function(mockHandler, requestSettings, origSettings, origHandler) {
1534
+
1535
+ mockRequest = _ajax.call($, $.extend(true, {}, origSettings, {
1536
+ // Mock the XHR object
1537
+ xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ); }
1538
+ }));
1539
+ })(mockHandler, requestSettings, origSettings, mockHandlers[k]);
1540
+
1541
+ return mockRequest;
1542
+ }
1543
+
1544
+ // We don't have a mock request
1545
+ unmockedAjaxCalls.push(origSettings);
1546
+ if($.mockjaxSettings.throwUnmocked === true) {
1547
+ throw new Error('AJAX not mocked: ' + origSettings.url);
1548
+ }
1549
+ else { // trigger a normal request
1550
+ return _ajax.apply($, [origSettings]);
1551
+ }
1552
+ }
1553
+
1554
+ /**
1555
+ * Copies URL parameter values if they were captured by a regular expression
1556
+ * @param {Object} mockHandler
1557
+ * @param {Object} origSettings
1558
+ */
1559
+ function copyUrlParameters(mockHandler, origSettings) {
1560
+ //parameters aren't captured if the URL isn't a RegExp
1561
+ if (!(mockHandler.url instanceof RegExp)) {
1562
+ return;
1563
+ }
1564
+ //if no URL params were defined on the handler, don't attempt a capture
1565
+ if (!mockHandler.hasOwnProperty('urlParams')) {
1566
+ return;
1567
+ }
1568
+ var captures = mockHandler.url.exec(origSettings.url);
1569
+ //the whole RegExp match is always the first value in the capture results
1570
+ if (captures.length === 1) {
1571
+ return;
1572
+ }
1573
+ captures.shift();
1574
+ //use handler params as keys and capture resuts as values
1575
+ var i = 0,
1576
+ capturesLength = captures.length,
1577
+ paramsLength = mockHandler.urlParams.length,
1578
+ //in case the number of params specified is less than actual captures
1579
+ maxIterations = Math.min(capturesLength, paramsLength),
1580
+ paramValues = {};
1581
+ for (i; i < maxIterations; i++) {
1582
+ var key = mockHandler.urlParams[i];
1583
+ paramValues[key] = captures[i];
1584
+ }
1585
+ origSettings.urlParams = paramValues;
1586
+ }
1587
+
1588
+
1589
+ // Public
1590
+
1591
+ $.extend({
1592
+ ajax: handleAjax
1593
+ });
1594
+
1595
+ $.mockjaxSettings = {
1596
+ //url: null,
1597
+ //type: 'GET',
1598
+ log: function( mockHandler, requestSettings ) {
1599
+ if ( mockHandler.logging === false ||
1600
+ ( typeof mockHandler.logging === 'undefined' && $.mockjaxSettings.logging === false ) ) {
1601
+ return;
1602
+ }
1603
+ if ( window.console && console.log ) {
1604
+ var message = 'MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url;
1605
+ var request = $.extend({}, requestSettings);
1606
+
1607
+ if (typeof console.log === 'function') {
1608
+ console.log(message, request);
1609
+ } else {
1610
+ try {
1611
+ console.log( message + ' ' + JSON.stringify(request) );
1612
+ } catch (e) {
1613
+ console.log(message);
1614
+ }
1615
+ }
1616
+ }
1617
+ },
1618
+ logging: true,
1619
+ status: 200,
1620
+ statusText: "OK",
1621
+ responseTime: 500,
1622
+ isTimeout: false,
1623
+ throwUnmocked: false,
1624
+ contentType: 'text/plain',
1625
+ response: '',
1626
+ responseText: '',
1627
+ responseXML: '',
1628
+ proxy: '',
1629
+ proxyType: 'GET',
1630
+
1631
+ lastModified: null,
1632
+ etag: '',
1633
+ headers: {
1634
+ etag: 'IJF@H#@923uf8023hFO@I#H#',
1635
+ 'content-type' : 'text/plain'
1636
+ }
1637
+ };
1638
+
1639
+ $.mockjax = function(settings) {
1640
+ var i = mockHandlers.length;
1641
+ mockHandlers[i] = settings;
1642
+ return i;
1643
+ };
1644
+ $.mockjax.clear = function(i) {
1645
+ if ( arguments.length == 1 ) {
1646
+ mockHandlers[i] = null;
1647
+ } else {
1648
+ mockHandlers = [];
1649
+ }
1650
+ mockedAjaxCalls = [];
1651
+ unmockedAjaxCalls = [];
1652
+ };
1653
+ // support older, deprecated version
1654
+ $.mockjaxClear = function(i) {
1655
+ window.console && window.console.warn && window.console.warn( 'DEPRECATED: The $.mockjaxClear() method has been deprecated in 1.6.0. Please use $.mockjax.clear() as the older function will be removed soon!' );
1656
+ $.mockjax.clear();
1657
+ };
1658
+ $.mockjax.handler = function(i) {
1659
+ if ( arguments.length == 1 ) {
1660
+ return mockHandlers[i];
1661
+ }
1662
+ };
1663
+ $.mockjax.mockedAjaxCalls = function() {
1664
+ return mockedAjaxCalls;
1665
+ };
1666
+ $.mockjax.unfiredHandlers = function() {
1667
+ var results = [];
1668
+ for (var i=0, len=mockHandlers.length; i<len; i++) {
1669
+ var handler = mockHandlers[i];
1670
+ if (handler !== null && !handler.fired) {
1671
+ results.push(handler);
1672
+ }
1673
+ }
1674
+ return results;
1675
+ };
1676
+ $.mockjax.unmockedAjaxCalls = function() {
1677
+ return unmockedAjaxCalls;
1678
+ };
1679
+ })(jQuery);