ember-data-factory-guy 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/danielspaniel/ember-data-factory-guy.png?branch=master)](http://travis-ci.org/danielspaniel/ember-data-factory-guy)
|
2
|
-
=================
|
1
|
+
# Ember Data Factory Guy [![Build Status](https://secure.travis-ci.org/danielspaniel/ember-data-factory-guy.png?branch=master)](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
|