diff --git a/.ember-cli b/.ember-cli new file mode 100644 index 0000000..ee64cfe --- /dev/null +++ b/.ember-cli @@ -0,0 +1,9 @@ +{ + /** + Ember CLI sends analytics information by default. The data is completely + anonymous, but there are times when you might want to disable this behavior. + + Setting `disableAnalytics` to true will prevent any data from being sent. + */ + "disableAnalytics": false +} diff --git a/Brocfile.js b/Brocfile.js index 8c25bfe..f49c402 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -1,9 +1,22 @@ /* global require, module */ var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); +var pickFiles = require('broccoli-static-compiler'); var app = new EmberAddon(); +var sinon = pickFiles('bower_components/sinonjs', { + srcDir: '/', + files: ['sinon.js'], + destDir: '/assets' +}); + +var sinonQunit = pickFiles('bower_components/sinon-qunit/lib', { + srcDir: '/', + files: ['sinon-qunit.js'], + destDir: '/assets' +}); + // Use `app.import` to add additional libraries to the generated // output files. // @@ -17,4 +30,4 @@ var app = new EmberAddon(); // please specify an object with the list of modules as keys // along with the exports of each module as its value. -module.exports = app.toTree(); +module.exports = app.toTree( sinon, sinonQunit ); diff --git a/addon/adapters/localstorage.js b/addon/adapters/localstorage.js index f7abe36..a8c48a9 100755 --- a/addon/adapters/localstorage.js +++ b/addon/adapters/localstorage.js @@ -171,7 +171,7 @@ var LocalStorageAdapter = Adapter.extend({ save: function( url, content ) { var promise; - Ember.assert('A url is required to delete a model', url); + Ember.assert('A url is required to save a model', url); promise = new Ember.RSVP.Promise( function( resolve ){ var db, @@ -218,7 +218,7 @@ var LocalStorageAdapter = Adapter.extend({ * @return {object} localStorage or mockup */ _getLocalStorage: function(){ - return this.get( 'localStorageMockup' ) || window.localStorage; + return window.localStorage; }, /** diff --git a/addon/cache.js b/addon/cache.js index 9086851..c54713e 100644 --- a/addon/cache.js +++ b/addon/cache.js @@ -189,8 +189,7 @@ export default Ember.Object.extend({ }, fetchOne: function( type ){ - var self = this, - record, + var record, promise = this._getPromises( type ).get( 'ids.0' ); if( promise ){ @@ -204,9 +203,7 @@ export default Ember.Object.extend({ } return Ember.ObjectProxy.createWithMixins( Ember.PromiseProxyMixin ) - .set( 'promise', new Ember.RSVP.Promise( function( resolve, reject ){ - resolve( record ); - })); + .set( 'promise', new Ember.RSVP.Promise.resolve( record ) ); }, @@ -219,8 +216,7 @@ export default Ember.Object.extend({ * @return {Object} */ fetchById: function( type, id ) { - var self = this, - record, + var record, promise = this._getPromiseById( type, id ); if( promise ){ @@ -234,9 +230,7 @@ export default Ember.Object.extend({ } return Ember.ObjectProxy.createWithMixins( Ember.PromiseProxyMixin ) - .set( 'promise', new Ember.RSVP.Promise( function( resolve, reject ){ - resolve( record ); - })); + .set( 'promise', new Ember.RSVP.Promise.resolve( record ) ); }, /** @@ -262,9 +256,7 @@ export default Ember.Object.extend({ } return Ember.ArrayProxy.createWithMixins( Ember.PromiseProxyMixin ) - .set( 'promise', new Ember.RSVP.Promise( function( resolve, reject){ - resolve( records ); - })); + .set( 'promise', new Ember.RSVP.Promise.resolve( records ) ); }, /** diff --git a/addon/initializers/sl-model.js b/addon/initializers/sl-model.js index b79047c..52afbde 100755 --- a/addon/initializers/sl-model.js +++ b/addon/initializers/sl-model.js @@ -21,4 +21,4 @@ export default function ( container, application ) { application.inject('adapter', 'store', 'store:main'); -}; +} diff --git a/blueprints/localstorage-initializer/files/app/initializers/localstorage.js b/blueprints/localstorage-initializer/files/app/initializers/localstorage.js index b1c49cb..d9ee445 100644 --- a/blueprints/localstorage-initializer/files/app/initializers/localstorage.js +++ b/blueprints/localstorage-initializer/files/app/initializers/localstorage.js @@ -8,7 +8,7 @@ export default { var localStorageAdapter = SlModelLocalstorageAdapter.extend(); localStorageAdapter.reopenClass({ - namspace: '<%= namespace %>' + namespace: '<%= namespace %>' }); container.register('adapter:localstorage', localStorageAdapter ); diff --git a/bower.json b/bower.json index a092aa7..4b9fb41 100644 --- a/bower.json +++ b/bower.json @@ -1,16 +1,21 @@ { - "name": "dummy", + "name": "sl-model", "dependencies": { "handlebars": "~1.3.0", "jquery": "^1.11.1", "ember": "1.7.0", "ember-resolver": "~0.1.7", - "loader": "stefanpenner/loader.js#1.0.1", + "loader.js": "stefanpenner/loader.js#1.0.1", "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3", "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4", "ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2", "ember-qunit": "0.1.8", "ember-qunit-notifications": "0.0.4", - "qunit": "~1.15.0" + "qunit": "~1.15.0", + "pretender": "0.1.0" + }, + "devDependencies": { + "sinonjs": "~1.10.2", + "sinon-qunit": "~2.0.0" } -} +} \ No newline at end of file diff --git a/config/environment.js b/config/environment.js new file mode 100644 index 0000000..0dfaed4 --- /dev/null +++ b/config/environment.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = function(/* environment, appConfig */) { + return { }; +}; diff --git a/package.json b/package.json index 98e407a..642b1fd 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "sl-model", - "version": "0.0.0", + "version": "0.1.7", "directories": { "doc": "doc", - "test": "test" + "test": "tests" }, "scripts": { "start": "ember server", @@ -14,27 +14,30 @@ "engines": { "node": ">= 0.10.0" }, - "keywords": [ - "ember-addon" - ], - "ember-addon": { - "configPath": "tests/dummy/config" - }, "author": "", "license": "MIT", "devDependencies": { "body-parser": "^1.2.0", - "broccoli-asset-rev": "0.0.17", + "broccoli-asset-rev": "0.3.0", "broccoli-ember-hbs-template-compiler": "^1.6.1", + "broccoli-static-compiler": "^0.2.0", "connect-restreamer": "^1.0.0", - "ember-cli": "0.0.44", - "ember-cli-ember-data": "0.1.0", + "ember-cli": "0.1.1", + "ember-cli-content-security-policy": "0.2.0", "ember-cli-ic-ajax": "0.1.1", - "ember-cli-qunit": "0.0.5", + "ember-cli-inject-live-reload": "^1.2.2", + "ember-cli-pretender": "^0.3.1", + "ember-cli-qunit": "0.1.0", "express": "^4.8.5", "glob": "^4.0.5" }, + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "configPath": "tests/dummy/config" + }, "dependencies": { - "sl-modelize": "git+ssh://git@gitlab.softlayer.local:interface/sl-modelize.git#addon" + "sl-modelize": "git+ssh://git@gitlab.softlayer.local:interface/sl-modelize.git#v0.0.2" } } diff --git a/server/mocks/bar.js b/server/mocks/bar.js new file mode 100644 index 0000000..02886d5 --- /dev/null +++ b/server/mocks/bar.js @@ -0,0 +1,13 @@ +module.exports = function(app) { + var express = require('express'); + var barApiRouter = express.Router(); + barApiRouter.get('/', function(req, res) { + res.send({"bar":[ + { + id: 1, + name: 'cheers' + } + ]}); + }); + app.use('/api/bar', barApiRouter); +}; diff --git a/server/mocks/car.js b/server/mocks/car.js new file mode 100644 index 0000000..2506db5 --- /dev/null +++ b/server/mocks/car.js @@ -0,0 +1,21 @@ +module.exports = function(app) { + var express = require('express'); + var carApiRouter = express.Router(); + carApiRouter.get('/', function(req, res) { + res.send({"car":[ + { + id: 1, + name: 'ford' + }, + { + id: 2, + name: 'chevy' + }, + { + id: 3, + name: 'lambo' + } + ]}); + }); + app.use('/api/car', carApiRouter); +}; diff --git a/server/mocks/foo.js b/server/mocks/foo.js new file mode 100644 index 0000000..621f167 --- /dev/null +++ b/server/mocks/foo.js @@ -0,0 +1,17 @@ +module.exports = function(app) { + var express = require('express'); + var fooApiRouter = express.Router(); + fooApiRouter.get('/', function(req, res) { + res.send({"foo":[ + { + id: 1, + name: 'fighters', + bar: { + id: 2, + name: 'cheers2' + } + } + ]}); + }); + app.use('/api/foo', fooApiRouter); +}; diff --git a/server/mocks/test.js b/server/mocks/test.js deleted file mode 100644 index c75dde8..0000000 --- a/server/mocks/test.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = function(app) { - var express = require('express'); - var testApiRouter = express.Router(); - testApiRouter.get('/', function(req, res) { - res.send({"test":[ - { - id: 1, - name: 'test1' - }, - { - id: 2, - name: 'test2' - }, - { - id: 3, - name: 'test3' - } - ]}); - }); - app.use('/api/test', testApiRouter); -}; diff --git a/tests/.jshintrc b/tests/.jshintrc index 95db7f3..5a454f0 100644 --- a/tests/.jshintrc +++ b/tests/.jshintrc @@ -39,13 +39,14 @@ "findWithAssert", "wait", "DS", - "keyEvent", "isolatedContainer", "startApp", "andThen", "currentURL", "currentPath", - "currentRouteName" + "currentRouteName", + "propEqual", + "sinon" ], "node": false, "browser": false, diff --git a/tests/dummy/.jshintrc b/tests/dummy/.jshintrc index 427d89f..7547475 100644 --- a/tests/dummy/.jshintrc +++ b/tests/dummy/.jshintrc @@ -2,8 +2,7 @@ "predef": { "document": true, "window": true, - "-Promise": true, - "DummyENV": true + "-Promise": true }, "browser" : true, "boss" : true, diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index 5727e51..757df38 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -1,14 +1,16 @@ import Ember from 'ember'; import Resolver from 'ember/resolver'; import loadInitializers from 'ember/load-initializers'; +import config from './config/environment'; Ember.MODEL_FACTORY_INJECTIONS = true; var App = Ember.Application.extend({ - modulePrefix: 'dummy', // TODO: loaded via config + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, Resolver: Resolver }); -loadInitializers(App, 'dummy'); +loadInitializers(App, config.modulePrefix); export default App; diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html index 028dd91..0f3e6af 100644 --- a/tests/dummy/app/index.html +++ b/tests/dummy/app/index.html @@ -7,20 +7,13 @@ - {{BASE_TAG}} + {{content-for 'head'}} - - diff --git a/tests/dummy/app/models/bar.js b/tests/dummy/app/models/bar.js new file mode 100644 index 0000000..6934e21 --- /dev/null +++ b/tests/dummy/app/models/bar.js @@ -0,0 +1,14 @@ +import SlModel from 'sl-model/model'; + +var Bar = SlModel.extend({ +}); + +Bar.reopenClass({ + adapter: 'localstorage', + url: '/api/bar', + serializer: function( result ){ + return result.bar; + } +}); + +export default Bar; diff --git a/tests/dummy/app/models/car.js b/tests/dummy/app/models/car.js new file mode 100644 index 0000000..b5f5c51 --- /dev/null +++ b/tests/dummy/app/models/car.js @@ -0,0 +1,13 @@ +import SlModel from 'sl-model/model'; + +var Car = SlModel.extend({ +}); + +Car.reopenClass({ + url: '/api/car', + serializer: function( result ){ + return result.car; + } +}); + +export default Car; diff --git a/tests/dummy/app/models/foo.js b/tests/dummy/app/models/foo.js new file mode 100644 index 0000000..3476afb --- /dev/null +++ b/tests/dummy/app/models/foo.js @@ -0,0 +1,13 @@ +import SlModel from 'sl-model/model'; + +var Foo = SlModel.extend({ +}); + +Foo.reopenClass({ + url: '/api/foo', + serializer: function( result ){ + return result.foo; + } +}); + +export default Foo; diff --git a/tests/dummy/app/models/test.js b/tests/dummy/app/models/test.js deleted file mode 100644 index 83cd3b8..0000000 --- a/tests/dummy/app/models/test.js +++ /dev/null @@ -1,14 +0,0 @@ -import SlModel from 'sl-model/model'; - -var Test = SlModel.extend({ - log: function( msg ){ console.log( msg, this ); } -}); - -Test.reopenClass({ - url: '/api/test', - serializer: function( result ){ - return result.test; - } -}); - -export default Test; diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index d650ea7..cef554b 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -1,7 +1,8 @@ import Ember from 'ember'; +import config from './config/environment'; var Router = Ember.Router.extend({ - location: DummyENV.locationType + location: config.locationType }); Router.map(function() { diff --git a/tests/dummy/app/routes/application.js b/tests/dummy/app/routes/application.js index 946cd3e..279bd32 100644 --- a/tests/dummy/app/routes/application.js +++ b/tests/dummy/app/routes/application.js @@ -1,15 +1,3 @@ import Ember from 'ember'; export default Ember.Route.extend({ - - beforeModel: function(){ - var self = this; - this.store.find( 'test' ).then( function( testModels ){ - console.log( 'found models', testModels ); - }) - .catch( function(){ - console.log( 'no model found!' ); - - }); - } - }); diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs index d08c11f..ff53cff 100644 --- a/tests/dummy/app/templates/application.hbs +++ b/tests/dummy/app/templates/application.hbs @@ -1,3 +1,3 @@ -

