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 +4 -4
- data/Gruntfile.js +4 -2
- data/README.md +59 -12
- data/bower.json +3 -2
- data/dist/ember-data-factory-guy.js +826 -97
- data/dist/ember-data-factory-guy.min.js +1 -1
- data/ember-data-factory-guy.gemspec +1 -1
- data/package.json +1 -1
- data/src/factory_guy.js +11 -10
- data/src/factory_guy_test_mixin.js +91 -62
- data/src/store.js +33 -26
- data/tests/active_model_adapter_factory_test.js +38 -54
- data/tests/factory_guy_test.js +4 -4
- data/tests/factory_guy_test_mixin_test.js +217 -22
- data/tests/index.html +4 -4
- data/tests/rest_adapter_factory_test.js +38 -39
- data/tests/support/factories/hat_factory.js +8 -0
- data/tests/support/factories/outfit_factory.js +8 -0
- data/tests/support/factories/profile_factory.js +5 -0
- data/tests/support/factories/project_factory.js +2 -0
- data/tests/support/factories/user_factory.js +43 -29
- data/tests/support/models/hat.js +1 -0
- data/tests/support/models/outfit.js +4 -0
- data/tests/support/models/user.js +1 -0
- data/tests/support/test_helper.js +4 -192
- data/tests/test_setup.js +74 -29
- data/vendor/assets/javascripts/ember_data_factory_guy.js +826 -97
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c363f00f4ebb7fb8180ca566590bc388b72088a
|
4
|
+
data.tar.gz: 48aef40535b00c54b9c593c12a3b795452d7e8f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
11
|
-
- 0.7.1
|
12
|
-
- 0.7.
|
13
|
-
- 0.7.
|
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.
|
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
|
-
|
569
|
+
#### Using FactoryGuyTestMixin
|
570
570
|
|
571
571
|
- Uses mockjax
|
572
572
|
- Has helper methods
|
573
|
-
-
|
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
|
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
|
+
"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
|
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
|
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
|
366
|
-
@param {String} trait trait
|
367
|
-
@param {Object} opts
|
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
|
395
|
-
@param {Number} number
|
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
|
484
|
-
@param {
|
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 (
|
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
|
-
|
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 (
|
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(
|
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}
|
819
|
-
@param {
|
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 (
|
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
|
876
|
-
failed find by passing in
|
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
|
-
|
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 =
|
885
|
-
|
886
|
-
var url = this.buildURL(modelName
|
887
|
-
|
888
|
-
|
889
|
-
|
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
|
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 {
|
901
|
-
@param {
|
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 (
|
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
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
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
|
948
|
+
failed update by passing in success argument as false.
|
918
949
|
|
919
|
-
@param {String} type
|
920
|
-
@param {String} id
|
921
|
-
@param {
|
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,
|
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: (
|
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
|
967
|
+
failed delete by passing in success argument as false.
|
934
968
|
|
935
|
-
@param {String} type
|
936
|
-
@param {String} id
|
937
|
-
@param {
|
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,
|
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: (
|
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);
|