ember-data-factory-guy 0.2.1 → 0.3.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.
- data/.gitignore +4 -1
- data/Gruntfile.js +8 -0
- data/README.md +253 -91
- data/bower.json +1 -1
- data/dist/ember-data-factory-guy.js +137 -65
- data/dist/ember-data-factory-guy.min.js +1 -1
- data/ember-data-factory-guy.gemspec +1 -1
- data/package.json +1 -1
- data/src/factory_guy.js +38 -24
- data/src/factory_guy_test_mixin.js +2 -2
- data/src/model_definition.js +7 -2
- data/src/store.js +90 -37
- data/tests/active_model_adapter_factory_test.js +26 -3
- data/tests/factory_guy_test.js +28 -2
- data/tests/fixture_adapter_factory_test.js +23 -0
- data/tests/rest_adapter_factory_test.js +27 -4
- data/tests/store_test.js +1 -1
- data/tests/support/factories/hat_factory.js +9 -0
- data/tests/support/factories/project_factory.js +12 -0
- data/tests/support/models/hat.js +8 -0
- data/tests/support/models/user.js +2 -1
- data/tests/support/test_helper.js +3 -0
- data/tests/test_setup.js +32 -1
- data/vendor/assets/javascripts/ember_data_factory_guy.js +137 -65
- metadata +4 -2
data/.gitignore
CHANGED
data/Gruntfile.js
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
Ember Data Factory Guy [](http://travis-ci.org/danielspaniel/ember-data-factory-guy)
|
2
|
-
=================
|
1
|
+
# Ember Data Factory Guy [](http://travis-ci.org/danielspaniel/ember-data-factory-guy)
|
3
2
|
|
4
|
-
|
3
|
+
## Using as Gem
|
5
4
|
|
6
5
|
To Use with in Rails project or project with sprockets:
|
7
6
|
|
@@ -24,7 +23,7 @@ then:
|
|
24
23
|
//= require ember_data_factory_guy
|
25
24
|
```
|
26
25
|
|
27
|
-
|
26
|
+
## Using as bower component
|
28
27
|
|
29
28
|
Add as one of your dependencies in bower.json file:
|
30
29
|
```json
|
@@ -40,13 +39,13 @@ then:
|
|
40
39
|
$ bower install
|
41
40
|
```
|
42
41
|
|
43
|
-
|
42
|
+
## How this works
|
44
43
|
|
45
44
|
Add fixtures to the store using the:
|
46
45
|
|
47
|
-
* DS.FixtureAdapter
|
48
46
|
* DS.RestAdapter
|
49
47
|
* DS.ActiveModelAdapter
|
48
|
+
* DS.FixtureAdapter
|
50
49
|
|
51
50
|
NOTE: The benefit of using FactoryGuy is that you can run your tests with the
|
52
51
|
default adapter that your application's store normally uses. In other words:
|
@@ -60,25 +59,39 @@ If you do get these types of errors try requiring the factory_guy_has_many.js fi
|
|
60
59
|
( located in dist dir and vendor dir ) AFTER you require ember-data,
|
61
60
|
but BEFORE you require your models.
|
62
61
|
|
62
|
+
Let's say you have a few models like these:
|
63
63
|
|
64
64
|
```javascript
|
65
65
|
|
66
|
-
////////////////////////////////////////////
|
67
|
-
// Model definitions
|
68
|
-
|
69
66
|
User = DS.Model.extend({
|
70
67
|
name: DS.attr('string'),
|
71
68
|
type: DS.attr('string'),
|
72
|
-
projects: DS.hasMany('project')
|
73
|
-
|
69
|
+
projects: DS.hasMany('project'),
|
70
|
+
hats: DS.hasMany('hat', {polymorphic: true})
|
71
|
+
});
|
74
72
|
|
75
73
|
Project = DS.Model.extend({
|
76
|
-
title: DS.attr('string')
|
74
|
+
title: DS.attr('string'),
|
77
75
|
user: DS.belongsTo('user')
|
78
|
-
})
|
76
|
+
});
|
77
|
+
|
78
|
+
Hat = DS.Model.extend({
|
79
|
+
type: DS.attr('string'),
|
80
|
+
user: DS.belongsTo('user')
|
81
|
+
});
|
82
|
+
|
83
|
+
BigHat = Hat.extend();
|
84
|
+
SmallHat = Hat.extend();
|
79
85
|
|
86
|
+
```
|
87
|
+
|
88
|
+
|
89
|
+
### Defining a Fixture Factory for a Model
|
90
|
+
|
91
|
+
```javascript
|
80
92
|
////////////////////////////////////////////
|
81
93
|
// FactoryGuy definitions for models
|
94
|
+
|
82
95
|
FactoryGuy.define('user', {
|
83
96
|
// sequences to be used in attributes definition
|
84
97
|
sequences: {
|
@@ -99,113 +112,185 @@ but BEFORE you require your models.
|
|
99
112
|
type: 'superuser',
|
100
113
|
name: 'Admin'
|
101
114
|
}
|
115
|
+
// using a function for an attribute that refers to other attributes
|
116
|
+
funny_user: {
|
117
|
+
type: function(f) { return 'funny ' + f.name }
|
118
|
+
}
|
102
119
|
});
|
103
120
|
|
104
121
|
FactoryGuy.define('project', {
|
105
122
|
default: {
|
106
123
|
title: 'Project'
|
124
|
+
},
|
125
|
+
//
|
126
|
+
// define built in belongTo models
|
127
|
+
//
|
128
|
+
project_with_user: {
|
129
|
+
// user model with default attributes
|
130
|
+
user: {}
|
131
|
+
},
|
132
|
+
project_with_dude: {
|
133
|
+
// user model with custom attributes
|
134
|
+
user: {name: 'Dude'}
|
135
|
+
},
|
136
|
+
project_with_admin: {
|
137
|
+
// for named association, use this FactoryGuy.association helper method
|
138
|
+
user: FactoryGuy.association('admin')
|
107
139
|
}
|
108
140
|
});
|
109
141
|
|
142
|
+
FactoryGuy.define('hat', {
|
143
|
+
default: {},
|
144
|
+
small_hat: {
|
145
|
+
type: 'small_hat'
|
146
|
+
},
|
147
|
+
big_hat: {
|
148
|
+
type: 'big_hat'
|
149
|
+
}
|
150
|
+
})
|
151
|
+
```
|
152
|
+
|
153
|
+
|
154
|
+
### Building Json
|
155
|
+
|
156
|
+
```javascript
|
110
157
|
//////////////////////////////////////////////////////////////////
|
111
|
-
//
|
158
|
+
//
|
112
159
|
// building json with FactoryGuy.build
|
113
160
|
//
|
114
161
|
|
115
|
-
|
162
|
+
FactoryGuy.build('user') // {id: 1, name: 'User1', type: 'normal'}
|
116
163
|
// note the sequence used in the name attribute
|
117
|
-
|
118
|
-
|
119
|
-
|
164
|
+
FactoryGuy.build('user') // {id: 2, name: 'User2', type: 'normal'}
|
165
|
+
FactoryGuy.build('user', {name: 'bob'}) // {id: 3, name: 'bob', type: 'normal'}
|
166
|
+
FactoryGuy.build('admin') // {id: 4, name: 'Admin', type: 'superuser'}
|
167
|
+
// note the type attribute was built from a function which depends on the name
|
168
|
+
// and the name is still a generated attribute from a sequence function
|
169
|
+
FactoryGuy.build('funny_user') // {id: 5, name: 'User3', type: 'funny User3'}
|
170
|
+
|
171
|
+
// basic project
|
172
|
+
FactoryGuy.build('project') // {id: 1, title: 'Project'}
|
173
|
+
|
174
|
+
// project with a user
|
175
|
+
FactoryGuy.build('project_with_user') // {id: 1, title: 'Project', user: {id:6, name: 'User4', type: 'normal'}
|
176
|
+
// project with user that has custom attributes
|
177
|
+
FactoryGuy.build('project_with_dude') // {id: 2, title: 'Project', user: {id:7, name: 'Dude', type: 'normal'}
|
178
|
+
// project with user that has a named user
|
179
|
+
FactoryGuy.build('project_with_admin') // {id: 3, title: 'Project', user: {id:8, name: 'Admin', type: 'superuser'}
|
120
180
|
|
121
181
|
//////////////////////////////////////////////////////////////////
|
122
|
-
//
|
182
|
+
//
|
123
183
|
// building json with FactoryGuy.buildList
|
124
184
|
//
|
125
185
|
|
126
|
-
|
186
|
+
FactoryGuy.buildList('user', 2) // [ {id: 1, name: 'User1', type: 'normal'}, {id: 2, name: 'User2', type: 'normal'} ]
|
187
|
+
```
|
127
188
|
|
128
|
-
//////////////////////////////////////////////////////////////////
|
129
|
-
//
|
130
|
-
// with store using => DS.Fixture adapter
|
131
|
-
//
|
132
|
-
// store.makeFixture => creates model in the store and returns json
|
133
|
-
// store.makeList => creates list of models in the store and returns json
|
134
|
-
//
|
135
189
|
|
136
|
-
|
137
|
-
store.makeFixture('user', {name: 'bob'}); // user.FIXTURES = [{id: 2, name: 'bob', type: 'normal'}]
|
138
|
-
store.makeFixture('admin'); // user.FIXTURES = [{id: 3, name: 'Admin', type: 'superuser'}]
|
139
|
-
store.makeFixture('admin', {name: 'Fred'}); // user.FIXTURES = [{id: 4, name: 'Fred', type: 'superuser'}]
|
190
|
+
###Adding records to store
|
140
191
|
|
192
|
+
#####DS.ActiveModelAdapter/DS.RestAdapter
|
141
193
|
|
142
|
-
|
143
|
-
// you use the ActiveModelAdapter or RESTAdapter the record is returned so you don't
|
144
|
-
// have to then go and find it
|
145
|
-
var userJson = store.makeFixture('user');
|
146
|
-
store.find('user', userJson.id).then(function(user) {
|
147
|
-
user.toJSON() ( has all the same key/values as ) userJson;
|
148
|
-
});
|
194
|
+
###### The Basics
|
149
195
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
// OR
|
154
|
-
var userJson = store.makeFixture('user');
|
155
|
-
var projectJson = store.makeFixture('project', user: userJson.id);
|
156
|
-
|
157
|
-
// will give you the same result, but with fixture adapter all associations
|
158
|
-
// are treated as async ( by factory_guy_has_many.js fix ), so it's
|
159
|
-
// a bit clunky to get this associated data. When using DS.FixtureAdapter
|
160
|
-
// in view specs though, this clunk is dealt with for you. But remember,
|
161
|
-
// you don't have to use the Fixture adapter.
|
162
|
-
store.find('user', 1).then(function(user) {
|
163
|
-
user.get('name') == 'My name';
|
164
|
-
user.get('projects').then(function(projects) {
|
165
|
-
projects.length == 1;
|
166
|
-
});
|
167
|
-
});
|
196
|
+
store.makeFixture => creates model in the store and returns model instance
|
197
|
+
*NOTE* since you are getting a model instances, you can synchronously
|
198
|
+
start asking for data from the model, and its associations
|
168
199
|
|
169
|
-
|
170
|
-
|
200
|
+
```javascript
|
201
|
+
var user = store.makeFixture('user'); // user.toJSON() = {id: 1, name: 'User1', type: 'normal'}
|
202
|
+
// note that the user name is a sequence
|
203
|
+
var user = store.makeFixture('user'); // user.toJSON() = {id: 2, name: 'User2', type: 'normal'}
|
204
|
+
var user = store.makeFixture('funny_user'); // user.toJSON() = {id: 3, name: 'User3', type: 'funny User3'}
|
205
|
+
var user = store.makeFixture('user', {name: 'bob'}); // user.toJSON() = {id: 4, name: 'bob', type: 'normal'}
|
206
|
+
var user = store.makeFixture('admin'); // user.toJSON() = {id: 5, name: 'Admin', type: 'superuser'}
|
207
|
+
var user = store.makeFixture('admin', {name: 'Fred'}); // user.toJSON() = {id: 6, name: 'Fred', type: 'superuser'}
|
208
|
+
```
|
171
209
|
|
172
|
-
|
173
|
-
//
|
174
|
-
// with store using => DS.ActiveModelAdapter/DS.RestAdapter
|
175
|
-
//
|
176
|
-
// store.makeFixture => creates model in the store and returns model instance
|
177
|
-
// store.makeList => creates list of models in the store and returns model instance
|
178
|
-
//
|
179
|
-
// *NOTE* since you are now getting a model instances, you can synchronously
|
180
|
-
// start asking for data from the model
|
181
|
-
//
|
210
|
+
###### associations
|
182
211
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
212
|
+
``` javascript
|
213
|
+
var project = store.makeFixture('project');
|
214
|
+
var user = store.makeFixture('user', {projects: [project]});
|
215
|
+
// OR
|
216
|
+
var user = store.makeFixture('user');
|
217
|
+
var project = store.makeFixture('project', {user: user});
|
189
218
|
|
190
|
-
|
219
|
+
// will get you the same results, since FactoryGuy makes sure the associations
|
220
|
+
// are created in both directions
|
221
|
+
// user.get('projects.length') == 1;
|
222
|
+
// user.get('projects.firstObject.user') == user;
|
223
|
+
```
|
224
|
+
|
225
|
+
###### polymorphic hasMany associations
|
226
|
+
|
227
|
+
```javascript
|
228
|
+
var sh = store.makeFixture('big_hat');
|
229
|
+
var bh = store.makeFixture('small_hat');
|
230
|
+
var user = store.makeFixture('user', {hats: [sh, bh]})
|
231
|
+
// user.get('hats.length') == 2;
|
232
|
+
// (user.get('hats.firstObject') instanceof BigHat) == true
|
233
|
+
// (user.get('hats.lastObject') instanceof SmallHat) == true
|
234
|
+
```
|
235
|
+
|
236
|
+
###### create lists
|
237
|
+
|
238
|
+
```javascript
|
239
|
+
var users = store.makeList('user', 3);
|
240
|
+
```
|
241
|
+
|
242
|
+
#####DS.Fixture adapter
|
243
|
+
|
244
|
+
store.makeFixture => creates model in the store and returns json
|
191
245
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
246
|
+
Technically when you call store.makeFixture with a store using the DS.FixtureAdapter,
|
247
|
+
the fixture is actually added to the models FIXTURE array. It just seems to be added
|
248
|
+
to the store because when you call store.find to get that record, the adapter looks
|
249
|
+
in that FIXTURE array to find it and then puts it in the store.
|
250
|
+
|
251
|
+
```javascript
|
252
|
+
|
253
|
+
store.makeFixture('user'); // user.FIXTURES = [{id: 1, name: 'User1', type: 'normal'}]
|
254
|
+
store.makeFixture('user', {name: 'bob'}); // user.FIXTURES = [{id: 2, name: 'bob', type: 'normal'}]
|
255
|
+
store.makeFixture('admin'); // user.FIXTURES = [{id: 3, name: 'Admin', type: 'superuser'}]
|
256
|
+
store.makeFixture('admin', {name: 'Fred'}); // user.FIXTURES = [{id: 4, name: 'Fred', type: 'superuser'}]
|
197
257
|
|
198
|
-
// will get you the same results
|
199
|
-
user.get('projects.length') == 1;
|
200
|
-
user.get('projects.firstObject.user') == user;
|
201
258
|
|
202
|
-
|
203
|
-
|
259
|
+
// Use store.find to get the model instance ( Remember this is the Fixture adapter, if
|
260
|
+
// you use the ActiveModelAdapter or RESTAdapter the record is returned so you don't
|
261
|
+
// have to then go and find it )
|
262
|
+
var userJson = store.makeFixture('user');
|
263
|
+
store.find('user', userJson.id).then(function(user) {
|
264
|
+
user.toJSON() ( pretty much equals ) userJson;
|
265
|
+
});
|
204
266
|
|
267
|
+
// and to setup associations ...
|
268
|
+
var projectJson = store.makeFixture('project');
|
269
|
+
var userJson = store.makeFixture('user', {projects: [projectJson.id]});
|
270
|
+
// OR
|
271
|
+
var userJson = store.makeFixture('user');
|
272
|
+
var projectJson = store.makeFixture('project', {user: userJson.id});
|
273
|
+
|
274
|
+
// will give you the same result, but with fixture adapter all associations
|
275
|
+
// are treated as async ( by factory_guy_has_many.js fix ), so it's
|
276
|
+
// a bit clunky to get this associated data. When using DS.FixtureAdapter
|
277
|
+
// in view specs though, this clunk is dealt with for you. But remember,
|
278
|
+
// you don't have to use the Fixture adapter.
|
279
|
+
store.find('user', 1).then(function(user) {
|
280
|
+
user.toJSON() (pretty much equals) userJson;
|
281
|
+
user.get('projects').then(function(projects) {
|
282
|
+
projects.length == 1;
|
283
|
+
});
|
284
|
+
});
|
285
|
+
|
286
|
+
// and for lists
|
287
|
+
store.makeList('user', 2, {projects: [project.id]});
|
205
288
|
```
|
206
289
|
|
207
|
-
|
208
|
-
|
290
|
+
###Testing models, controllers, views
|
291
|
+
|
292
|
+
|
293
|
+
This section assumes you are testing the ( controllers and views ) in isolation.
|
209
294
|
|
210
295
|
The code bundled in dist/ember-data-factory-guy.js includes a mixin named FactoryGuyTestMixin which
|
211
296
|
can be used in your tests to make it easier to access the store and make fixtures.
|
@@ -219,7 +304,6 @@ TestHelper = Ember.Object.createWithMixins(FactoryGuyTestMixin);
|
|
219
304
|
|
220
305
|
// Then in your tests you can use it like so:
|
221
306
|
|
222
|
-
|
223
307
|
var testHelper, store;
|
224
308
|
|
225
309
|
module('User Model', {
|
@@ -257,7 +341,85 @@ test("make a user using your applications default adapter", function() {
|
|
257
341
|
```
|
258
342
|
|
259
343
|
|
260
|
-
|
261
|
-
|
344
|
+
###Integration Tests
|
345
|
+
|
346
|
+
Since it is recommended to use your normal adapter ( which is usually a subclass of RESTAdapter, )
|
347
|
+
FactoryGuyTestMixin assumes you will want to use that adapter to do your integration tests.
|
348
|
+
|
349
|
+
To do that you will still have to deal with ember data trying to create, update or delete records.
|
350
|
+
|
351
|
+
If you put models into the store ( with store#makeFixture ), the http GET call does not need to be mocked,
|
352
|
+
since that model is already in the store.
|
353
|
+
|
354
|
+
But what if you want to handle create, update or delete?
|
355
|
+
FactoryGuy assumes you want to mock ajax calls with the mockjax library,
|
356
|
+
and you will need to download and include that library to use the following feature.
|
357
|
+
|
358
|
+
Here is a sample of what you could do in a view test:
|
359
|
+
|
360
|
+
```javascript
|
361
|
+
|
362
|
+
// create a view test helper using the FactoryGuyTestMixin
|
363
|
+
ViewTestHelper = Ember.Object.createWithMixins(FactoryGuyTestMixin,{
|
364
|
+
// override setup to do a few extra things for view tests
|
365
|
+
setup: function (app, opts) {
|
366
|
+
app.reset(); // reset ember app before test
|
367
|
+
$.mockjaxSettings.logging = false; // mockjax settings
|
368
|
+
$.mockjaxSettings.responseTime = 0; // mockjax settings
|
369
|
+
return this._super(app); // still call the base setup from FactoryGuyTestMixin
|
370
|
+
},
|
371
|
+
// override teardown to clear mockjax declarations
|
372
|
+
teardown: function() {
|
373
|
+
$.mockjaxClear();
|
374
|
+
this._super();
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
var viewHelper;
|
379
|
+
|
380
|
+
module('User View', {
|
381
|
+
setup: function() {
|
382
|
+
viewHelper = ViewTestHelper.setup(App); // set up helper
|
383
|
+
var user = viewHelper.make('user'); // create a user in the store
|
384
|
+
visit('/users/'+user.id); // visit the users route
|
385
|
+
},
|
386
|
+
teardown: function() {
|
387
|
+
Em.run(function() { viewHelper.teardown(); });
|
388
|
+
}
|
389
|
+
});
|
390
|
+
|
391
|
+
test("Creates new project", function() {
|
392
|
+
andThen(function() {
|
393
|
+
var newProjectName = "Gonzo Project"
|
394
|
+
|
395
|
+
click('.add-div div:contains(New Project)')
|
396
|
+
fillIn('.add-project input', newProjectName)
|
397
|
+
// This is the special sauce that makes this project really hum.
|
398
|
+
// Check out the FactoryGuyTestMixin to see what is going on here
|
399
|
+
viewHelper.handleCreate('project', {name: newProjectName})
|
400
|
+
|
401
|
+
/**
|
402
|
+
Let's say that clicking this '.add-project .link', triggers action in the view to
|
403
|
+
create project record and looks something like this:
|
404
|
+
|
405
|
+
actions: {
|
406
|
+
addProject: function (user) {
|
407
|
+
this.get('controller.store')
|
408
|
+
.createRecord('project', {
|
409
|
+
name: this.$('.add-project input').val(),
|
410
|
+
user: user
|
411
|
+
})
|
412
|
+
.save()
|
413
|
+
}
|
414
|
+
|
415
|
+
*/
|
416
|
+
click('.add-project .link')
|
417
|
+
|
418
|
+
var newProjectDiv = find('.project:contains('+newProjectName+')')
|
419
|
+
equal(newProjectDiv[0] != undefined, true)
|
420
|
+
})
|
421
|
+
})
|
422
|
+
|
423
|
+
```
|
424
|
+
|
262
425
|
|
263
|
-
mockjax
|