├── .gitignore
├── README.mkd
├── Rakefile
├── public
└── javascripts
│ ├── backbone-factory.js
│ ├── backbone-min.js
│ ├── test-setup.js
│ └── underscore-min.js
└── spec
└── javascripts
├── BackboneFactorySpec.js
├── helpers
└── SpecHelper.js
└── support
├── jasmine.yml
├── jasmine_config.rb
└── jasmine_runner.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle
2 | db/*.qlite3
3 | log/*.log
4 | tmp/**/*
5 | config/database.yml
6 | tmp/*
7 | doc/api
8 | doc/app
9 | *.swp
10 | *.swo
11 | *.un~
12 | *˜
13 | .DS_Store
14 | schema.rb
15 | .tags
16 | emails/*
17 | public/uploads/*
18 |
--------------------------------------------------------------------------------
/README.mkd:
--------------------------------------------------------------------------------
1 | Backbone Factory
2 | ================
3 |
4 | Introduction
5 | ------------
6 |
7 | Backbone Factory is a small javascript library for creating [Backbone.js](http://documentcloud.github.com/backbone/) objects for testing your code. It has no external dependency.
8 |
9 | The API is heavily inspired by the awesome [Factory Girl](https://github.com/thoughtbot/factory_girl).
10 |
11 |
12 | Installation
13 | ------------
14 |
15 | To use it, just [download](https://github.com/SupportBee/Backbone-Factory/raw/master/public/javascripts/backbone-factory.js) the file and include it in your testing setup.
16 | Usage
17 | -----
18 |
19 | Lets say you have two Backbone models, Post and User
20 |
21 | ```javascript
22 | var User = Backbone.Model.extend({
23 |
24 | name: null,
25 | email: null
26 |
27 | });
28 |
29 | var Post = Backbone.Model.extend({
30 |
31 | defaults: {
32 | title: 'Default Title'
33 | }
34 |
35 | });
36 | ```
37 |
38 | ### Defining Factories
39 |
40 | To define factories for them
41 |
42 | ```javascript
43 | var postFactory = BackboneFactory.define('post', Post);
44 | var userFactory = BackboneFactory.define('user', User);
45 | ```
46 |
47 | ### Using Factories
48 |
49 | To use these factories,
50 |
51 | ```javscript
52 | this.postObject = BackboneFactory.create('post');
53 | this.userObject = BackboneFactory.create('user');
54 | ```
55 |
56 | This will create objects using the [defaults](http://documentcloud.github.com/backbone/#Model-defaults) you have in your class definitions.
57 |
58 |
59 | ### Defining Sequences
60 |
61 | ```javascript
62 | var emailSequence = BackboneFactory.define_sequence('email', function(n){
63 | return "person"+n+"@example.com";
64 | });
65 | ```
66 |
67 | ### Using Sequences
68 |
69 | ```javascript
70 | var email = BackboneFactory.next('email') // person1@example.com
71 | ```
72 |
73 | ### Defining Factories with defaults
74 |
75 | ```javascript
76 | var userFactory = BackboneFactory.define('user', User, function(){
77 | return {
78 | name : 'Backbone User',
79 | email: BackboneFactory.next('person_email')
80 | };
81 | }
82 | );
83 | ```
84 |
85 | ### Overriding defaults when creating objects
86 |
87 | ```javascript
88 | var userWithEmail = BackboneFactory.create('user', function(){
89 | return {
90 | email: 'overriden@example.com'
91 | };
92 | });
93 | ```
94 |
95 | Contributing
96 | ------------
97 |
98 | 1. Open a ticket on GitHub, maybe someone else has the problem too
99 | 2. Make a fork of my GitHub repository
100 | 3. Make a spec driven change to the code base (we use [jasmine](http://pivotal.github.com/jasmine/))
101 | 5. Make sure it works and all specs pass
102 | 6. Update the README if needed to reflect your change / addition
103 | 7. With all specs passing push your changes back to your fork
104 | 8. Send me a pull request
105 |
106 |
107 | License
108 | -------
109 |
110 | (The MIT License)
111 |
112 | Copyright (c) 2009, 2010, 2011
113 |
114 | Permission is hereby granted, free of charge, to any person obtaining
115 | a copy of this software and associated documentation files (the
116 | 'Software'), to deal in the Software without restriction, including
117 | without limitation the rights to use, copy, modify, merge, publish,
118 | distribute, sublicense, and/or sell copies of the Software, and to
119 | permit persons to whom the Software is furnished to do so, subject to
120 | the following conditions:
121 |
122 | The above copyright notice and this permission notice shall be
123 | included in all copies or substantial portions of the Software.
124 |
125 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
126 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
127 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
128 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
129 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
130 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
131 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 |
2 | begin
3 | require 'jasmine'
4 | load 'jasmine/tasks/jasmine.rake'
5 | rescue LoadError
6 | task :jasmine do
7 | abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine"
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/public/javascripts/backbone-factory.js:
--------------------------------------------------------------------------------
1 | // Backbone Factory JS
2 | // https://github.com/SupportBee/Backbone-Factory
3 |
4 | (function(){
5 | window.BackboneFactory = {
6 |
7 | factories: {},
8 | sequences: {},
9 |
10 | define: function(factory_name, klass, defaults){
11 |
12 | // Check for arguments' sanity
13 | if(factory_name.match(/[^\w-_]+/)){
14 | throw "Factory name should not contain spaces or other funky characters";
15 | }
16 |
17 | if(defaults === undefined) defaults = function(){return {}};
18 |
19 | // The object creator
20 | this.factories[factory_name] = function(options){
21 | if(options === undefined) options = function(){return {}};
22 | arguments = _.extend({}, {id: BackboneFactory.next("_" + factory_name + "_id")}, defaults.call(), options.call());
23 | return new klass(arguments);
24 | };
25 |
26 | // Lets define a sequence for id
27 | BackboneFactory.define_sequence("_"+ factory_name +"_id", function(n){
28 | return n
29 | });
30 | },
31 |
32 | create: function(factory_name, options){
33 | if(this.factories[factory_name] === undefined){
34 | throw "Factory with name " + factory_name + " does not exist";
35 | }
36 | return this.factories[factory_name].apply(null, [options]);
37 | },
38 |
39 | define_sequence: function(sequence_name, callback){
40 | this.sequences[sequence_name] = {}
41 | this.sequences[sequence_name]['counter'] = 0;
42 | this.sequences[sequence_name]['callback'] = callback;
43 | },
44 |
45 | next: function(sequence_name){
46 | if(this.sequences[sequence_name] === undefined){
47 | throw "Sequence with name " + sequence_name + " does not exist";
48 | }
49 | this.sequences[sequence_name]['counter'] += 1;
50 | return this.sequences[sequence_name]['callback'].apply(null, [this.sequences[sequence_name]['counter']]); //= callback;
51 | }
52 | }
53 | })();
54 |
--------------------------------------------------------------------------------
/public/javascripts/backbone-min.js:
--------------------------------------------------------------------------------
1 | // Backbone.js 0.3.3
2 | // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Backbone may be freely distributed under the MIT license.
4 | // For all details and documentation:
5 | // http://documentcloud.github.com/backbone
6 | (function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d/g,">").replace(/"/g,
9 | """)},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&
10 | !this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this},
11 | fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete",
12 | this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},hasChanged:function(a){if(a)return this._previousAttributes[a]!=
13 | this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}});
14 | e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c').hide().appendTo("body")[0].contentWindow;
22 | "onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment=
23 | this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events,
24 | {tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({},
25 | this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend=
26 | m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override",
27 | g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})();
28 |
--------------------------------------------------------------------------------
/public/javascripts/test-setup.js:
--------------------------------------------------------------------------------
1 | //Models for testing out Backbone Factory
2 |
3 | var User = Backbone.Model.extend({
4 |
5 | name: null,
6 | email: null
7 |
8 | });
9 |
10 | var Post = Backbone.Model.extend({
11 |
12 | defaults: {
13 | title: 'Default Title'
14 | }
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/public/javascripts/underscore-min.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.1.6
2 | // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){var p=this,C=p._,m={},i=Array.prototype,n=Object.prototype,f=i.slice,D=i.unshift,E=n.toString,l=n.hasOwnProperty,s=i.forEach,t=i.map,u=i.reduce,v=i.reduceRight,w=i.filter,x=i.every,y=i.some,o=i.indexOf,z=i.lastIndexOf;n=Array.isArray;var F=Object.keys,q=Function.prototype.bind,b=function(a){return new j(a)};typeof module!=="undefined"&&module.exports?(module.exports=b,b._=b):p._=b;b.VERSION="1.1.6";var h=b.each=b.forEach=function(a,c,d){if(a!=null)if(s&&a.forEach===s)a.forEach(c,d);else if(b.isNumber(a.length))for(var e=
9 | 0,k=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,
13 | c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),
16 | e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,
20 | b.identity)};b.functions=b.methods=function(a){return b.filter(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=
21 | typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;
22 | for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};
23 | b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset||!a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=
24 | 0;e/g,interpolate:/<%=([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||
25 | null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d};var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort",
26 | "splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})();
27 |
--------------------------------------------------------------------------------
/spec/javascripts/BackboneFactorySpec.js:
--------------------------------------------------------------------------------
1 | describe("Backbone Factory", function() {
2 |
3 | describe("Defining and using Sequences", function(){
4 |
5 | beforeEach(function() {
6 | var emailSequence = BackboneFactory.define_sequence('email', function(n){
7 | return "person"+n+"@example.com";
8 | });
9 | });
10 |
11 | it("should increment the sequence on successive calls", function(){
12 | expect(BackboneFactory.next('email')).toBe('person1@example.com');
13 | expect(BackboneFactory.next('email')).toBe('person2@example.com');
14 | });
15 |
16 | });
17 |
18 | describe("Defining and using Factories", function(){
19 |
20 | beforeEach(function() {
21 | var emailSequence = BackboneFactory.define_sequence('person_email', function(n){
22 | return "person"+n+"@example.com";
23 | });
24 | var postFactory = BackboneFactory.define('post', Post, function(){
25 | return {
26 | author: BackboneFactory.create('user')
27 | };
28 | }
29 | );
30 | var userFactory = BackboneFactory.define('user', User, function(){
31 | return {
32 | name : 'Backbone User',
33 | email: BackboneFactory.next('person_email')
34 | };
35 | }
36 | );
37 |
38 | this.postObject = BackboneFactory.create('post');
39 | this.userObject = BackboneFactory.create('user');
40 | });
41 |
42 |
43 | it("return an instance of the Backbone Object requested", function() {
44 | expect(this.postObject instanceof Post).toBeTruthy();
45 | expect(this.userObject instanceof User).toBeTruthy();
46 | });
47 |
48 | // Not sure if this test is needed. But what the hell!
49 | it("should preserve the defaults if not overriden", function() {
50 | expect(this.postObject.get('title')).toBe('Default Title');
51 | });
52 |
53 |
54 |
55 | it("should use the defaults supplied when creating objects", function() {
56 | expect(this.userObject.get('name')).toBe('Backbone User');
57 | });
58 |
59 | it("should work with sequences", function(){
60 | expect(this.userObject.get('email')).toBe('person2@example.com');
61 | var anotherUser = BackboneFactory.create('user');
62 | expect(anotherUser.get('email')).toBe('person3@example.com');
63 | });
64 |
65 | it("should work if other factories are passed", function(){
66 | expect(this.postObject.get('author') instanceof User).toBeTruthy();
67 | })
68 |
69 | it("should override defaults if arguments are passed on creation", function(){
70 | var userWithEmail = BackboneFactory.create('user', function(){
71 | return {
72 | email: 'overriden@example.com'
73 | };
74 | });
75 | expect(userWithEmail.get('email')).toBe('overriden@example.com');
76 | });
77 |
78 | it("should have an id", function() {
79 | expect(this.userObject.id).toBeDefined();
80 | });
81 |
82 | it("should have an id that increments on creation", function(){
83 | var firstID = BackboneFactory.create('user').id;
84 | var secondID = BackboneFactory.create('user').id;
85 | expect(secondID).toBe(firstID + 1);
86 | });
87 |
88 | describe("Error Messages", function() {
89 |
90 | it("should throw an error if factory_name is not proper", function() {
91 | expect(function(){BackboneFactory.define('wrong name', Post)}).toThrow("Factory name should not contain spaces or other funky characters");
92 | });
93 |
94 | it("should not throw an error if factory_name has a hyphen", function() {
95 | expect(function(){BackboneFactory.define('okay-name', Post)}).not.toThrow();
96 | });
97 |
98 | it("should throw an error if you try to use an undefined factory", function() {
99 | expect(function(){BackboneFactory.create('undefined_factory')}).toThrow("Factory with name undefined_factory does not exist");
100 | });
101 |
102 | it("should throw an error if you try to use an undefined sequence", function() {
103 | expect(function(){BackboneFactory.next('undefined_sequence')}).toThrow("Sequence with name undefined_sequence does not exist");
104 | });
105 |
106 | });
107 |
108 | });
109 |
110 | });
111 |
112 |
--------------------------------------------------------------------------------
/spec/javascripts/helpers/SpecHelper.js:
--------------------------------------------------------------------------------
1 | beforeEach(function() {
2 | this.addMatchers({
3 | toBePlaying: function(expectedSong) {
4 | var player = this.actual;
5 | return player.currentlyPlayingSong === expectedSong
6 | && player.isPlaying;
7 | }
8 | })
9 | });
10 |
--------------------------------------------------------------------------------
/spec/javascripts/support/jasmine.yml:
--------------------------------------------------------------------------------
1 | # src_files
2 | #
3 | # Return an array of filepaths relative to src_dir to include before jasmine specs.
4 | # Default: []
5 | #
6 | # EXAMPLE:
7 | #
8 | # src_files:
9 | # - lib/source1.js
10 | # - lib/source2.js
11 | # - dist/**/*.js
12 | #
13 | src_files:
14 | - public/javascripts/underscore-min.js
15 | - public/javascripts/backbone-min.js
16 | - public/javascripts/test-setup.js
17 | - public/javascripts/backbone-factory.js
18 | #- public/javascripts/**/*.js
19 |
20 | # stylesheets
21 | #
22 | # Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
23 | # Default: []
24 | #
25 | # EXAMPLE:
26 | #
27 | # stylesheets:
28 | # - css/style.css
29 | # - stylesheets/*.css
30 | #
31 | stylesheets:
32 |
33 | # helpers
34 | #
35 | # Return an array of filepaths relative to spec_dir to include before jasmine specs.
36 | # Default: ["helpers/**/*.js"]
37 | #
38 | # EXAMPLE:
39 | #
40 | # helpers:
41 | # - helpers/**/*.js
42 | #
43 | helpers:
44 |
45 | # spec_files
46 | #
47 | # Return an array of filepaths relative to spec_dir to include.
48 | # Default: ["**/*[sS]pec.js"]
49 | #
50 | # EXAMPLE:
51 | #
52 | # spec_files:
53 | # - **/*[sS]pec.js
54 | #
55 | spec_files:
56 | - **/*[sS]pec.js
57 |
58 | # src_dir
59 | #
60 | # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
61 | # Default: project root
62 | #
63 | # EXAMPLE:
64 | #
65 | # src_dir: public
66 | #
67 | src_dir:
68 |
69 | # spec_dir
70 | #
71 | # Spec directory path. Your spec_files must be returned relative to this path.
72 | # Default: spec/javascripts
73 | #
74 | # EXAMPLE:
75 | #
76 | # spec_dir: spec/javascripts
77 | #
78 | spec_dir:
79 |
--------------------------------------------------------------------------------
/spec/javascripts/support/jasmine_config.rb:
--------------------------------------------------------------------------------
1 | module Jasmine
2 | class Config
3 |
4 | # Add your overrides or custom config code here
5 |
6 | end
7 | end
8 |
9 |
10 | # Note - this is necessary for rspec2, which has removed the backtrace
11 | module Jasmine
12 | class SpecBuilder
13 | def declare_spec(parent, spec)
14 | me = self
15 | example_name = spec["name"]
16 | @spec_ids << spec["id"]
17 | backtrace = @example_locations[parent.description + " " + example_name]
18 | parent.it example_name, {} do
19 | me.report_spec(spec["id"])
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/javascripts/support/jasmine_runner.rb:
--------------------------------------------------------------------------------
1 | $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
2 |
3 | require 'rubygems'
4 | require 'jasmine'
5 | jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
6 | require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
7 | if Jasmine::rspec2?
8 | require 'rspec'
9 | else
10 | require 'spec'
11 | end
12 |
13 | jasmine_config = Jasmine::Config.new
14 | spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
15 |
16 | should_stop = false
17 |
18 | if Jasmine::rspec2?
19 | RSpec.configuration.after(:suite) do
20 | spec_builder.stop if should_stop
21 | end
22 | else
23 | Spec::Runner.configure do |config|
24 | config.after(:suite) do
25 | spec_builder.stop if should_stop
26 | end
27 | end
28 | end
29 |
30 | spec_builder.start
31 | should_stop = true
32 | spec_builder.declare_suites
--------------------------------------------------------------------------------