Welcome to Ember.js

+

Welcome to Sl-Model!

{{outlet}} diff --git a/tests/dummy/app/templates/index.hbs b/tests/dummy/app/templates/index.hbs new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/tests/dummy/app/templates/index.hbs @@ -0,0 +1 @@ +test diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 47490a8..8a3bb9d 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -2,6 +2,7 @@ module.exports = function(environment) { var ENV = { + modulePrefix: 'dummy', environment: environment, baseURL: '/', locationType: 'auto', @@ -24,10 +25,26 @@ module.exports = function(environment) { // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; ENV.APP.LOG_VIEW_LOOKUPS = true; + ENV.contentSecurityPolicy = { + 'default-src': "'none'", + 'script-src': "'self' 'unsafe-inline' 'unsafe-eval'", + 'font-src': "'self'", + 'connect-src': "'self'", + 'img-src': "'self'", + 'style-src': "'self' 'unsafe-inline'" + }; } if (environment === 'test') { - ENV.baseURL = '/'; // Testem prefers this... + // Testem prefers this... + ENV.baseURL = '/'; + ENV.locationType = 'auto'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; } if (environment === 'production') { diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js index 62fc58f..28f4ece 100644 --- a/tests/helpers/resolver.js +++ b/tests/helpers/resolver.js @@ -1,9 +1,11 @@ import Resolver from 'ember/resolver'; +import config from '../../config/environment'; var resolver = Resolver.create(); resolver.namespace = { - modulePrefix: 'dummy' + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix }; export default resolver; diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index a5d62ca..7cd4320 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -1,16 +1,13 @@ import Ember from 'ember'; -import Application from 'dummy/app'; -import Router from 'dummy/router'; +import Application from '../../app'; +import Router from '../../router'; +import config from '../../config/environment'; export default function startApp(attrs) { var App; - var attributes = Ember.merge({ - // useful Test defaults - rootElement: '#ember-testing', - LOG_ACTIVE_GENERATION: false, - LOG_VIEW_LOOKUPS: false - }, attrs); // but you can override; + var attributes = Ember.merge({}, config.APP); + attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; Router.reopen({ location: 'none' diff --git a/tests/index.html b/tests/index.html index e88d21d..15fb50e 100644 --- a/tests/index.html +++ b/tests/index.html @@ -7,7 +7,7 @@ - {{BASE_TAG}} + {{content-for 'head'}} @@ -33,17 +33,12 @@
- - + + diff --git a/tests/test-helper.js b/tests/test-helper.js index f77e5a2..b5f6449 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -8,8 +8,5 @@ setResolver(resolver); document.write('
'); QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'}); -if (QUnit.urlParams.nocontainer) { - document.getElementById('ember-testing-container').style.visibility = 'hidden'; -} else { - document.getElementById('ember-testing-container').style.visibility = 'visible'; -} +var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible'; +document.getElementById('ember-testing-container').style.visibility = containerVisibility; diff --git a/tests/unit/adapters-test.js b/tests/unit/adapters-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/adapters/ajax-test.js b/tests/unit/adapters/ajax-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/adapters/localstorage-test.js b/tests/unit/adapters/localstorage-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/cache-test.js b/tests/unit/cache-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/initializers/sl-model-test.js b/tests/unit/initializers/sl-model-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/store-test.js b/tests/unit/store-test.js new file mode 100644 index 0000000..9e079b8 --- /dev/null +++ b/tests/unit/store-test.js @@ -0,0 +1,130 @@ +import Ember from 'ember'; +import { test, moduleFor } from 'ember-qunit'; +import Foo from 'dummy/models/foo'; +import Bar from 'dummy/models/bar'; +import Store from 'sl-model/store'; + +var store, + AjaxAdapter, + LocalstorageAdapter; + +module( 'Unit - sl-model/store', { + + setup: function(){ + Foo.reopenClass({url:'/foo'}); + + Bar.reopenClass({ adapter: 'localstorage' }); + + AjaxAdapter = Ember.Object.extend({ type: 'ajax', __find: function(){}, find: function(){ return Ember.Object.create(); } }); + + LocalstorageAdapter = Ember.Object.extend({ type: 'localstorage' }); + + store = Store.create({ + container: { + registry: [], + cache: {}, + normalize: function( key ){ + return key; + }, + lookup: function( key ){ + if( this.cache[key] ) return this.cache[key]; + + var obj = this.registry.findBy( 'key', key ).factory.create({container:this}); + this.cache[key] = obj; + return obj; + }, + lookupFactory: function( key ){ + return this.registry.findBy( 'key', key ).factory; + } + } + }); + store.container.registry.push( { key: 'adapter:ajax', factory: AjaxAdapter } ); + store.container.registry.push( { key: 'adapter:localstorage', factory: LocalstorageAdapter } ); + + store.container.registry.push( { key: 'model:foo', factory: Foo } ); + store.container.registry.push( { key: 'model:bar', factory: Bar } ); + }, + teardown: function(){ + } +}); + +test( 'modelFor: should return the model "Foo" for type "foo" ', function() { + ok( store.modelFor( 'foo' ) === Foo ); +}); + +test( 'modelFor: should return the model "Bar" for type "bar" ', function() { + ok( store.modelFor( 'bar' ) === Bar ); +}); + +test( 'adapterFor: should return the adapter ajax for model type foo', function() { + ok( store.adapterFor( 'foo' ) instanceof AjaxAdapter ); +}); + +test( 'adapterFor: should return the adapter localstorage for model type bar', function() { + ok( store.adapterFor( 'bar' ) instanceof LocalstorageAdapter ); +}); + +test( 'findOne: should call __find with correct args', function(){ + var options = { "otherId":1 }, + args; + + store.__find = sinon.spy(); + + store.findOne( 'foo', options ); + + ok( store.__find.calledWith( 'foo', null, options, true ) ); +}); + +test( 'find should call __find with numeric id', function(){ + var options = { "otherId": 1 }; + store.__find = sinon.spy(); + store.find( 'foo', 1, options ); + ok( store.__find.calledWith( 'foo', 1, options, false ) ); +}); + +test( 'find should call __find with object for first param', function(){ + var options = { "otherId": 1 }; + store.__find = sinon.spy(); + store.find( 'foo', options ); + ok( store.__find.calledWith( 'foo', null, options, false ) ); +}); + +test( 'find should call __find with only the type', function(){ + store.__find = sinon.spy(); + store.find( 'foo' ); + ok( store.__find.calledWith( 'foo', null, null, false ) ); +}); + +test( '__find should have called modelFor', function(){ + sinon.spy( store, 'modelFor' ); + store.__find( 'foo', 1, {}, false ); + ok( store.modelFor.calledWith( 'foo' ) ); +}); + +test( '__find should have called adapterFor', function(){ + sinon.spy( store, 'adapterFor' ); + store.__find( 'foo', 1, {}, false ); + ok( store.adapterFor.calledWith( 'foo' ) ); +}); + +test( '__find should have called AjaxAdapter.find', function(){ + var ajaxAdapter = store.container.lookup('adapter:ajax'); + sinon.spy( ajaxAdapter, 'find' ); + store.__find( 'foo', 1, {}, false ); + ok( ajaxAdapter.find.calledWith( Foo, 1, {}, false ) ); +}); + +test( 'createRecord should have called modelFor', function(){ +}); + +test( 'createRecord should have called Foo.create once', function(){ +}); + +test( 'createRecord should have called Foo.create with an object container', function(){ +}); + +test( 'registerPreQueryHook should add an entry to preQueryHooks', function(){ +}); + +test( 'runPreQueryHooks should run query hook once', function(){ +});