ember-data-factory-guy 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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