ember-data-factory-guy 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ bower_components/
2
+ node_modules/
data/Gruntfile.js ADDED
@@ -0,0 +1,45 @@
1
+ module.exports = function(grunt) {
2
+
3
+ grunt.initConfig({
4
+
5
+ pkg: grunt.file.readJSON('package.json'),
6
+
7
+ concat: {
8
+ dist: {
9
+ src: ['src/factory_guy.js', 'src/store.js', 'src/factory_guy_helper_mixin.js'],
10
+ dest: "dist/ember-data-factory-guy.js"
11
+ },
12
+ gem: {
13
+ files: {
14
+ "vendor/assets/javascripts/ember_data_factory_guy.js": ['src/factory_guy.js', 'src/store.js', 'src/factory_guy_helper_mixin.js'],
15
+ "vendor/assets/javascripts/factory_guy_has_many.js": ['src/has_many.js']
16
+ }
17
+ },
18
+ test: {
19
+ src: ['tests/support/factories/*.js', 'tests/support/models/*.js'],
20
+ dest: "tests/test_setup.js"
21
+ }
22
+ },
23
+
24
+ uglify: {
25
+ options: { mangle: false, compress: false },
26
+
27
+ dist: {
28
+ src: ['dist/ember-data-factory-guy.js'],
29
+ dest: 'dist/ember-data-factory-guy.min.js'
30
+ }
31
+ },
32
+
33
+ qunit: {
34
+ all: ['tests/*.html']
35
+ }
36
+ });
37
+
38
+ grunt.loadNpmTasks('grunt-contrib-coffee');
39
+ grunt.loadNpmTasks('grunt-contrib-concat');
40
+ grunt.loadNpmTasks('grunt-contrib-uglify');
41
+ grunt.loadNpmTasks('grunt-contrib-qunit');
42
+
43
+ grunt.registerTask('default', ['concat', 'uglify']);
44
+ grunt.registerTask('test', ['concat:dist', 'qunit']);
45
+ };
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # Using as Gem
2
+
3
+ To Use with in Rails project or project with sprockets:
4
+
5
+ In Gemfile:
6
+
7
+ ```ruby
8
+ gem 'ember-data-factory-guy', group: test
9
+ ```
10
+
11
+ then:
12
+
13
+ ```
14
+ $ bundle install
15
+ ```
16
+
17
+ # How this works
18
+
19
+ Add fixtures to the store using the:
20
+
21
+ * DS.FixtureAdapter
22
+ * DS.RestAdapter
23
+ * DS.ActiveModelAdapter
24
+
25
+ ```javascript
26
+
27
+ ////////////////////////////////////////////
28
+ // Model definitions
29
+
30
+ User = DS.Model.extend({
31
+ name: DS.attr 'string',
32
+ projects: DS.hasMany 'project'
33
+ })
34
+
35
+ Project = DS.Model.extend({
36
+ title: DS.attr 'string'
37
+ })
38
+
39
+ ////////////////////////////////////////////
40
+ // Fixture definitions for models
41
+
42
+ FactoryGuy.define('user', {
43
+ // default values for 'user' attributes
44
+ default: {
45
+ name: 'User1'
46
+ },
47
+ // named 'user' type with custom attributes
48
+ admin: {
49
+ name: 'Admin'
50
+ }
51
+ });
52
+
53
+ FactoryGuy.define('project', {
54
+ default: {title: 'Project'}
55
+ });
56
+
57
+ //////////////////////////////////////////////////////////////////
58
+ //
59
+ // building json with FactoryGuy.build
60
+ //
61
+ var userJson = FactoryGuy.build('user') // {id: 1, name: 'User1'}
62
+ var customUserJson = FactoryGuy.build('user', name: 'bob') // {id: 2, name: 'bob'}
63
+ var namedUserJson = FactoryGuy.build('admin') // {id: 3, name: 'Admin'}
64
+
65
+ //////////////////////////////////////////////////////////////////
66
+ // store.makeFixture method creates model in the store
67
+ //
68
+ // with DS.Fixture adapter
69
+ // makeFixture returns json
70
+ //
71
+ store.makeFixture('user'); // user.FIXTURES = {id: 1, name: 'User1'}
72
+ store.makeFixture('user', {name: 'bob'}); // user.FIXTURES = {id: 2, name: 'bob'}
73
+ store.makeFixture('admin'); // user.FIXTURES = {id: 3, name: 'Admin'}
74
+ store.makeFixture('admin', name: 'My name'); // user.FIXTURES = {id: 4, name: 'My name'}
75
+
76
+ // Use store.find to get the model instance
77
+ store.makeFixture('user');
78
+ store.find('user', 1).then(function(user) {
79
+ user.get('name') == 'My name';
80
+ });
81
+
82
+ // and to setup associations ...
83
+ var project = store.makeFixture('project');
84
+ var user = store.makeFixture('user', projects: [project.id]);
85
+
86
+ // with fixture adapter all associations are treated as async, so it's
87
+ // a bit clunky to get this associated data. When using DS.FixtureAdapter
88
+ // in view specs though, this clunk is dealt with for you.
89
+ store.find('user', 1).then(function(user) {
90
+ user.get('name') == 'My name';
91
+ user.get('projects').then(function(projects) {
92
+ projects.length == 1;
93
+ });
94
+ });
95
+
96
+ //////////////////////////////////////////////////////////////////
97
+ // store.makeFixture method creates model and adds it to store
98
+ //
99
+ // with DS.ActiveModelAdapter/DS.RestAdapter
100
+ //
101
+ // returns a model instances so you can synchronously
102
+ // start asking for data, as soon as you get the model
103
+ //
104
+ var user = store.makeFixture('user');
105
+ var user = store.makeFixture('user', {name: 'bob'}); // user.toJSON() = {id: 2, name: 'bob'}
106
+ var user = store.makeFixture('admin'); // user.toJSON() = {id: 3, name: 'Admin'}
107
+ var user = store.makeFixture('admin', name: 'My name'); // user.toJSON() = {id: 4, name: 'My name'}
108
+
109
+ // and to setup associations ...
110
+
111
+ var project = store.makeFixture('project');
112
+ var user = store.makeFixture('user', projects: [project.id]);
113
+
114
+ user.get('projects.length') == 1;
115
+ user.get('projects.firstObject.user') == user;
116
+
117
+
118
+ ```
data/bower.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "ember-data-factory-guy",
3
+ "version": "0.0.1",
4
+ "authors": [
5
+ "Daniel Sudol <dansudol@yahoo.com>",
6
+ "Opak Alex <opak.alexandr@gmail.com>"
7
+ ],
8
+ "description": "Factory for testing Ember application using Ember Data",
9
+ "main": "dist/ember-data-factory-guy.js",
10
+ "keywords": [
11
+ "Factory",
12
+ "Ember",
13
+ "Data",
14
+ "FixtureAdapter"
15
+ ],
16
+ "license": "MIT",
17
+
18
+ "dependencies": {
19
+ "handlebars": "~1.1.2",
20
+ "jquery": "1.10.2",
21
+ "ember": "~1.6.0",
22
+ "ember-data": "~1.0.0-beta.7",
23
+ "emblem.js": "*",
24
+ "chance": "latest",
25
+ "qunit": "latest"
26
+ },
27
+
28
+ "ignore": [
29
+ "**/.*",
30
+ "node_modules",
31
+ "bower_components",
32
+ "test",
33
+ "tests"
34
+ ]
35
+ }
@@ -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
+ })