ember-data-factory-guy 0.5.1 → 0.6.0

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: c49287f23a8f4b826b7baf71eef5742921013414
4
- data.tar.gz: 535da4db233369f9040ba0ac8d7d77077323c358
3
+ metadata.gz: 21456baccb82088ae063f86ee70e3582848c760a
4
+ data.tar.gz: 82e3178d129e0d7bb44e9a6c778cdf240a3b3f1b
5
5
  SHA512:
6
- metadata.gz: aaaa95a6d8d3814dfafe3f571667ccc381ad3582598e7b3f3400dce1ba68a61e28288c090e724e0e5a9b577825408e45637c8d01b94f2baece459f170f2c7690
7
- data.tar.gz: 269260acf8c9ea30ab715cedf8e185b583110da7f2922016338e9a28e9a612d190cd6a21714cc0b5c4dbcf06aeb3d80a0be26cdf0774f84d868ed680c3b1d316
6
+ metadata.gz: 37c4c45d592490dd3f80068cf75c8838d0bc2599164805b172331760827564d5e74246a129651c9c5e80357a01b1746ab923157e64c7ab65aeee55bc3ab33673
7
+ data.tar.gz: 295339f7367bbd5e604f3ec8dd18419658c97a8d4471dea0658bfda7a5b883b5c31e09cade02d5adf32efacbc8f282421eedba56fe8351e66cb8cd4f944ede37
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Daniel Sudol and contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -106,13 +106,16 @@ Let's say you have a few models like these:
106
106
  // use the 'userName' sequence for this attribute
107
107
  name: FactoryGuy.generate('userName')
108
108
  },
109
-
109
+ //
110
110
  // named 'user' type with custom attributes
111
+ //
111
112
  admin: {
112
113
  type: 'superuser',
113
114
  name: 'Admin'
114
115
  }
116
+ //
115
117
  // using a function for an attribute that refers to other attributes
118
+ //
116
119
  funny_user: {
117
120
  type: function(f) { return 'funny ' + f.name }
118
121
  }
@@ -140,9 +143,10 @@ Let's say you have a few models like these:
140
143
  user: {name: 'Dude'}
141
144
  },
142
145
  project_with_admin: {
143
- // for named association, use this FactoryGuy.association helper method
144
- user: FactoryGuy.association('admin')
146
+ // for named association, use the FactoryGuy.belongsTo helper method
147
+ user: FactoryGuy.belongsTo('admin')
145
148
  }
149
+
146
150
  });
147
151
 
