ember-data-factory-guy 0.1
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.
- data/.gitignore +2 -0
- data/Gruntfile.js +45 -0
- data/README.md +118 -0
- data/bower.json +35 -0
- data/dist/ember-data-factory-guy.js +376 -0
- data/dist/ember-data-factory-guy.min.js +1 -0
- data/ember-data-factory-guy.gemspec +20 -0
- data/lib/ember-data-factory-guy.rb +13 -0
- data/package.json +41 -0
- data/src/factory_guy.js +144 -0
- data/src/factory_guy_helper_mixin.js +89 -0
- data/src/has_many.js +188 -0
- data/src/store.js +142 -0
- data/tests/active_model_adapter_factory_test.js +63 -0
- data/tests/factory_guy_test.js +0 -0
- data/tests/fixture_adapter_factory_test.js +134 -0
- data/tests/index.html +38 -0
- data/tests/rest_adapter_factory_test.js +61 -0
- data/tests/store_test.js +35 -0
- data/tests/support/factories/project_factory.js +3 -0
- data/tests/support/factories/user_factory.js +10 -0
- data/tests/support/models/project.js +4 -0
- data/tests/support/models/user.js +4 -0
- data/tests/support/test_helper.js +23 -0
- data/tests/test_setup.js +22 -0
- data/vendor/assets/javascripts/ember_data_factory_guy.js +376 -0
- data/vendor/assets/javascripts/factory_guy_has_many.js +188 -0
- metadata +76 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
TestHelper = Ember.Object.createWithMixins(FactoryGuyHelperMixin,{
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Setup with type of adapter
|
5
|
+
*
|
6
|
+
* @param adapter DS.FixtureAdapter or DS.ActiveModelSerializer or whatever
|
7
|
+
*/
|
8
|
+
setup: function(adapter) {
|
9
|
+
var container = new Ember.Container();
|
10
|
+
this.set('container', container);
|
11
|
+
|
12
|
+
container.register("model:user", User);
|
13
|
+
container.register("model:project", Project);
|
14
|
+
container.register("store:main", DS.Store.extend({adapter: adapter}));
|
15
|
+
container.register("serializer:-default", DS.RESTSerializer);
|
16
|
+
container.register('transform:string', DS.StringTransform);
|
17
|
+
|
18
|
+
if (adapter instanceof DS.FixtureAdapter) {
|
19
|
+
adapter.simulateRemoteResponse = false;
|
20
|
+
}
|
21
|
+
return this;
|
22
|
+
}
|
23
|
+
});
|
data/tests/test_setup.js
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
FactoryGuy.define('project', {
|
2
|
+
default: {title: 'Project'}
|
3
|
+
});
|
4
|
+
FactoryGuy.define('user', {
|
5
|
+
// default values for 'user' attributes
|
6
|
+
default: {
|
7
|
+
name: 'User1'
|
8
|
+
},
|
9
|
+
// named 'user' type with custom attributes
|
10
|
+
admin: {
|
11
|
+
name: 'Admin'
|
12
|
+
}
|
13
|
+
});
|
14
|
+
Project = DS.Model.extend({
|
15
|
+
title: DS.attr('string'),
|
16
|
+
user: DS.belongsTo('user')
|
17
|
+
})
|
18
|
+
|
19
|
+
User = DS.Model.extend({
|
20
|
+
name: DS.attr('string'),
|
21
|
+
projects: DS.hasMany('project')
|
22
|
+
})
|
@@ -0,0 +1,376 @@
|
|
1
|
+
FactoryGuy = Ember.Object.reopenClass({
|
2
|
+
fixtureStore: {},
|
3
|
+
fixtureLookup: {},
|
4
|
+
modelIds: {},
|
5
|
+
|
6
|
+
/**
|
7
|
+
```javascript
|
8
|
+
|
9
|
+
User = DS.Model.extend({
|
10
|
+
name: DS.attr('string'),
|
11
|
+
})
|
12
|
+
|
13
|
+
FactoryGuy.define('user', {
|
14
|
+
default: {
|
15
|
+
name: "Fred"
|
16
|
+
},
|
17
|
+
|
18
|
+
bob: {
|
19
|
+
name: "Bob"
|
20
|
+
}
|
21
|
+
});
|
22
|
+
|
23
|
+
```
|
24
|
+
|
25
|
+
For the User model, you can define fixtures like 'bob' or just use 'user'
|
26
|
+
and get default values.
|
27
|
+
|
28
|
+
And to get those fixtures you would call them this way:
|
29
|
+
|
30
|
+
FactoryGuy.build('user') or FactoryGuy.build('bob')
|
31
|
+
|
32
|
+
@param model the model to define
|
33
|
+
@param config your default and specific fixtures
|
34
|
+
*/
|
35
|
+
define: function (model, config) {
|
36
|
+
var info = this.getModelInfo(model);
|
37
|
+
for (key in config) {
|
38
|
+
var value = config[key];
|
39
|
+
info[key] = value;
|
40
|
+
if (key != 'default') {
|
41
|
+
this.fixtureLookup[key] = model;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
// setup id
|
45
|
+
this.modelIds[model] = 0;
|
46
|
+
},
|
47
|
+
|
48
|
+
/**
|
49
|
+
|
50
|
+
@param model
|
51
|
+
*/
|
52
|
+
getModelInfo: function (model) {
|
53
|
+
if (!this.fixtureStore[model]) {
|
54
|
+
this.fixtureStore[model] = {};
|
55
|
+
}
|
56
|
+
return this.fixtureStore[model];
|
57
|
+
},
|
58
|
+
|
59
|
+
/**
|
60
|
+
|
61
|
+
@param name fixture name
|
62
|
+
@returns model associated with fixture name
|
63
|
+
*/
|
64
|
+
lookupModelForName: function (name) {
|
65
|
+
var model = this.fixtureLookup[name];
|
66
|
+
if (!model) {
|
67
|
+
if (this.fixtureStore[name]) {
|
68
|
+
model = name;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
return model;
|
72
|
+
},
|
73
|
+
|
74
|
+
/**
|
75
|
+
Generate next id for model
|
76
|
+
*/
|
77
|
+
generateId: function (model) {
|
78
|
+
var lastId = this.modelIds[model] || 0;
|
79
|
+
this.modelIds[model] = lastId + 1;
|
80
|
+
return this.modelIds[model];
|
81
|
+
},
|
82
|
+
|
83
|
+
/**
|
84
|
+
Build fixtures for model or specific fixture name. For example:
|
85
|
+
|
86
|
+
FactoryGuy.build('user') for User model
|
87
|
+
FactoryGuy.build('bob') for User model with bob attributes
|
88
|
+
|
89
|
+
@param name fixture name
|
90
|
+
@param opts options that will override default fixture values
|
91
|
+
@returns {*}
|
92
|
+
*/
|
93
|
+
build: function (name, opts) {
|
94
|
+
var model = this.lookupModelForName(name);
|
95
|
+
if (!model) {
|
96
|
+
throw new Error("can't find that factory named [" + name + "]");
|
97
|
+
}
|
98
|
+
|
99
|
+
var modelInfo = this.fixtureStore[model];
|
100
|
+
var modelAttributes = modelInfo[name] || {};
|
101
|
+
var defaultModelAttributes = modelInfo.default;
|
102
|
+
var fixture = $.extend({}, defaultModelAttributes, modelAttributes, opts);
|
103
|
+
fixture.id = this.generateId(model);
|
104
|
+
return fixture;
|
105
|
+
},
|
106
|
+
|
107
|
+
/**
|
108
|
+
Clear model instances from FIXTURES array, and from store cache.
|
109
|
+
Reset the id sequence for the models back to zero.
|
110
|
+
*/
|
111
|
+
resetModels: function (store) {
|
112
|
+
var typeMaps = store.typeMaps;
|
113
|
+
if (store.usingFixtureAdapter()) {
|
114
|
+
for (typeKey in this.fixtureStore) {
|
115
|
+
var modelType = store.modelFor(typeKey);
|
116
|
+
modelType.FIXTURES = [];
|
117
|
+
store.unloadAll(modelType);
|
118
|
+
}
|
119
|
+
} else {
|
120
|
+
for (model in typeMaps) {
|
121
|
+
if (typeMaps[model].type.typeKey != 'user') {
|
122
|
+
// console.log(typeMaps[model].type.typeKey)
|
123
|
+
store.unloadAll(typeMaps[model].type);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
this.modelIds = {}
|
128
|
+
},
|
129
|
+
|
130
|
+
/**
|
131
|
+
Push fixture to model's FIXTURES array.
|
132
|
+
Used when store's adapter is a DS.FixtureAdapter.
|
133
|
+
|
134
|
+
@param modelClass DS.Model type
|
135
|
+
@param fixture the fixture to add
|
136
|
+
*/
|
137
|
+
pushFixture: function (modelClass, fixture) {
|
138
|
+
if (!modelClass['FIXTURES']) {
|
139
|
+
modelClass['FIXTURES'] = [];
|
140
|
+
}
|
141
|
+
modelClass['FIXTURES'].push(fixture);
|
142
|
+
return fixture;
|
143
|
+
}
|
144
|
+
})
|
145
|
+
DS.Store.reopen({
|
146
|
+
|
147
|
+
usingFixtureAdapter: function() {
|
148
|
+
var adapter = this.adapterFor('application');
|
149
|
+
return adapter instanceof DS.FixtureAdapter
|
150
|
+
},
|
151
|
+
|
152
|
+
/**
|
153
|
+
Make new fixture and save to store. If the store is using FixtureAdapter,
|
154
|
+
will push to FIXTURE array, otherwise will use push method on adapter.
|
155
|
+
|
156
|
+
@param name
|
157
|
+
@param options
|
158
|
+
@returns {*}
|
159
|
+
*/
|
160
|
+
makeFixture: function (name, options) {
|
161
|
+
var modelName = FactoryGuy.lookupModelForName(name);
|
162
|
+
var fixture = FactoryGuy.build(name, options);
|
163
|
+
var modelType = this.modelFor(modelName);
|
164
|
+
|
165
|
+
if (this.usingFixtureAdapter()) {
|
166
|
+
this.setBelongsToFixturesAssociation(modelType, modelName, fixture);
|
167
|
+
return FactoryGuy.pushFixture(modelType, fixture);
|
168
|
+
} else {
|
169
|
+
var self = this;
|
170
|
+
var model;
|
171
|
+
Em.run( function() {
|
172
|
+
model = self.push(modelName, fixture);
|
173
|
+
self.setBelongsToRestAssociation(modelType, modelName, model);
|
174
|
+
});
|
175
|
+
return model;
|
176
|
+
}
|
177
|
+
},
|
178
|
+
|
179
|
+
/**
|
180
|
+
Trying to set the belongsTo association for FixtureAdapter,
|
181
|
+
with models that have a hasMany association.
|
182
|
+
|
183
|
+
For example if a client hasMany projects, then set the client.id
|
184
|
+
on each project that the client hasMany of, so that the project
|
185
|
+
now has the belongsTo client association setup.
|
186
|
+
|
187
|
+
@param name
|
188
|
+
@param model
|
189
|
+
*/
|
190
|
+
setBelongsToFixturesAssociation: function (modelType, modelName, parentFixture) {
|
191
|
+
var store = this;
|
192
|
+
var adapter = this.adapterFor('application');
|
193
|
+
var relationShips = Ember.get(modelType, 'relationshipNames');
|
194
|
+
if (relationShips.hasMany) {
|
195
|
+
relationShips.hasMany.forEach(function (relationship) {
|
196
|
+
var hasManyModel = store.modelFor(Em.String.singularize(relationship));
|
197
|
+
if (parentFixture[relationship]) {
|
198
|
+
parentFixture[relationship].forEach(function(id) {
|
199
|
+
var hasManyfixtures = adapter.fixturesForType(hasManyModel);
|
200
|
+
var fixture = adapter.findFixtureById(hasManyfixtures, id);
|
201
|
+
fixture[modelName] = parentFixture.id;
|
202
|
+
})
|
203
|
+
}
|
204
|
+
})
|
205
|
+
}
|
206
|
+
},
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Trying to set the belongsTo association for the rest type models
|
210
|
+
* with a hasMany association
|
211
|
+
*
|
212
|
+
* For example if a client hasMany projects, then set the client
|
213
|
+
* on each project that the client hasMany of, so that the project
|
214
|
+
* now has the belongsTo client association setup
|
215
|
+
*
|
216
|
+
* @param modelType
|
217
|
+
* @param modelName
|
218
|
+
* @param parent model to check for hasMany
|
219
|
+
*/
|
220
|
+
setBelongsToRestAssociation: function (modelType, modelName, parent) {
|
221
|
+
var relationShips = Ember.get(modelType, 'relationshipNames');
|
222
|
+
|
223
|
+
if (relationShips.hasMany) {
|
224
|
+
relationShips.hasMany.forEach(function (name) {
|
225
|
+
var children = parent.get(name);
|
226
|
+
if (children.get('length') > 0) {
|
227
|
+
children.forEach(function(child) {
|
228
|
+
child.set(modelName, parent)
|
229
|
+
})
|
230
|
+
}
|
231
|
+
})
|
232
|
+
}
|
233
|
+
},
|
234
|
+
|
235
|
+
/**
|
236
|
+
Adding a pushPayload for FixtureAdapter, but using the original with
|
237
|
+
other adapters that support pushPayload.
|
238
|
+
|
239
|
+
@param type
|
240
|
+
@param payload
|
241
|
+
*/
|
242
|
+
pushPayload: function (type, payload) {
|
243
|
+
if (this.usingFixtureAdapter()) {
|
244
|
+
var model = this.modelFor(modelName);
|
245
|
+
FactoryGuy.pushFixture(model, payload);
|
246
|
+
} else {
|
247
|
+
this._super(type, payload);
|
248
|
+
}
|
249
|
+
}
|
250
|
+
});
|
251
|
+
|
252
|
+
|
253
|
+
DS.FixtureAdapter.reopen({
|
254
|
+
|
255
|
+
/**
|
256
|
+
Overriding createRecord in FixtureAdapter to add the record
|
257
|
+
created to the hashMany records for all of the records that
|
258
|
+
this one belongsTo.
|
259
|
+
|
260
|
+
@method createRecord
|
261
|
+
@param {DS.Store} store
|
262
|
+
@param {subclass of DS.Model} type
|
263
|
+
@param {DS.Model} record
|
264
|
+
@return {Promise} promise
|
265
|
+
*/
|
266
|
+
createRecord: function(store, type, record) {
|
267
|
+
var promise = this._super(store, type, record);
|
268
|
+
|
269
|
+
promise.then( function() {
|
270
|
+
var hasManyName = Ember.String.pluralize(type.typeKey);
|
271
|
+
var relationShips = Ember.get(type, 'relationshipNames');
|
272
|
+
if (relationShips.belongsTo) {
|
273
|
+
// console.log('record',record+'', type.typeKey, hasManyName);
|
274
|
+
// relationShips.belongsTo.forEach(function (relationship) {
|
275
|
+
// console.log(relationship, record.get(relationship)+'')
|
276
|
+
// var belongsToRecord = record.get(relationship);
|
277
|
+
// console.log(relationshipForType)
|
278
|
+
// belongsToRecord.get(hasManyName).addObject(record);
|
279
|
+
// })
|
280
|
+
}
|
281
|
+
})
|
282
|
+
return promise;
|
283
|
+
}
|
284
|
+
|
285
|
+
})
|
286
|
+
|
287
|
+
|
288
|
+
FactoryGuyHelperMixin = Em.Mixin.create({
|
289
|
+
|
290
|
+
setup: function(app) {
|
291
|
+
this.set('container', app.__container__);
|
292
|
+
return this;
|
293
|
+
},
|
294
|
+
|
295
|
+
useFixtureAdapter: function(app) {
|
296
|
+
app.ApplicationAdapter = DS.FixtureAdapter;
|
297
|
+
this.getStore().adapterFor('application').simulateRemoteResponse = false;
|
298
|
+
},
|
299
|
+
|
300
|
+
find: function(type, id) {
|
301
|
+
return this.getStore().find(type, id);
|
302
|
+
},
|
303
|
+
|
304
|
+
make: function(name, opts) {
|
305
|
+
return this.getStore().makeFixture(name, opts);
|
306
|
+
},
|
307
|
+
|
308
|
+
getStore: function () {
|
309
|
+
return this.get('container').lookup('store:main');
|
310
|
+
},
|
311
|
+
|
312
|
+
pushPayload: function(type, hash) {
|
313
|
+
return this.getStore().pushPayload(type, hash);
|
314
|
+
},
|
315
|
+
|
316
|
+
pushRecord: function(type, hash) {
|
317
|
+
return this.getStore().push(type, hash);
|
318
|
+
},
|
319
|
+
|
320
|
+
stubEndpointForHttpRequest: function (url, json, options) {
|
321
|
+
options = options || {};
|
322
|
+
var request = {
|
323
|
+
url: url,
|
324
|
+
dataType: 'json',
|
325
|
+
responseText: json,
|
326
|
+
type: options.type || 'GET',
|
327
|
+
status: options.status || 200
|
328
|
+
}
|
329
|
+
|
330
|
+
if (options.data) {
|
331
|
+
request.data = options.data
|
332
|
+
}
|
333
|
+
|
334
|
+
$.mockjax(request);
|
335
|
+
},
|
336
|
+
|
337
|
+
/**
|
338
|
+
* Handling ajax POST for a model
|
339
|
+
*
|
340
|
+
* @param name of the fixture ( or model ) to create
|
341
|
+
* @param opts fixture options
|
342
|
+
*/
|
343
|
+
handleCreate: function (name, opts) {
|
344
|
+
var model = FactoryGuy.lookupModelForName(name);
|
345
|
+
this.stubEndpointForHttpRequest(
|
346
|
+
"/" + Em.String.pluralize(model),
|
347
|
+
this.buildAjaxResponse(name, opts),
|
348
|
+
{type: 'POST'}
|
349
|
+
)
|
350
|
+
},
|
351
|
+
|
352
|
+
buildAjaxResponse: function (name, opts) {
|
353
|
+
var fixture = FactoryGuy.build(name, opts);
|
354
|
+
var model = FactoryGuy.lookupModelForName(name);
|
355
|
+
var hash = {};
|
356
|
+
hash[model] = fixture;
|
357
|
+
return hash;
|
358
|
+
},
|
359
|
+
|
360
|
+
handleUpdate: function (root, id) {
|
361
|
+
this.stubEndpointForHttpRequest(
|
362
|
+
"/" + Em.String.pluralize(root) + "/" + id, '{}', {type: 'PUT'}
|
363
|
+
)
|
364
|
+
},
|
365
|
+
|
366
|
+
handleDelete: function (root, id) {
|
367
|
+
this.stubEndpointForHttpRequest(
|
368
|
+
"/" + Em.String.pluralize(root) + "/" + id, {}, {type: 'DELETE'}
|
369
|
+
)
|
370
|
+
},
|
371
|
+
|
372
|
+
teardown: function () {
|
373
|
+
FactoryGuy.resetModels(this.getStore());
|
374
|
+
}
|
375
|
+
|
376
|
+
})
|