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 CHANGED
@@ -1,3 +1,6 @@
1
1
  bower_components/
2
2
  node_modules/
3
- *.gem
3
+ factory_guy_presentation/
4
+ factory_guy_presents/
5
+ stats/
6
+ *.gem
data/Gruntfile.js CHANGED
@@ -49,6 +49,14 @@ module.exports = function(grunt) {
49
49
 
50
50
  qunit: {
51
51
  all: ['tests/*.html']
52
+ },
53
+
54
+ bump: {
55
+ options: {
56
+ files: ['package.json', 'bower.json', 'ember-data-factory-guy.gemspec'],
57
+ commitFiles: ["-a"],
58
+ push: false
59
+ }
52
60
  }
53
61
  });
54
62
 
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
- # Using as Gem
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
- # Using as bower component
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
- # How this works
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
- // ** Make one fixture at time **
158
+ //
112
159
  // building json with FactoryGuy.build
113
160
  //
114
161
 
115
- var userJson = FactoryGuy.build('user') // {id: 1, name: 'User1', type: 'normal'}
162
+ FactoryGuy.build('user') // {id: 1, name: 'User1', type: 'normal'}
116
163
  // note the sequence used in the name attribute
117
- var user2Json = FactoryGuy.build('user') // {id: 2, name: 'User2', type: 'normal'}
118
- var customUserJson = FactoryGuy.build('user', name: 'bob') // {id: 3, name: 'bob', type: 'normal'}
119
- var namedUserJson = FactoryGuy.build('admin') // {id: 4, name: 'Admin', type: 'superuser'}
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
- // ** Make a list of fixtures **
182
+ //
123
183
  // building json with FactoryGuy.buildList
124
184
  //
125
185
 
126
- var userJson = FactoryGuy.buildList('user',2) // [ {id: 1, name: 'User1', type: 'normal'}, {id: 2, name: 'User2', type: 'normal'} ]
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
- store.makeFixture('user'); // user.FIXTURES = [{id: 1, name: 'User1', type: 'normal'}]
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
- // Use store.find to get the model instance ( Remember this is the Fixture adapter, if
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
- // and to setup associations ...
151
- var projectJson = store.makeFixture('project');
152
- var userJson = store.makeFixture('user', projects: [project.id]);
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
- // and for lists
170
- var users = store.makeList('user', 2, projects: [project.id]);
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
- var user = store.makeFixture('user'); // user.toJSON() = {id: 1, name: 'User1', type: 'normal'}
184
- // note that the user name is a sequence
185
- var user = store.makeFixture('user'); // user.toJSON() = {id: 2, name: 'User2', type: 'normal'}
186
- var user = store.makeFixture('user', {name: 'bob'}); // user.toJSON() = {id: 3, name: 'bob', type: 'normal'}
187
- var user = store.makeFixture('admin'); // user.toJSON() = {id: 4, name: 'Admin', type: 'superuser'}
188
- var user = store.makeFixture('admin', name: 'Fred'); // user.toJSON() = {id: 5, name: 'Fred', type: 'superuser'}
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
- // and to setup associations ...
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
- var project = store.makeFixture('project');
193
- var user = store.makeFixture('user', projects: [project]);
194
- // OR
195
- var user = store.makeFixture('user');
196
- var project = store.makeFixture('project', user: user);
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
- // and to create lists ( of 3 users in this case )
203
- var users = store.makeList('user', 3);
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
- Extra Goodies
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
- Further Extra Goodies
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