148
152
  FactoryGuy.define('hat', {
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-data-factory-guy",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "authors": [
5
5
  "Daniel Sudol <dansudol@yahoo.com>",
6
6
  "Opak Alex <opak.alexandr@gmail.com>"
@@ -70,7 +70,7 @@ ModelDefinition = function (model, config) {
70
70
 
71
71
  @param {String} name fixture name
72
72
  @param {Object} opts attributes to override
73
- @param {String} traits array of traits
73
+ @param {String} traitArgs array of traits
74
74
  @returns {Object} json
75
75
  */
76
76
  this.build = function (name, opts, traitArgs) {
@@ -260,23 +260,70 @@ FactoryGuy = {
260
260
  default: {
261
261
  title: 'Project'
262
262
  },
263
+
264
+ // setup named project with built in associated user
263
265
  project_with_admin: {
264
- // for named association, use this FactoryGuy.association helper method
265
- user: FactoryGuy.association('admin')
266
+ user: FactoryGuy.belongsTo('admin')
266
267
  }
267
268
 
269
+ // or use as a trait
270
+ traits: {
271
+ with_admin: {
272
+ user: FactoryGuy.belongsTo('admin')
273
+ }
274
+ }
275
+ })
268
276
  ```
269
277
 
270
278
  @param {String} fixtureName fixture name
271
279
  @param {Object} opts options
272
280
  @returns {Function} wrapper function that will build the association json
273
281
  */
274
- association: function (fixtureName, opts) {
282
+ belongsTo: function (fixtureName, opts) {
275
283
  return function () {
276
284
  return FactoryGuy.build(fixtureName, opts);
277
285
  }
278
286
  },
279
287
 
288
+ association: function(fixtureName, opts) {
289
+ console.log('DEPRECATION Warning: use FactoryGuy.belongsTo instead')
290
+ return this.belongsTo(fixtureName, opts);
291
+ },
292
+
293
+ /**
294
+ Used in model definitions to define a hasMany association attribute.
295
+ For example:
296
+
297
+ ```
298
+ FactoryGuy.define('user', {
299
+ default: {
300
+ name: 'Bob'
301
+ },
302
+
303
+ // define the named user type that will have projects
304
+ user_with_projects: { FactoryGuy.hasMany('project', 2) }
305
+
306
+ // or use as a trait
307
+ traits: {
308
+ with_projects: {
309
+ projects: FactoryGuy.hasMany('project', 2)
310
+ }
311
+ }
312
+ })
313
+
314
+ ```
315
+
316
+ @param {String} fixtureName fixture name
317
+ @param {Number} number of hasMany association items to build
318
+ @param {Object} opts options
319
+ @returns {Function} wrapper function that will build the association json
320
+ */
321
+ hasMany: function (fixtureName, number, opts) {
322
+ return function () {
323
+ return FactoryGuy.buildList(fixtureName, number, opts);
324
+ }
325
+ },
326
+
280
327
  /**
281
328
  Given a fixture name like 'person' or 'dude' determine what model this name
282
329
  refers to. In this case it's 'person' for each one.
@@ -543,9 +590,6 @@ DS.Store.reopen({
543
590
  then push that model to the store and set the id of that new model
544
591
  as the attribute value in the fixture
545
592
 
546
- If it's a hasMany association, and its polymorphic, then convert the
547
- attribute value to a polymorphic style
548
-
549
593
  @param modelType
550
594
  @param fixture
551
595
  */
@@ -559,6 +603,19 @@ DS.Store.reopen({
559
603
  fixture[relationship.key] = belongsToRecord;
560
604
  }
561
605
  }
606
+ if (relationship.kind == 'hasMany') {
607
+ var hasManyRecords = fixture[relationship.key];
608
+ // if the records are objects and not instances they need to be converted to
609
+ // instances
610
+ if (Ember.typeOf(hasManyRecords) == 'array' && Ember.typeOf(hasManyRecords[0]) == 'object') {
611
+ var records = Em.A()
612
+ hasManyRecords.forEach(function(record) {
613
+ var record = store.push(relationship.type, record);
614
+ records.push(record);
615
+ })
616
+ fixture[relationship.key] = records;
617
+ }
618
+ }
562
619
  })
563
620
  },
564
621
 
@@ -895,6 +952,17 @@ FactoryGuyTestMixin = Em.Mixin.create({
895
952
  }
896
953
  },
897
954
 
955
+ /**
956
+ Build url for the mockjax call. Proxy to the adapters buildURL method.
957
+
958
+ @param {String} type model type name like 'user' for User model
959
+ @param {String} id
960
+ @return {String} url
961
+ */
962
+ buildURL: function (type, id) {
963
+ return this.getStore().adapterFor('application').buildURL(type, id);
964
+ },
965
+
898
966
  /**
899
967
  Handling ajax GET ( find record ) for a model. You can mock
900
968
  failed find by passing in status of 500.
@@ -907,7 +975,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
907
975
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
908
976
  var responseJson = this.buildAjaxHttpResponse(name, opts);
909
977
  var id = responseJson[modelName].id
910
- var url = "/" + Em.String.pluralize(modelName) + "/" + id;
978
+ var url = this.buildURL(modelName, id);
911
979
  this.stubEndpointForHttpRequest(
912
980
  url,
913
981
  responseJson,
@@ -927,7 +995,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
927
995
  handleCreate: function (name, opts, status) {
928
996
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
929
997
  var responseJson = this.buildAjaxHttpResponse(name, opts);
930
- var url = "/" + Em.String.pluralize(modelName);
998
+ var url = this.buildURL(modelName);
931
999
  this.stubEndpointForHttpRequest(
932
1000
  url,
933
1001
  responseJson,
@@ -940,13 +1008,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
940
1008
  Handling ajax PUT ( update record ) for a model type. You can mock
941
1009
  failed update by passing in status of 500.
942
1010
 
943
- @param {String} root modelType like 'user' for User
1011
+ @param {String} type model type like 'user' for User model
944
1012
  @param {String} id id of record to update
945
1013
  @param {Integer} status Optional HTTP status response code
946
1014
  */
947
- handleUpdate: function (root, id, status) {
1015
+ handleUpdate: function (type, id, status) {
948
1016
  this.stubEndpointForHttpRequest(
949
- "/" + Em.String.pluralize(root) + "/" + id,
1017
+ this.buildURL(type, id),
950
1018
  {},
951
1019
  {type: 'PUT', status: (status || 200)}
952
1020
  )
@@ -956,13 +1024,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
956
1024
  Handling ajax DELETE ( delete record ) for a model type. You can mock
957
1025
  failed delete by passing in status of 500.
958
1026
 
959
- @param {String} root modelType like 'user' for User
1027
+ @param {String} type model type like 'user' for User model
960
1028
  @param {String} id id of record to update
961
1029
  @param {Integer} status Optional HTTP status response code
962
1030
  */
963
- handleDelete: function (root, id, status) {
1031
+ handleDelete: function (type, id, status) {
964
1032
  this.stubEndpointForHttpRequest(
965
- "/" + Em.String.pluralize(root) + "/" + id,
1033
+ this.buildURL(type, id),
966
1034
  {},
967
1035
  {type: 'DELETE', status: (status || 200)}
968
1036
  )
@@ -1 +1 @@
1
- Sequence=function(fn){var index=1;this.next=function(){return fn.call(this,index++)};this.reset=function(){index=1}};function MissingSequenceError(message){this.toString=function(){return message}}ModelDefinition=function(model,config){var sequences={};var traits={};var defaultAttributes={};var namedModels={};var modelId=1;this.model=model;this.matchesName=function(name){return model==name||namedModels[name]};this.merge=function(config){};this.generate=function(name,sequenceFn){if(sequenceFn){if(!sequences[name]){sequences[name]=new Sequence(sequenceFn)}}var sequence=sequences[name];if(!sequence){throw new MissingSequenceError("Can not find that sequence named ["+sequenceName+"] in '"+model+"' definition")}return sequence.next()};this.build=function(name,opts,traitArgs){var traitsObj={};traitArgs.forEach(function(trait){$.extend(traitsObj,traits[trait])});var modelAttributes=namedModels[name]||{};var fixture=$.extend({},defaultAttributes,modelAttributes,traitsObj,opts);for(attribute in fixture){if(Ember.typeOf(fixture[attribute])=="function"){fixture[attribute]=fixture[attribute].call(this,fixture)}else if(Ember.typeOf(fixture[attribute])=="object"){fixture[attribute]=FactoryGuy.build(attribute,fixture[attribute])}}if(!fixture.id){fixture.id=modelId++}return fixture};this.buildList=function(name,number,traits,opts){var arr=[];for(var i=0;i<number;i++){arr.push(this.build(name,opts,traits))}return arr};this.reset=function(){modelId=1;for(name in sequences){sequences[name].reset()}};var parseDefault=function(object){if(!object){return}defaultAttributes=object};var parseTraits=function(object){if(!object){return}traits=object};var parseSequences=function(object){if(!object){return}for(sequenceName in object){var sequenceFn=object[sequenceName];if(Ember.typeOf(sequenceFn)!="function"){throw new Error("Problem with ["+sequenceName+"] sequence definition. Sequences must be functions")}object[sequenceName]=new Sequence(sequenceFn)}sequences=object};var parseConfig=function(config){parseSequences(config.sequences);delete config.sequences;parseTraits(config.traits);delete config.traits;parseDefault(config.default);delete config.default;namedModels=config};parseConfig(config)};FactoryGuy={modelDefinitions:{},define:function(model,config){if(this.modelDefinitions[model]){this.modelDefinitions[model].merge(config)}else{this.modelDefinitions[model]=new ModelDefinition(model,config)}},generate:function(nameOrFunction){var sortaRandomName=Math.floor((1+Math.random())*65536).toString(16)+Date.now();return function(){if(Em.typeOf(nameOrFunction)=="function"){return this.generate(sortaRandomName,nameOrFunction)}else{return this.generate(nameOrFunction)}}},association:function(fixtureName,opts){return function(){return FactoryGuy.build(fixtureName,opts)}},lookupModelForFixtureName:function(name){var definition=this.lookupDefinitionForFixtureName(name);if(definition){return definition.model}},lookupDefinitionForFixtureName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition}}},build:function(){var args=Array.prototype.slice.call(arguments);var opts={};var name=args.shift();if(!name){throw new Error("Build needs a factory name to build")}if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.build(name,opts,traits)},buildList:function(){var args=Array.prototype.slice.call(arguments);var name=args.shift();var number=args.shift();if(!name||!number){throw new Error("buildList needs a name and a number ( at least ) to build with")}var opts={};if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.buildList(name,number,traits,opts)},resetModels:function(store){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];definition.reset();try{var modelType=store.modelFor(definition.model);if(store.usingFixtureAdapter()){modelType.FIXTURES=[]}store.unloadAll(modelType)}catch(e){}}},pushFixture:function(modelClass,fixture){if(!modelClass["FIXTURES"]){modelClass["FIXTURES"]=[]}modelClass["FIXTURES"].push(fixture);return fixture},clear:function(opts){if(!opts){this.modelDefinitions={}}}};DS.Store.reopen({usingFixtureAdapter:function(){var adapter=this.adapterFor("application");return adapter instanceof DS.FixtureAdapter},makeFixture:function(name,options){var store=this;var modelName=FactoryGuy.lookupModelForFixtureName(name);var fixture=FactoryGuy.build(name,options);var modelType=store.modelFor(modelName);if(this.usingFixtureAdapter()){this.setAssociationsForFixtureAdapter(modelType,modelName,fixture);return FactoryGuy.pushFixture(modelType,fixture)}else{var store=this;var model;Em.run(function(){store.findEmbeddedBelongsToAssociationsForRESTAdapter(modelType,fixture);if(fixture.type){modelName=fixture.type.underscore();modelType=store.modelFor(modelName)}model=store.push(modelName,fixture);store.setAssociationsForRESTAdapter(modelType,modelName,model)});return model}},makeList:function(name,number,options){var arr=[];for(var i=0;i<number;i++){arr.push(this.makeFixture(name,options))}return arr},setAssociationsForFixtureAdapter:function(modelType,modelName,fixture){var self=this;var adapter=this.adapterFor("application");Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){if(fixture[relationship.key]){fixture[relationship.key].forEach(function(id){var hasManyfixtures=adapter.fixturesForType(relationship.type);var fixture=adapter.findFixtureById(hasManyfixtures,id);fixture[modelName]=fixture.id})}}if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(belongsToRecord){if(typeof belongsToRecord=="object"){FactoryGuy.pushFixture(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord.id}var hasManyName=self.findHasManyRelationshipNameForFixtureAdapter(relationship.type,relationship.parentType);var belongsToFixtures=adapter.fixturesForType(relationship.type);var belongsTofixture=adapter.findFixtureById(belongsToFixtures,fixture[relationship.key]);if(!belongsTofixture[hasManyName]){belongsTofixture[hasManyName]=[]}belongsTofixture[hasManyName].push(fixture.id)}}})},findEmbeddedBelongsToAssociationsForRESTAdapter:function(modelType,fixture){var store=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(Ember.typeOf(belongsToRecord)=="object"){belongsToRecord=store.push(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord}}})},setAssociationsForRESTAdapter:function(modelType,modelName,model){var self=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){var children=model.get(name)||[];children.forEach(function(child){var belongsToName=self.findRelationshipName("belongsTo",child.constructor,model);var hasManyName=self.findRelationshipName("hasMany",child.constructor,model);var inverseName=relationship.options&&relationship.options.inverse;if(belongsToName){child.set(belongsToName||inverseName,model)}else if(hasManyName){relation=child.get(hasManyName||inverseName)||[];relation.pushObject(model)}})}if(relationship.kind=="belongsTo"){var belongsToRecord=model.get(name);if(belongsToRecord){var setAssociations=function(){var hasManyName=self.findRelationshipName("hasMany",belongsToRecord.constructor,model);if(hasManyName){belongsToRecord.get(hasManyName).addObject(model);return}var oneToOneName=self.findRelationshipName("belongsTo",belongsToRecord.constructor,model);if(oneToOneName&&!(belongsToRecord.constructor==model.constructor)){belongsToRecord.set(oneToOneName,model)}};if(belongsToRecord.then){belongsToRecord.then(function(record){belongsToRecord=record;setAssociations()})}else{setAssociations()}}}})},findRelationshipName:function(kind,belongToModelType,childModel){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind==kind&&childModel instanceof relationship.type){relationshipName=relationship.key}});return relationshipName},findHasManyRelationshipNameForFixtureAdapter:function(belongToModelType,childModelType){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"&&childModelType==relationship.type){relationshipName=relationship.key}});return relationshipName},pushPayload:function(type,payload){if(this.usingFixtureAdapter()){var model=this.modelFor(modelName);FactoryGuy.pushFixture(model,payload)}else{this._super(type,payload)}}});DS.FixtureAdapter.reopen({createRecord:function(store,type,record){var promise=this._super(store,type,record);promise.then(function(){Em.RSVP.Promise.resolve(Ember.get(type,"relationshipNames")).then(function(relationShips){if(relationShips.belongsTo){relationShips.belongsTo.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);Ember.RSVP.resolve(belongsToRecord.get(hasManyName)).then(function(relationship){relationship.addObject(record)})}})})}if(relationShips.hasMany){relationShips.hasMany.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord&&belongsToRecord.get("length")>0){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);belongsToRecord.forEach(function(child){child.get(hasManyName).addObject(record)})}})})}})});return promise}});FactoryGuyTestMixin=Em.Mixin.create({setup:function(app){this.set("container",app.__container__);return this},useFixtureAdapter:function(app){app.ApplicationAdapter=DS.FixtureAdapter;this.getStore().adapterFor("application").simulateRemoteResponse=false},usingActiveModelSerializer:function(type){var store=this.getStore();var type=store.modelFor(type);var serializer=store.serializerFor(type.typeKey);return serializer instanceof DS.ActiveModelSerializer},find:function(type,id){return this.getStore().find(type,id)},make:function(name,opts){return this.getStore().makeFixture(name,opts)},getStore:function(){return this.get("container").lookup("store:main")},pushPayload:function(type,hash){return this.getStore().pushPayload(type,hash)},pushRecord:function(type,hash){return this.getStore().push(type,hash)},stubEndpointForHttpRequest:function(url,json,options){options=options||{};var request={url:url,dataType:"json",responseText:json,type:options.type||"GET",status:options.status||200};if(options.data){request.data=options.data}$.mockjax(request)},buildAjaxHttpResponse:function(name,opts){var fixture=FactoryGuy.build(name,opts);var modelName=FactoryGuy.lookupModelForFixtureName(name);if(this.usingActiveModelSerializer(modelName)){this.toSnakeCase(fixture)}var hash={};hash[modelName]=fixture;return hash},toSnakeCase:function(fixture){for(key in fixture){if(key!=Em.String.decamelize(key)){var value=fixture[key];delete fixture[key];fixture[Em.String.decamelize(key)]=value}}},handleFind:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var id=responseJson[modelName].id;var url="/"+Em.String.pluralize(modelName)+"/"+id;this.stubEndpointForHttpRequest(url,responseJson,{type:"GET",status:status||200});return responseJson},handleCreate:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var url="/"+Em.String.pluralize(modelName);this.stubEndpointForHttpRequest(url,responseJson,{type:"POST",status:status||200});return responseJson},handleUpdate:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"PUT",status:status||200})},handleDelete:function(root,id,status){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"DELETE",status:status||200})},teardown:function(){FactoryGuy.resetModels(this.getStore())}});
1
+ Sequence=function(fn){var index=1;this.next=function(){return fn.call(this,index++)};this.reset=function(){index=1}};function MissingSequenceError(message){this.toString=function(){return message}}ModelDefinition=function(model,config){var sequences={};var traits={};var defaultAttributes={};var namedModels={};var modelId=1;this.model=model;this.matchesName=function(name){return model==name||namedModels[name]};this.merge=function(config){};this.generate=function(name,sequenceFn){if(sequenceFn){if(!sequences[name]){sequences[name]=new Sequence(sequenceFn)}}var sequence=sequences[name];if(!sequence){throw new MissingSequenceError("Can not find that sequence named ["+sequenceName+"] in '"+model+"' definition")}return sequence.next()};this.build=function(name,opts,traitArgs){var traitsObj={};traitArgs.forEach(function(trait){$.extend(traitsObj,traits[trait])});var modelAttributes=namedModels[name]||{};var fixture=$.extend({},defaultAttributes,modelAttributes,traitsObj,opts);for(attribute in fixture){if(Ember.typeOf(fixture[attribute])=="function"){fixture[attribute]=fixture[attribute].call(this,fixture)}else if(Ember.typeOf(fixture[attribute])=="object"){fixture[attribute]=FactoryGuy.build(attribute,fixture[attribute])}}if(!fixture.id){fixture.id=modelId++}return fixture};this.buildList=function(name,number,traits,opts){var arr=[];for(var i=0;i<number;i++){arr.push(this.build(name,opts,traits))}return arr};this.reset=function(){modelId=1;for(name in sequences){sequences[name].reset()}};var parseDefault=function(object){if(!object){return}defaultAttributes=object};var parseTraits=function(object){if(!object){return}traits=object};var parseSequences=function(object){if(!object){return}for(sequenceName in object){var sequenceFn=object[sequenceName];if(Ember.typeOf(sequenceFn)!="function"){throw new Error("Problem with ["+sequenceName+"] sequence definition. Sequences must be functions")}object[sequenceName]=new Sequence(sequenceFn)}sequences=object};var parseConfig=function(config){parseSequences(config.sequences);delete config.sequences;parseTraits(config.traits);delete config.traits;parseDefault(config.default);delete config.default;namedModels=config};parseConfig(config)};FactoryGuy={modelDefinitions:{},define:function(model,config){if(this.modelDefinitions[model]){this.modelDefinitions[model].merge(config)}else{this.modelDefinitions[model]=new ModelDefinition(model,config)}},generate:function(nameOrFunction){var sortaRandomName=Math.floor((1+Math.random())*65536).toString(16)+Date.now();return function(){if(Em.typeOf(nameOrFunction)=="function"){return this.generate(sortaRandomName,nameOrFunction)}else{return this.generate(nameOrFunction)}}},belongsTo:function(fixtureName,opts){return function(){return FactoryGuy.build(fixtureName,opts)}},hasMany:function(fixtureName,number,opts){return function(){return FactoryGuy.buildList(fixtureName,number,opts)}},lookupModelForFixtureName:function(name){var definition=this.lookupDefinitionForFixtureName(name);if(definition){return definition.model}},lookupDefinitionForFixtureName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition}}},build:function(){var args=Array.prototype.slice.call(arguments);var opts={};var name=args.shift();if(!name){throw new Error("Build needs a factory name to build")}if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.build(name,opts,traits)},buildList:function(){var args=Array.prototype.slice.call(arguments);var name=args.shift();var number=args.shift();if(!name||!number){throw new Error("buildList needs a name and a number ( at least ) to build with")}var opts={};if(Ember.typeOf(args[args.length-1])=="object"){opts=args.pop()}var traits=args;var definition=this.lookupDefinitionForFixtureName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.buildList(name,number,traits,opts)},resetModels:function(store){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];definition.reset();try{var modelType=store.modelFor(definition.model);if(store.usingFixtureAdapter()){modelType.FIXTURES=[]}store.unloadAll(modelType)}catch(e){}}},pushFixture:function(modelClass,fixture){if(!modelClass["FIXTURES"]){modelClass["FIXTURES"]=[]}modelClass["FIXTURES"].push(fixture);return fixture},clear:function(opts){if(!opts){this.modelDefinitions={}}}};DS.Store.reopen({usingFixtureAdapter:function(){var adapter=this.adapterFor("application");return adapter instanceof DS.FixtureAdapter},makeFixture:function(name,options){var store=this;var modelName=FactoryGuy.lookupModelForFixtureName(name);var fixture=FactoryGuy.build(name,options);var modelType=store.modelFor(modelName);if(this.usingFixtureAdapter()){this.setAssociationsForFixtureAdapter(modelType,modelName,fixture);return FactoryGuy.pushFixture(modelType,fixture)}else{var store=this;var model;Em.run(function(){store.findEmbeddedBelongsToAssociationsForRESTAdapter(modelType,fixture);if(fixture.type){modelName=fixture.type.underscore();modelType=store.modelFor(modelName)}model=store.push(modelName,fixture);store.setAssociationsForRESTAdapter(modelType,modelName,model)});return model}},makeList:function(name,number,options){var arr=[];for(var i=0;i<number;i++){arr.push(this.makeFixture(name,options))}return arr},setAssociationsForFixtureAdapter:function(modelType,modelName,fixture){var self=this;var adapter=this.adapterFor("application");Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){if(fixture[relationship.key]){fixture[relationship.key].forEach(function(id){var hasManyfixtures=adapter.fixturesForType(relationship.type);var fixture=adapter.findFixtureById(hasManyfixtures,id);fixture[modelName]=fixture.id})}}if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(belongsToRecord){if(typeof belongsToRecord=="object"){FactoryGuy.pushFixture(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord.id}var hasManyName=self.findHasManyRelationshipNameForFixtureAdapter(relationship.type,relationship.parentType);var belongsToFixtures=adapter.fixturesForType(relationship.type);var belongsTofixture=adapter.findFixtureById(belongsToFixtures,fixture[relationship.key]);if(!belongsTofixture[hasManyName]){belongsTofixture[hasManyName]=[]}belongsTofixture[hasManyName].push(fixture.id)}}})},findEmbeddedBelongsToAssociationsForRESTAdapter:function(modelType,fixture){var store=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="belongsTo"){var belongsToRecord=fixture[relationship.key];if(Ember.typeOf(belongsToRecord)=="object"){belongsToRecord=store.push(relationship.type,belongsToRecord);fixture[relationship.key]=belongsToRecord}}if(relationship.kind=="hasMany"){var hasManyRecords=fixture[relationship.key];if(Ember.typeOf(hasManyRecords)=="array"&&Ember.typeOf(hasManyRecords[0])=="object"){var records=Em.A();hasManyRecords.forEach(function(record){var record=store.push(relationship.type,record);records.push(record)});fixture[relationship.key]=records}}})},setAssociationsForRESTAdapter:function(modelType,modelName,model){var self=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){var children=model.get(name)||[];children.forEach(function(child){var belongsToName=self.findRelationshipName("belongsTo",child.constructor,model);var hasManyName=self.findRelationshipName("hasMany",child.constructor,model);var inverseName=relationship.options&&relationship.options.inverse;if(belongsToName){child.set(belongsToName||inverseName,model)}else if(hasManyName){relation=child.get(hasManyName||inverseName)||[];relation.pushObject(model)}})}if(relationship.kind=="belongsTo"){var belongsToRecord=model.get(name);if(belongsToRecord){var setAssociations=function(){var hasManyName=self.findRelationshipName("hasMany",belongsToRecord.constructor,model);if(hasManyName){belongsToRecord.get(hasManyName).addObject(model);return}var oneToOneName=self.findRelationshipName("belongsTo",belongsToRecord.constructor,model);if(oneToOneName&&!(belongsToRecord.constructor==model.constructor)){belongsToRecord.set(oneToOneName,model)}};if(belongsToRecord.then){belongsToRecord.then(function(record){belongsToRecord=record;setAssociations()})}else{setAssociations()}}}})},findRelationshipName:function(kind,belongToModelType,childModel){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind==kind&&childModel instanceof relationship.type){relationshipName=relationship.key}});return relationshipName},findHasManyRelationshipNameForFixtureAdapter:function(belongToModelType,childModelType){var relationshipName;Ember.get(belongToModelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"&&childModelType==relationship.type){relationshipName=relationship.key}});return relationshipName},pushPayload:function(type,payload){if(this.usingFixtureAdapter()){var model=this.modelFor(modelName);FactoryGuy.pushFixture(model,payload)}else{this._super(type,payload)}}});DS.FixtureAdapter.reopen({createRecord:function(store,type,record){var promise=this._super(store,type,record);promise.then(function(){Em.RSVP.Promise.resolve(Ember.get(type,"relationshipNames")).then(function(relationShips){if(relationShips.belongsTo){relationShips.belongsTo.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);if(hasManyName){Ember.RSVP.resolve(belongsToRecord.get(hasManyName)).then(function(relationship){relationship.addObject(record)})}}})})}if(relationShips.hasMany){relationShips.hasMany.forEach(function(relationship){Em.RSVP.Promise.resolve(record.get(relationship)).then(function(belongsToRecord){if(belongsToRecord&&belongsToRecord.get("length")>0){var hasManyName=store.findRelationshipName("hasMany",belongsToRecord.constructor,record);belongsToRecord.forEach(function(child){child.get(hasManyName).addObject(record)})}})})}})});return promise}});FactoryGuyTestMixin=Em.Mixin.create({setup:function(app){this.set("container",app.__container__);return this},useFixtureAdapter:function(app){app.ApplicationAdapter=DS.FixtureAdapter;this.getStore().adapterFor("application").simulateRemoteResponse=false},usingActiveModelSerializer:function(type){var store=this.getStore();var type=store.modelFor(type);var serializer=store.serializerFor(type.typeKey);return serializer instanceof DS.ActiveModelSerializer},find:function(type,id){return this.getStore().find(type,id)},make:function(name,opts){return this.getStore().makeFixture(name,opts)},getStore:function(){return this.get("container").lookup("store:main")},pushPayload:function(type,hash){return this.getStore().pushPayload(type,hash)},pushRecord:function(type,hash){return this.getStore().push(type,hash)},stubEndpointForHttpRequest:function(url,json,options){options=options||{};var request={url:url,dataType:"json",responseText:json,type:options.type||"GET",status:options.status||200};if(options.data){request.data=options.data}$.mockjax(request)},buildAjaxHttpResponse:function(name,opts){var fixture=FactoryGuy.build(name,opts);var modelName=FactoryGuy.lookupModelForFixtureName(name);if(this.usingActiveModelSerializer(modelName)){this.toSnakeCase(fixture)}var hash={};hash[modelName]=fixture;return hash},toSnakeCase:function(fixture){for(key in fixture){if(key!=Em.String.decamelize(key)){var value=fixture[key];delete fixture[key];fixture[Em.String.decamelize(key)]=value}}},buildURL:function(type,id){return this.getStore().adapterFor("application").buildURL(type,id)},handleFind:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var id=responseJson[modelName].id;var url=this.buildURL(modelName,id);this.stubEndpointForHttpRequest(url,responseJson,{type:"GET",status:status||200});return responseJson},handleCreate:function(name,opts,status){var modelName=FactoryGuy.lookupModelForFixtureName(name);var responseJson=this.buildAjaxHttpResponse(name,opts);var url=this.buildURL(modelName);this.stubEndpointForHttpRequest(url,responseJson,{type:"POST",status:status||200});return responseJson},handleUpdate:function(type,id,status){this.stubEndpointForHttpRequest(this.buildURL(type,id),{},{type:"PUT",status:status||200})},handleDelete:function(type,id,status){this.stubEndpointForHttpRequest(this.buildURL(type,id),{},{type:"DELETE",status:status||200})},teardown:function(){FactoryGuy.resetModels(this.getStore())}});
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "ember-data-factory-guy"
4
- s.version = "0.5.1"
4
+ s.version = "0.6.0"
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Daniel Sudol", "Alex Opak"]
7
7
  s.email = ["dansudol@yahoo.com", "opak.alexandr@gmail.com"]
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-data-factory-guy",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "authors": [
5
5
  "Daniel Sudol <dansudol@yahoo.com>",
6
6
  "Opak Alex <opak.alexandr@gmail.com>"
data/src/factory_guy.js CHANGED
@@ -90,23 +90,70 @@ FactoryGuy = {
90
90
  default: {
91
91
  title: 'Project'
92
92
  },
93
+
94
+ // setup named project with built in associated user
93
95
  project_with_admin: {
94
- // for named association, use this FactoryGuy.association helper method
95
- user: FactoryGuy.association('admin')
96
+ user: FactoryGuy.belongsTo('admin')
96
97
  }
97
98
 
99
+ // or use as a trait
100
+ traits: {
101
+ with_admin: {
102
+ user: FactoryGuy.belongsTo('admin')
103
+ }
104
+ }
105
+ })
98
106
  ```
99
107
 
100
108
  @param {String} fixtureName fixture name
101
109
  @param {Object} opts options
102
110
  @returns {Function} wrapper function that will build the association json
103
111
  */
104
- association: function (fixtureName, opts) {
112
+ belongsTo: function (fixtureName, opts) {
105
113
  return function () {
106
114
  return FactoryGuy.build(fixtureName, opts);
107
115
  }
108
116
  },
109
117
 
118
+ association: function(fixtureName, opts) {
119
+ console.log('DEPRECATION Warning: use FactoryGuy.belongsTo instead')
120
+ return this.belongsTo(fixtureName, opts);
121
+ },
122
+
123
+ /**
124
+ Used in model definitions to define a hasMany association attribute.
125
+ For example:
126
+
127
+ ```
128
+ FactoryGuy.define('user', {
129
+ default: {
130
+ name: 'Bob'
131
+ },
132
+
133
+ // define the named user type that will have projects
134
+ user_with_projects: { FactoryGuy.hasMany('project', 2) }
135
+
136
+ // or use as a trait
137
+ traits: {
138
+ with_projects: {
139
+ projects: FactoryGuy.hasMany('project', 2)
140
+ }
141
+ }
142
+ })
143
+
144
+ ```
145
+
146
+ @param {String} fixtureName fixture name
147
+ @param {Number} number of hasMany association items to build
148
+ @param {Object} opts options
149
+ @returns {Function} wrapper function that will build the association json
150
+ */
151
+ hasMany: function (fixtureName, number, opts) {
152
+ return function () {
153
+ return FactoryGuy.buildList(fixtureName, number, opts);
154
+ }
155
+ },
156
+
110
157
  /**
111
158
  Given a fixture name like 'person' or 'dude' determine what model this name
112
159
  refers to. In this case it's 'person' for each one.
@@ -112,6 +112,17 @@ FactoryGuyTestMixin = Em.Mixin.create({
112
112
  }
113
113
  },
114
114
 
115
+ /**
116
+ Build url for the mockjax call. Proxy to the adapters buildURL method.
117
+
118
+ @param {String} type model type name like 'user' for User model
119
+ @param {String} id
120
+ @return {String} url
121
+ */
122
+ buildURL: function (type, id) {
123
+ return this.getStore().adapterFor('application').buildURL(type, id);
124
+ },
125
+
115
126
  /**
116
127
  Handling ajax GET ( find record ) for a model. You can mock
117
128
  failed find by passing in status of 500.
@@ -124,7 +135,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
124
135
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
125
136
  var responseJson = this.buildAjaxHttpResponse(name, opts);
126
137
  var id = responseJson[modelName].id
127
- var url = "/" + Em.String.pluralize(modelName) + "/" + id;
138
+ var url = this.buildURL(modelName, id);
128
139
  this.stubEndpointForHttpRequest(
129
140
  url,
130
141
  responseJson,
@@ -144,7 +155,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
144
155
  handleCreate: function (name, opts, status) {
145
156
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
146
157
  var responseJson = this.buildAjaxHttpResponse(name, opts);
147
- var url = "/" + Em.String.pluralize(modelName);
158
+ var url = this.buildURL(modelName);
148
159
  this.stubEndpointForHttpRequest(
149
160
  url,
150
161
  responseJson,
@@ -157,13 +168,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
157
168
  Handling ajax PUT ( update record ) for a model type. You can mock
158
169
  failed update by passing in status of 500.
159
170
 
160
- @param {String} root modelType like 'user' for User
171
+ @param {String} type model type like 'user' for User model
161
172
  @param {String} id id of record to update
162
173
  @param {Integer} status Optional HTTP status response code
163
174
  */
164
- handleUpdate: function (root, id, status) {
175
+ handleUpdate: function (type, id, status) {
165
176
  this.stubEndpointForHttpRequest(
166
- "/" + Em.String.pluralize(root) + "/" + id,
177
+ this.buildURL(type, id),
167
178
  {},
168
179
  {type: 'PUT', status: (status || 200)}
169
180
  )
@@ -173,13 +184,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
173
184
  Handling ajax DELETE ( delete record ) for a model type. You can mock
174
185
  failed delete by passing in status of 500.
175
186
 
176
- @param {String} root modelType like 'user' for User
187
+ @param {String} type model type like 'user' for User model
177
188
  @param {String} id id of record to update
178
189
  @param {Integer} status Optional HTTP status response code
179
190
  */
180
- handleDelete: function (root, id, status) {
191
+ handleDelete: function (type, id, status) {
181
192
  this.stubEndpointForHttpRequest(
182
- "/" + Em.String.pluralize(root) + "/" + id,
193
+ this.buildURL(type, id),
183
194
  {},
184
195
  {type: 'DELETE', status: (status || 200)}
185
196
  )
@@ -54,7 +54,7 @@ ModelDefinition = function (model, config) {
54
54
 
55
55
  @param {String} name fixture name
56
56
  @param {Object} opts attributes to override
57
- @param {String} traits array of traits
57
+ @param {String} traitArgs array of traits
58
58
  @returns {Object} json
59
59
  */
60
60
  this.build = function (name, opts, traitArgs) {
data/src/store.js CHANGED
@@ -125,9 +125,6 @@ DS.Store.reopen({
125
125
  then push that model to the store and set the id of that new model
126
126
  as the attribute value in the fixture
127
127
 
128
- If it's a hasMany association, and its polymorphic, then convert the
129
- attribute value to a polymorphic style
130
-
131
128
  @param modelType
132
129
  @param fixture
133
130
  */
@@ -141,6 +138,19 @@ DS.Store.reopen({
141
138
  fixture[relationship.key] = belongsToRecord;
142
139
  }
143
140
  }
141
+ if (relationship.kind == 'hasMany') {
142
+ var hasManyRecords = fixture[relationship.key];
143
+ // if the records are objects and not instances they need to be converted to
144
+ // instances
145
+ if (Ember.typeOf(hasManyRecords) == 'array' && Ember.typeOf(hasManyRecords[0]) == 'object') {
146
+ var records = Em.A()
147
+ hasManyRecords.forEach(function(record) {
148
+ var record = store.push(relationship.type, record);
149
+ records.push(record);
150
+ })
151
+ fixture[relationship.key] = records;
152
+ }
153
+ }
144
154
  })
145
155
  },
146
156
 
@@ -88,15 +88,28 @@ test("Referring to other attributes in attribute definition", function() {
88
88
  });
89
89
 
90
90
 
91
- test("Using associations in attribute definition", function() {
91
+ test("Using belongsTo associations in attribute definition", function() {
92
92
  var json = FactoryGuy.build('project_with_user');
93
- deepEqual(json, {id: 1, title: 'Project1', user: {id: 1, name: 'User1'}}, 'creates default user for "user" belongsTo attribute');
93
+ deepEqual(json, {id: 1, title: 'Project1', user: {id: 1, name: 'User1'}}, 'creates default association');
94
94
 
95
95
  var json = FactoryGuy.build('project_with_dude');
96
- deepEqual(json, {id: 2, title: 'Project2', user: {id: 2, name: 'Dude'}}, 'creates user with optional attributes for "user" belongsTo attribute');
96
+ deepEqual(json, {id: 2, title: 'Project2', user: {id: 2, name: 'Dude'}}, 'creates association with optional attributes');
97
97
 
98
98
  var json = FactoryGuy.build('project_with_admin');
99
- deepEqual(json, {id: 3, title: 'Project3', user: {id: 3, name: 'Admin'}}, 'creates named user for "user" belongsTo attribute');
99
+ deepEqual(json, {id: 3, title: 'Project3', user: {id: 3, name: 'Admin'}}, 'creates association using named attribute');
100
+
101
+ var json = FactoryGuy.build('project_with_parent');
102
+ deepEqual(json, {id: 5, title: 'Project4', parent: {id: 4, title: 'Project5'}}, 'belongsTo association name differs from model name');
103
+ });
104
+
105
+
106
+ test("Using hasMany associations in attribute definition", function() {
107
+ var json = FactoryGuy.build('user_with_projects');
108
+ deepEqual(json, {
109
+ id: 1,
110
+ name: 'User1',
111
+ projects: [{id: 1, title: 'Project1'},{id: 2, title: 'Project2'}]
112
+ }, 'creates list of hasMany association items');
100
113
  });
101
114
 
102
115
 
@@ -121,6 +134,13 @@ test("#build with traits", function() {
121
134
 
122
135
  var json = FactoryGuy.build('project', 'with_title_sequence');
123
136
  deepEqual(json, {id: 7, title: 'Project3'}, 'trait with attribute using sequence');
137
+
138
+ var json = FactoryGuy.build('user', 'with_projects');
139
+ deepEqual(json, {
140
+ id: 6,
141
+ name: 'User1',
142
+ projects: [{id: 8, title: 'Project4'},{id: 9, title: 'Project5'}]
143
+ }, 'trait with hasMany association');
124
144
  });
125
145
 
126
146
 
@@ -0,0 +1,32 @@
1
+ var testHelper, store;
2
+
3
+ module('FactoryGuyTestMixin with DS.RESTAdapter', {
4
+ setup: function () {
5
+ testHelper = TestHelper.setup(DS.RESTAdapter);
6
+ store = testHelper.getStore();
7
+ },
8
+ teardown: function () {
9
+ DS.RESTAdapter.reopen({
10
+ namespace: '',
11
+ host: ''
12
+ })
13
+ Em.run(function () {
14
+ testHelper.teardown();
15
+ });
16
+ }
17
+ });
18
+
19
+
20
+ test("#buildURL without namespace", function () {
21
+ equal(testHelper.buildURL('project'), '/projects', 'has no namespace by default');
22
+ })
23
+
24
+ test("#buildURL with namespace and host", function () {
25
+ DS.RESTAdapter.reopen({
26
+ host: 'https://dude.com',
27
+ namespace: 'api/v1'
28
+ })
29
+
30
+ equal(testHelper.buildURL('project'), 'https://dude.com/api/v1/projects');
31
+ })
32
+
@@ -1,17 +1,19 @@
1
1
  var testHelper, store;
2
2
 
3
3
  module('FactoryGuy with DS.FixtureAdapter', {
4
- setup: function() {
4
+ setup: function () {
5
5
  testHelper = TestHelper.setup(DS.FixtureAdapter);
6
6
  store = testHelper.getStore();
7
7
  },
8
- teardown: function() {
9
- Em.run(function() { testHelper.teardown(); });
8
+ teardown: function () {
9
+ Em.run(function () {
10
+ testHelper.teardown();
11
+ });
10
12
  }
11
13
  });
12
14
 
13
15
 
14
- test("#pushFixture adds fixture to Fixture array on model", function() {
16
+ test("#pushFixture adds fixture to Fixture array on model", function () {
15
17
  var fixtureJson = FactoryGuy.build('user');
16
18
  FactoryGuy.pushFixture(User, fixtureJson);
17
19
  equal(User.FIXTURES.length, 1);
@@ -22,18 +24,18 @@ test("#pushFixture adds fixture to Fixture array on model", function() {
22
24
  });
23
25
 
24
26
 
25
- asyncTest("can change fixture attributes after creation", function() {
27
+ asyncTest("can change fixture attributes after creation", function () {
26
28
  var user = store.makeFixture('user');
27
29
  user.name = "new name";
28
30
 
29
- store.find('user', 1).then( function(user) {
31
+ store.find('user', 1).then(function (user) {
30
32
  equal(user.get('name'), "new name", "changes local attributes");
31
33
  start();
32
34
  });
33
35
  });
34
36
 
35
37
 
36
- test("#resetModels clears the store of models, clears the FIXTURES arrays for each model and resets the model definition", function() {
38
+ test("#resetModels clears the store of models, clears the FIXTURES arrays for each model and resets the model definition", function () {
37
39
  var project = store.makeFixture('project');
38
40
  var user = store.makeFixture('user', {projects: [project.id]});
39
41
 
@@ -59,32 +61,34 @@ test("#resetModels clears the store of models, clears the FIXTURES arrays for ea
59
61
 
60
62
 
61
63
  module('DS.Store with DS.FixtureAdapter', {
62
- setup: function() {
64
+ setup: function () {
63
65
  testHelper = TestHelper.setup(DS.FixtureAdapter);
64
66
  store = testHelper.getStore();
65
67
  },
66
- teardown: function() {
67
- Em.run(function() { testHelper.teardown(); });
68
+ teardown: function () {
69
+ Em.run(function () {
70
+ testHelper.teardown();
71
+ });
68
72
  }
69
73
  });
70
74
 
71
75
 
72
- test("#makeFixture builds and pushes fixture into the models FIXTURE array", function() {
76
+ test("#makeFixture builds and pushes fixture into the models FIXTURE array", function () {
73
77
  var json = store.makeFixture('user');
74
78
  equal(User.FIXTURES.length, 1);
75
79
  equal(User.FIXTURES[0], json);
76
80
  });
77
81
 
78
82
 
79
- asyncTest("#makeFixture sets belongsTo on hasMany associations", function() {
83
+ asyncTest("#makeFixture sets belongsTo on hasMany associations", function () {
80
84
  var p1 = store.makeFixture('project');
81
85
  // second project not added on purpose to make sure only one is
82
86
  // assigned in hasMany
83
87
  store.makeFixture('project');
84
88
  var user = store.makeFixture('user', {projects: [p1.id]})
85
89
 
86
- store.find('user', 1).then( function(user) {
87
- user.get('projects').then( function(projects) {
90
+ store.find('user', 1).then(function (user) {
91
+ user.get('projects').then(function (projects) {
88
92
  equal(projects.get('length'), 1, "adds hasMany records");
89
93
  equal(projects.get('firstObject.user.id'), user.id, "sets belongsTo record");
90
94
  start();
@@ -93,12 +97,12 @@ asyncTest("#makeFixture sets belongsTo on hasMany associations", function() {
93
97
  })
94
98
 
95
99
 
96
- asyncTest("#makeFixture adds record to hasMany association array for which it belongsTo", function() {
100
+ asyncTest("#makeFixture adds record to hasMany association array for which it belongsTo", function () {
97
101
  var userJson = store.makeFixture('user');
98
102
  var projectJson = store.makeFixture('project', {user: userJson.id});
99
103
 
100
- store.find('user', userJson.id).then( function(user) {
101
- user.get('projects').then( function(projects) {
104
+ store.find('user', userJson.id).then(function (user) {
105
+ user.get('projects').then(function (projects) {
102
106
  equal(projects.get('length'), 1, "adds hasMany records");
103
107
  equal(projects.get('firstObject.user.id'), user.id, "sets belongsTo record");
104
108
  start();
@@ -106,12 +110,12 @@ asyncTest("#makeFixture adds record to hasMany association array for which it be
106
110
  })
107
111
  })
108
112
 
109
- asyncTest("#makeFixture handles default belongsTo associations in fixture", function() {
113
+ asyncTest("#makeFixture handles default belongsTo associations in fixture", function () {
110
114
  var projectWithUser = store.makeFixture('project_with_user');
111
115
  equal(User.FIXTURES.length, 1);
112
116
 
113
- store.find('user', 1).then( function(user) {
114
- user.get('projects').then( function(projects) {
117
+ store.find('user', 1).then(function (user) {
118
+ user.get('projects').then(function (projects) {
115
119
  equal(projects.get('length'), 1, "adds hasMany records");
116
120
  equal(projects.get('firstObject.user.id'), 1, "sets belongsTo record");
117
121
  start();
@@ -130,17 +134,17 @@ asyncTest("#makeFixture handles default belongsTo associations in fixture", func
130
134
  })
131
135
 
132
136
 
133
- asyncTest("#createRecord adds belongsTo association to records it hasMany of", function() {
137
+ asyncTest("#createRecord adds belongsTo association to records it hasMany of", function () {
134
138
  var user = store.makeFixture('user');
135
139
 
136
- store.find('user', user.id).then(function(user) {
140
+ store.find('user', user.id).then(function (user) {
137
141
 
138
- var projectJson = {title:'project', user: user};
142
+ var projectJson = {title: 'project', user: user};
139
143
 
140
144
  store.createRecord('project', projectJson).save()
141
- .then( function(project) {
145
+ .then(function (project) {
142
146
  return Ember.RSVP.all([project.get('user'), user.get('projects')]);
143
- }).then( function(promises) {
147
+ }).then(function (promises) {
144
148
  var projectUser = promises[0], projects = promises[1];
145
149
  equal(projectUser.get('id'), user.get('id'));
146
150
  equal(projects.get('length'), 1);
@@ -149,36 +153,36 @@ asyncTest("#createRecord adds belongsTo association to records it hasMany of", f
149
153
  })
150
154
  })
151
155
 
152
- asyncTest("#createRecord can work for one-to-none associations", function() {
156
+ asyncTest("#createRecord can work for one-to-none associations", function () {
153
157
  var user = store.makeFixture('user');
154
158
 
155
- store.find('user', user.id).then(function(user) {
159
+ store.find('user', user.id).then(function (user) {
156
160
 
157
- var smallCompanyJson = {name:'small company', owner: user};
161
+ var smallCompanyJson = {name: 'small company', owner: user};
158
162
 
159
163
  store.createRecord('small_company', smallCompanyJson).save()
160
- .then( function(smallCompany) {
164
+ .then(function (smallCompany) {
161
165
  return smallCompany.get('owner');
162
- }).then( function(owner) {
166
+ }).then(function (owner) {
163
167
  equal(owner.get('id'), user.get('id'));
164
168
  start();
165
169
  });
166
170
  })
167
171
  })
168
172
 
169
- asyncTest("#createRecord adds hasMany association to records it hasMany of ", function() {
173
+ asyncTest("#createRecord adds hasMany association to records it hasMany of ", function () {
170
174
  var usersJson = store.makeList('user', 3);
171
175
 
172
- Em.RSVP.all([store.find('user', usersJson[0].id),store.find('user', usersJson[1].id),store.find('user', usersJson[2].id)]).then(function(users) {
176
+ Em.RSVP.all([store.find('user', usersJson[0].id), store.find('user', usersJson[1].id), store.find('user', usersJson[2].id)]).then(function (users) {
173
177
 
174
- var propertyJson = {name:'beach front property'};
178
+ var propertyJson = {name: 'beach front property'};
175
179
 
176
180
  property = store.createRecord('property', propertyJson);
177
- property.get('owners').then(function(owners){
181
+ property.get('owners').then(function (owners) {
178
182
  owners.addObjects(users);
179
- }).then( function() {
183
+ }).then(function () {
180
184
  return property.get('owners');
181
- }).then( function(users) {
185
+ }).then(function (users) {
182
186
  equal(users.get('length'), usersJson.length);
183
187
  start();
184
188
  });
data/tests/index.html CHANGED
@@ -30,6 +30,7 @@
30
30
  <script src='rest_adapter_factory_test.js'></script>
31
31
  <script src='store_test.js'></script>
32
32
  <script src='factory_guy_test.js'></script>
33
+ <script src='factory_guy_test_mixin_test.js'></script>
33
34
  <div id='qunit-fixture'>
34
35
 
35
36
  <!-- any HTML you want to be present in each test (will be reset for each test) -->
@@ -195,6 +195,21 @@ test("belongsTo associations defined as attributes in fixture", function() {
195
195
  });
196
196
 
197
197
 
198
+ test("hasMany associations defined as attributes in fixture", function() {
199
+ var user = store.makeFixture('user_with_projects');
200
+ equal(user.get('projects.length'), 2)
201
+ equal(user.get('projects.firstObject.user'), user)
202
+ equal(user.get('projects.lastObject.user'), user)
203
+ })
204
+
205
+ test("hasMany associations defined with traits", function() {
206
+ var user = store.makeFixture('user', 'with_projects');
207
+ equal(user.get('projects.length'), 2)
208
+ equal(user.get('projects.firstObject.user'), user)
209
+ equal(user.get('projects.lastObject.user'), user)
210
+ })
211
+
212
+
198
213
  module('DS.Store#makeList with DS.RESTAdapter', {
199
214
  setup: function() {
200
215
  testHelper = TestHelper.setup(DS.RESTAdapter);
@@ -1,4 +1,4 @@
1
- FactoryGuy.define('company', {
1
+ FactoryGuy.define("company", {
2
2
  default: {
3
3
  name: 'Silly corp'
4
4
  }
@@ -1,4 +1,4 @@
1
- FactoryGuy.define('project', {
1
+ FactoryGuy.define("project", {
2
2
  sequences: {
3
3
  title: function(num) {return 'Project' + num}
4
4
  },
@@ -7,7 +7,7 @@ FactoryGuy.define('project', {
7
7
  with_title_sequence: { title: FactoryGuy.generate('title') },
8
8
  with_user: { user: {} },
9
9
  with_dude: { user: {name: 'Dude'} },
10
- with_admin: { user: FactoryGuy.association('admin') }
10
+ with_admin: { user: FactoryGuy.belongsTo('admin') }
11
11
  },
12
12
  default: {
13
13
  title: FactoryGuy.generate('title')
@@ -22,6 +22,11 @@ FactoryGuy.define('project', {
22
22
  },
23
23
  project_with_admin: {
24
24
  // for named association, use this FactoryGuy.association helper method
25
- user: FactoryGuy.association('admin')
25
+ user: FactoryGuy.belongsTo('admin')
26
+ },
27
+ project_with_parent: {
28
+ // refer to belongsTo association where the name of the association
29
+ // differs from the model name
30
+ parent: FactoryGuy.belongsTo('project')
26
31
  }
27
32
  });
@@ -6,5 +6,13 @@ FactoryGuy.define('user', {
6
6
  // named 'user' type with custom attributes
7
7
  admin: {
8
8
  name: 'Admin'
9
+ },
10
+ user_with_projects: {
11
+ projects: FactoryGuy.hasMany('project', 2)
12
+ },
13
+ traits: {
14
+ with_projects: {
15
+ projects: FactoryGuy.hasMany('project', 2)
16
+ }
9
17
  }
10
18
  });
data/tests/test_setup.js CHANGED
@@ -1,4 +1,4 @@
1
- FactoryGuy.define('company', {
1
+ FactoryGuy.define("company", {
2
2
  default: {
3
3
  name: 'Silly corp'
4
4
  }
@@ -25,7 +25,7 @@ FactoryGuy.define('profile', {
25
25
  description: 'Text goes here'
26
26
  }
27
27
  })
28
- FactoryGuy.define('project', {
28
+ FactoryGuy.define("project", {
29
29
  sequences: {
30
30
  title: function(num) {return 'Project' + num}
31
31
  },
@@ -34,7 +34,7 @@ FactoryGuy.define('project', {
34
34
  with_title_sequence: { title: FactoryGuy.generate('title') },
35
35
  with_user: { user: {} },
36
36
  with_dude: { user: {name: 'Dude'} },
37
- with_admin: { user: FactoryGuy.association('admin') }
37
+ with_admin: { user: FactoryGuy.belongsTo('admin') }
38
38
  },
39
39
  default: {
40
40
  title: FactoryGuy.generate('title')
@@ -49,7 +49,12 @@ FactoryGuy.define('project', {
49
49
  },
50
50
  project_with_admin: {
51
51
  // for named association, use this FactoryGuy.association helper method
52
- user: FactoryGuy.association('admin')
52
+ user: FactoryGuy.belongsTo('admin')
53
+ },
54
+ project_with_parent: {
55
+ // refer to belongsTo association where the name of the association
56
+ // differs from the model name
57
+ parent: FactoryGuy.belongsTo('project')
53
58
  }
54
59
  });
55
60
  FactoryGuy.define('property', {
@@ -65,6 +70,14 @@ FactoryGuy.define('user', {
65
70
  // named 'user' type with custom attributes
66
71
  admin: {
67
72
  name: 'Admin'
73
+ },
74
+ user_with_projects: {
75
+ projects: FactoryGuy.hasMany('project', 2)
76
+ },
77
+ traits: {
78
+ with_projects: {
79
+ projects: FactoryGuy.hasMany('project', 2)
80
+ }
68
81
  }
69
82
  });
70
83
  Company = DS.Model.extend({
@@ -112,16 +125,16 @@ Project = DS.Model.extend({
112
125
  });
113
126
 
114
127
  Property = DS.Model.extend({
115
- name: DS.attr('string'),
116
- company: DS.belongsTo('company', {async: true}),
128
+ name: DS.attr('string'),
129
+ company: DS.belongsTo('company', {async: true}),
117
130
  owners: DS.hasMany('user', {async: true, inverse: 'properties'})
118
131
  });
119
132
  User = DS.Model.extend({
120
- name: DS.attr('string'),
121
- company: DS.belongsTo('company', {async: true, inverse: 'users'}),
122
- properties: DS.hasMany('property', {async: true, inverse: 'owners'}),
133
+ name: DS.attr('string'),
134
+ company: DS.belongsTo('company', {async: true, inverse: 'users'}),
135
+ properties: DS.hasMany('property', {async: true, inverse: 'owners'}),
123
136
  projects: DS.hasMany('project'),
124
- hats: DS.hasMany('hat', {polymorphic: true})
137
+ hats: DS.hasMany('hat', {polymorphic: true})
125
138
  });
126
139
 
127
140
 
@@ -70,7 +70,7 @@ ModelDefinition = function (model, config) {
70
70
 
71
71
  @param {String} name fixture name
72
72
  @param {Object} opts attributes to override
73
- @param {String} traits array of traits
73
+ @param {String} traitArgs array of traits
74
74
  @returns {Object} json
75
75
  */
76
76
  this.build = function (name, opts, traitArgs) {
@@ -135,11 +135,6 @@ ModelDefinition = function (model, config) {
135
135
  if (!object) {
136
136
  return
137
137
  }
138
- // for (trait in object) {
139
- // var trait = object[trait];
140
- // if (Ember.typeOf(trait) == 'function') {}
141
- // object[trait] = new Trait(trait);
142
- // }
143
138
  traits = object;
144
139
  }
145
140
 
@@ -265,23 +260,65 @@ FactoryGuy = {
265
260
  default: {
266
261
  title: 'Project'
267
262
  },
263
+
264
+ // setup named project with built in associated user
268
265
  project_with_admin: {
269
- // for named association, use this FactoryGuy.association helper method
270
- user: FactoryGuy.association('admin')
266
+ user: FactoryGuy.belongsTo('admin')
271
267
  }
272
268
 
269
+ // or use as a trait
270
+ traits: {
271
+ with_admin: {
272
+ user: FactoryGuy.belongsTo('admin')
273
+ }
274
+ }
275
+ })
273
276
  ```
274
277
 
275
278
  @param {String} fixtureName fixture name
276
279
  @param {Object} opts options
277
280
  @returns {Function} wrapper function that will build the association json
278
281
  */
279
- association: function (fixtureName, opts) {
282
+ belongsTo: function (fixtureName, opts) {
280
283
  return function () {
281
284
  return FactoryGuy.build(fixtureName, opts);
282
285
  }
283
286
  },
284
287
 
288
+ /**
289
+ Used in model definitions to define a hasMany association attribute.
290
+ For example:
291
+
292
+ ```
293
+ FactoryGuy.define('user', {
294
+ default: {
295
+ name: 'Bob'
296
+ },
297
+
298
+ // define the named user type that will have projects
299
+ user_with_projects: { FactoryGuy.hasMany('project', 2) }
300
+
301
+ // or use as a trait
302
+ traits: {
303
+ with_projects: {
304
+ projects: FactoryGuy.hasMany('project', 2)
305
+ }
306
+ }
307
+ })
308
+
309
+ ```
310
+
311
+ @param {String} fixtureName fixture name
312
+ @param {Number} number of hasMany association items to build
313
+ @param {Object} opts options
314
+ @returns {Function} wrapper function that will build the association json
315
+ */
316
+ hasMany: function (fixtureName, number, opts) {
317
+ return function () {
318
+ return FactoryGuy.buildList(fixtureName, number, opts);
319
+ }
320
+ },
321
+
285
322
  /**
286
323
  Given a fixture name like 'person' or 'dude' determine what model this name
287
324
  refers to. In this case it's 'person' for each one.
@@ -548,9 +585,6 @@ DS.Store.reopen({
548
585
  then push that model to the store and set the id of that new model
549
586
  as the attribute value in the fixture
550
587
 
551
- If it's a hasMany association, and its polymorphic, then convert the
552
- attribute value to a polymorphic style
553
-
554
588
  @param modelType
555
589
  @param fixture
556
590
  */
@@ -564,6 +598,19 @@ DS.Store.reopen({
564
598
  fixture[relationship.key] = belongsToRecord;
565
599
  }
566
600
  }
601
+ if (relationship.kind == 'hasMany') {
602
+ var hasManyRecords = fixture[relationship.key];
603
+ // if the records are objects and not instances they need to be converted to
604
+ // instances
605
+ if (Ember.typeOf(hasManyRecords) == 'array' && Ember.typeOf(hasManyRecords[0]) == 'object') {
606
+ var records = Em.A()
607
+ hasManyRecords.forEach(function(record) {
608
+ var record = store.push(relationship.type, record);
609
+ records.push(record);
610
+ })
611
+ fixture[relationship.key] = records;
612
+ }
613
+ }
567
614
  })
568
615
  },
569
616
 
@@ -900,6 +947,17 @@ FactoryGuyTestMixin = Em.Mixin.create({
900
947
  }
901
948
  },
902
949
 
950
+ /**
951
+ Build url for the mockjax call. Proxy to the adapters buildURL method.
952
+
953
+ @param {String} type model type name like 'user' for User model
954
+ @param {String} id
955
+ @return {String} url
956
+ */
957
+ buildURL: function (type, id) {
958
+ return this.getStore().adapterFor('application').buildURL(type, id);
959
+ },
960
+
903
961
  /**
904
962
  Handling ajax GET ( find record ) for a model. You can mock
905
963
  failed find by passing in status of 500.
@@ -912,7 +970,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
912
970
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
913
971
  var responseJson = this.buildAjaxHttpResponse(name, opts);
914
972
  var id = responseJson[modelName].id
915
- var url = "/" + Em.String.pluralize(modelName) + "/" + id;
973
+ var url = this.buildURL(modelName, id);
916
974
  this.stubEndpointForHttpRequest(
917
975
  url,
918
976
  responseJson,
@@ -932,7 +990,7 @@ FactoryGuyTestMixin = Em.Mixin.create({
932
990
  handleCreate: function (name, opts, status) {
933
991
  var modelName = FactoryGuy.lookupModelForFixtureName(name);
934
992
  var responseJson = this.buildAjaxHttpResponse(name, opts);
935
- var url = "/" + Em.String.pluralize(modelName);
993
+ var url = this.buildURL(modelName);
936
994
  this.stubEndpointForHttpRequest(
937
995
  url,
938
996
  responseJson,
@@ -945,13 +1003,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
945
1003
  Handling ajax PUT ( update record ) for a model type. You can mock
946
1004
  failed update by passing in status of 500.
947
1005
 
948
- @param {String} root modelType like 'user' for User
1006
+ @param {String} type model type like 'user' for User model
949
1007
  @param {String} id id of record to update
950
1008
  @param {Integer} status Optional HTTP status response code
951
1009
  */
952
- handleUpdate: function (root, id, status) {
1010
+ handleUpdate: function (type, id, status) {
953
1011
  this.stubEndpointForHttpRequest(
954
- "/" + Em.String.pluralize(root) + "/" + id,
1012
+ this.buildURL(type, id),
955
1013
  {},
956
1014
  {type: 'PUT', status: (status || 200)}
957
1015
  )
@@ -961,13 +1019,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
961
1019
  Handling ajax DELETE ( delete record ) for a model type. You can mock
962
1020
  failed delete by passing in status of 500.
963
1021
 
964
- @param {String} root modelType like 'user' for User
1022
+ @param {String} type model type like 'user' for User model
965
1023
  @param {String} id id of record to update
966
1024
  @param {Integer} status Optional HTTP status response code
967
1025
  */
968
- handleDelete: function (root, id, status) {
1026
+ handleDelete: function (type, id, status) {
969
1027
  this.stubEndpointForHttpRequest(
970
- "/" + Em.String.pluralize(root) + "/" + id,
1028
+ this.buildURL(type, id),
971
1029
  {},
972
1030
  {type: 'DELETE', status: (status || 200)}
973
1031
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ember-data-factory-guy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Sudol
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-01 00:00:00.000000000 Z
12
+ date: 2014-08-21 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Easily create Fixtures for Ember Data
15
15
  email:
@@ -22,6 +22,7 @@ files:
22
22
  - .gitignore
23
23
  - .travis.yml
24
24
  - Gruntfile.js
25
+ - LICENSE
25
26
  - README.md
26
27
  - bower.json
27
28
  - dist/ember-data-factory-guy.js
@@ -38,6 +39,7 @@ files:
38
39
  - src/store.js
39
40
  - tests/active_model_adapter_factory_test.js
40
41
  - tests/factory_guy_test.js
42
+ - tests/factory_guy_test_mixin_test.js
41
43
  - tests/fixture_adapter_factory_test.js
42
44
  - tests/index.html
43
45
  - tests/rest_adapter_factory_test.js