diff --git a/.bowerrc b/.bowerrc index 6866ac2..959e169 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,4 @@ { - "directory": "vendor" + "directory": "bower_components", + "analytics": false } diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d5dea4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.hbs] +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 707a972..7da12c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,17 @@ -tmp -node_modules -vendor -doc \ No newline at end of file +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp + +# dependencies +/node_modules +/bower_components/* + +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index adbb6b5..0000000 --- a/.jscsrc +++ /dev/null @@ -1,101 +0,0 @@ -{ - "maximumLineLength": 120, - - "requireCurlyBraces": [ - "if", - "else", - "for", - "while", - "do", - "try", - "catch", - "case", - "default" - ], - - "requireSpaceAfterKeywords": [ - "if", - "else", - "for", - "while", - "do", - "switch", - "return", - "try", - "catch" - ], - - "requireSpaceBeforeBlockStatements": true, - - "requireParenthesesAroundIIFE": true, - - "requireSpacesInConditionalExpression": { - "afterTest": true, - "beforeConsequent": true, - "afterConsequent": true, - "beforeAlternate": true - }, - - "requireSpacesInFunctionExpression": { - "beforeOpeningCurlyBrace": true - }, - - "requireMultipleVarDecl": true, - - "requireBlocksOnNewline": 1, - - "requireSpacesInsideObjectBrackets": "allButNested", - - "requireSpacesInsideArrayBrackets": "allButNested", - - "requireSpaceAfterObjectKeys": true, - - "requireCommaBeforeLineBreak": true, - - "requireOperatorBeforeLineBreak": [ - "?", - "+", - "-", - "/", - "*", - "=", - "==", - "===", - "!=", - "!==", - ">", - ">=", - "<", - "<=" - ], - - "requireCamelCaseOrUpperCaseIdentifiers": true, - - "disallowKeywords": ["with"], - - "disallowMultipleLineStrings": true, - - "validateQuoteMarks": { "mark": "'", "escape": true }, - - "validateIndentation": 4, - - "disallowMixedSpacesAndTabs": true, - - "disallowTrailingWhitespace": true, - - "disallowTrailingComma": true, - - "disallowKeywordsOnNewLine": ["else"], - - "safeContextKeyword": [ "self" ], - - "validateJSDoc": { - "checkParamNames": true, - "checkRedundantParams": true, - "requireParamTypes": true - }, - - "validateParameterSeparator": ", ", - "requireSpacesInsideParentheses": "all" - -} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..df6253d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +--- +language: node_js + +sudo: false + +cache: + directories: + - node_modules + +install: + - npm install -g bower + - npm install + - bower install + +script: + - npm test diff --git a/Brocfile.js b/Brocfile.js index 561ce8d..8c25bfe 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -1,17 +1,20 @@ -var filterES6Modules = require('broccoli-es6-module-filter'); -var broconcat = require('broccoli-concat'); +/* global require, module */ -module.exports = broconcat( - filterES6Modules('lib', { - moduleType: 'amd', - anonymous: false, - compatFix: true, - packageName: 'sl-model', - main: 'main' - }), - { - inputFiles: ['**/*.js'], - outputFile: '/sl-model.js', - wrapInEval: false - } -); \ No newline at end of file +var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); + +var app = new EmberAddon(); + +// Use `app.import` to add additional libraries to the generated +// output files. +// +// If you need to use different assets in different +// environments, specify an object as the first parameter. That +// object's keys should be the environment name and the values +// should be the asset to use in that environment. +// +// If the library that you are including contains AMD or ES6 +// modules that you would like to import into your application +// 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(); diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index c14928b..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,6 +0,0 @@ -#master - -* updated `store.find` to do type detection on id parameter. No need to pass in null for id field now, you can pass in the options as the second parameter or leave it blank. - -#v0.1.4 -* refactored delete to deleteRecord \ No newline at end of file diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 51ac9eb..0000000 --- a/TODO.md +++ /dev/null @@ -1,4 +0,0 @@ -# ToDo - - 1. Write mor tests - 2. Yui docs everwhere diff --git a/TEST.md b/addon/.gitkeep similarity index 100% rename from TEST.md rename to addon/.gitkeep diff --git a/lib/adapter.js b/addon/adapter.js similarity index 91% rename from lib/adapter.js rename to addon/adapter.js index f5fa02c..9d238fc 100644 --- a/lib/adapter.js +++ b/addon/adapter.js @@ -1,4 +1,5 @@ -import ModelizeMixin from 'sl-modelize'; +import Ember from 'ember'; +import ModelizeMixin from 'sl-modelize/mixins/modelize'; /** * SL-Model/adapter diff --git a/lib/adapters/ajax.js b/addon/adapters/ajax.js similarity index 96% rename from lib/adapters/ajax.js rename to addon/adapters/ajax.js index b948566..8d948d9 100755 --- a/lib/adapters/ajax.js +++ b/addon/adapters/ajax.js @@ -24,12 +24,8 @@ export default Adapter.extend({ find: function ( type, id, options, findOne ){ var url, - cacheKey, - cachedModel, results, - cachedRequest, promise, - initialObj = {}, queryObj, store = this.get( 'store' ), model = store.modelFor( type ); @@ -149,8 +145,7 @@ export default Adapter.extend({ * @return {object} Promise */ save: function( url, content ) { - var promise, - result; + var promise; Ember.assert('A url property is required to save a model', url); @@ -167,7 +162,7 @@ export default Adapter.extend({ }.bind( this ), null, 'sl-model:save - then' ) - .catch( function ajaxAdapterSaveCatch( jqxhr, textStatus, error ) { + .catch( function ajaxAdapterSaveCatch( jqxhr ) { var errorData = { 'statusCode' : jqxhr.status, 'statusText' : jqxhr.statusText, diff --git a/lib/adapters/localstorage.js b/addon/adapters/localstorage.js similarity index 98% rename from lib/adapters/localstorage.js rename to addon/adapters/localstorage.js index 07cc7a1..f7abe36 100755 --- a/lib/adapters/localstorage.js +++ b/addon/adapters/localstorage.js @@ -50,7 +50,6 @@ var LocalStorageAdapter = Adapter.extend({ promise = new Ember.RSVP.Promise( function( resolve, reject){ //todo actual localStorage query var db, - modelKey, records, response, finalResult; @@ -174,7 +173,7 @@ var LocalStorageAdapter = Adapter.extend({ Ember.assert('A url is required to delete a model', url); - promise = new Ember.RSVP.Promise( function( resolve, reject ){ + promise = new Ember.RSVP.Promise( function( resolve ){ var db, records, recordIndex; diff --git a/addon/cache.js b/addon/cache.js new file mode 100644 index 0000000..3290002 --- /dev/null +++ b/addon/cache.js @@ -0,0 +1,378 @@ +import Ember from 'ember'; + +/** + * SL-Model/cache + * + * + * @class cache + */ +export default Ember.Object.extend({ + + /* + * holds the record cache + * @member object _records + * @access private + */ + _records: null, + + /* + * holds the promise cache + * @member object _promises + * @access private + */ + _promises: null, + + + /** + * _setupCache + * @access private + * + */ + _setupCache: function(){ + this.setProperties( { + '_records': Ember.Object.create(), + '_promises': Ember.Object.create() + } ); + }.on( 'init' ), + + /** + * _initializeRecords + * + * @access private + * @param {String} type + */ + _initializeRecords: function( type ){ + + this.set( '_records.'+type, Ember.Object.create({ + records: Ember.A([]), + ids: Ember.A([]) + })); + }, + + /** + * _getRecords returns the record cache + * + * @access private + * @param {String} type + * @return {Object} + */ + _getRecords: function( type ){ + var typeRecords = this.get( '_records.'+type ); + + if( ! typeRecords ){ + this._initializeRecords( type ); + typeRecords = this.get( '_records.'+type ); + } + + return typeRecords; + }, + + /** + * _getRecordById gets a record by id + * + * @access private + * @param type + * @param id + * @return {Object} + */ + _getRecordById: function( type, id ){ + return this._getRecords( type ).ids[ id ]; + }, + + /** + * _getAllRecords gets all records + * + * @access private + * @param type + * @return {Object} + */ + _getAllRecords: function( type ){ + return this._getRecords( type ).records; + }, + + /** + * _initializePromises + * + * @access private + * @param type + * @return {Object} + */ + _initializePromises: function( type ){ + this.set( '_promises.'+type, Ember.Object.create({ + all: null, + ids: Ember.A([]) + })); + }, + + /** + * _getPromises + * + * @access private + * @param type + * @return {Object} + */ + _getPromises: function( type ){ + var typePromises = this.get( '_promises.'+type ); + + if( ! typePromises ){ + this._initializePromises( type ); + typePromises = this.get( '_promises.'+type ); + } + + return typePromises; + }, + + /** + * _getPromiseById + * + * @access private + * @param type + * @param id + * @return {Object} + */ + _getPromiseById: function( type, id ){ + return this.get( '_promise.'+type+'.ids.'+id ); + }, + + /** + * _getAllPromise + * + * @access private + * @param type + * @return {Object} + */ + _getAllPromise: function( type ){ + return this.get( '_promise.'+type+'.all'); + }, + + /** + * isCached checks both caches to see if a record exists + * + * @param type + * @param id + * @param findOne + * @return {Object} + */ + isCached: function( type, id, findOne ){ + + if( id || findOne ){ + id = id || 0; + return !!this.fetchById( type, id ); + } + + return !!( this._getAllPromise( type ) || this._getAllRecords( type ).length ); + }, + + /** + * fetch returns a record or array of records + * + * @param type + * @param id + * @param findOne + * @return {Object|Array} + */ + fetch: function( type, id, findOne ){ + + if( id || findOne ){ + id = id || 0; + return this.fetchById( type, id ); + } + + return this.fetchAllByType( type ); + }, + + /** + * fetchById + * + * @param type + * @param id + * @return {Object} + */ + fetchById: function( type, id ) { + var self = this, + record, + promise = this._getPromiseById( type, id ); + + if( promise ){ + return promise; + } + + record = self._getRecordById( type, id ); + + if( ! record ){ + return false; + } + + return Ember.ObjectProxy.createWithMixins( Ember.PromiseProxyMixin ) + .set( 'promise', new Ember.RSVP.Promise( function( resolve, reject ){ + resolve( record ); + })); + }, + + /** + * fetchAllByType + * + * @param type + * @return {Array} + */ + fetchAllByType: function( type ) { + var self = this, + records, + findAllPromise = this._getAllPromise( type ); + + if( findAllPromise ){ + return findAllPromise; + } + + records = self._getAllRecords( type ); + + if( ! records ){ + return false; + } + + return Ember.ArrayProxy.createWithMixins( Ember.PromiseProxyMixin ) + .set( 'promise', new Ember.RSVP.Promise( function( resolve, reject){ + resolve( records); + })); + }, + + /** + * addToCache + * + * @param type + * @param id + * @param findOne + * @param result + * @return {Object|Array} + */ + addToCache: function( type, id, findOne, result ){ + + if( id || findOne ){ + if( result.then ){ + return this.addPromise( type, id, result ); + } else { + return this.addRecord( type, result ); + } + } + + return this.addAllPromise( type, result ); + }, + + /** + * addPromise + * + * @param type + * @param id + * @param promise + * @return {Object} ObjectProxy|PromiseProxyMixin + */ + addPromise: function( type, id, promise ){ + var self = this; + + this._getPromises( type ).get( 'ids' )[ id ] = promise; + + promise.then( function( records ){ + self.addRecord( type, record ); + delete this._getPromises( type ).get( 'ids' )[ id ]; + }); + + return promise; + }, + + /** + * addAllPromise + * + * @param type + * @param promise + * @return {Array} ArrayProxy|PromiseProxyMixin + */ + addAllPromise: function( type, promise ){ + var self = this; + + this._getPromises( type ).set( 'all', promise ); + + promise.then( function( records ){ + self.addRecords( type, records ); + self._getPromises( type ).set( 'all', undefined ); + }, function(){ + self._getPromises( type ).set( 'all', undefined ); + }); + + return promise; + }, + + /** + * addRecord + * + * @param type + * @param record + * @return {Object} + */ + addRecord: function( type, record ) { + var typeRecords = this._getRecords( type ), + id = record.get( 'id' ) || 0; + + typeRecords.ids[ id ] = record; + typeRecords.records.push( record ); + + return record; + }, + + /** + * addRecords + * + * @param type + * @param records + * @return {Array} + */ + addRecords: function( type, records ) { + var self = this; + + return records.map( function( record ) { + return self.addRecord( type, record ); + }); + }, + + /** + * removeRecord + * + * @param type + * @param record + */ + removeRecord: function( type, record ) { + var typeRecords = this.get( '_records.'+type ), + id = record.get( 'id' ), + idx = typeRecords.records.indexOf( record ); + + if( typeRecords ){ + delete typeRecords.ids[ id ]; + typeRecords.records = typeRecords.records.splice(idx, 1); + } + + }, + + /** + * removeRecords + * + * @param type + * @param records + */ + removeRecords: function( type, records ) { + var self = this; + + records.map( function( record ) { + self.removeRecord( type, record ); + }); + }, + + /** + * clearCache + * + * @param type + */ + clearCache: function( type ){ + this._initializeRecords( type ); + this._initializePromises( type ); + } + +}); diff --git a/lib/model.js b/addon/model.js similarity index 99% rename from lib/model.js rename to addon/model.js index e80089f..6175cad 100755 --- a/lib/model.js +++ b/addon/model.js @@ -54,7 +54,7 @@ var Model = Ember.ObjectProxy.extend({ Ember.assert( 'Enpoint must be configured on '+this.toString()+' before calling deleteRecord.', endpoint ); return this.container.lookup( 'adapter:'+this.constructor.adapter ).deleteRecord( endpoint, this.get( 'id' ) ) - .then( function( response ){ + .then( function(){ Ember.run(this, 'destroy'); }.bind( this ), null, 'sl-model.model:deleteRecord' ); } diff --git a/lib/store.js b/addon/store.js similarity index 88% rename from lib/store.js rename to addon/store.js index 74bfb77..f76f5c7 100755 --- a/lib/store.js +++ b/addon/store.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import cache from './cache'; /** * SL-Model/Store @@ -8,6 +9,10 @@ import Ember from 'ember'; */ export default Ember.Object.extend({ + setupcache: function(){ + this.set( '_cache', cache.create() ); + }.on( 'init'), + /** * preQueryHooks is an array of functions to be run before an adapter runs a query * @@ -91,8 +96,10 @@ export default Ember.Object.extend({ singularize: function( word ){ var inflectionDict = this.get( '_inflectionDict' ), foundDef = inflectionDict.keys().reduce( function( word, key ){ - var def = inflectionDict.get( key ); - if( RegExp( '^'+word ).test( def ) ){ + var def = inflectionDict.get( key ), + defRegex = new RegExp( '^'+word ); + + if( defRegex.test( def ) ){ return def; } return word; @@ -160,7 +167,26 @@ export default Ember.Object.extend({ * @return {object} an ember object / array proxy with the promise proxy mixin */ __find: function( type, id, options, findOne ) { - return this.adapterFor( type ).find( type, id, options, findOne ); + var result, + cache = this.get( '_cache' ), + reload = options && options.reload; + + if( reload || !cache.isCached( type, id, findOne )){ + result = this.adapterFor( type ).find( type, id, options, findOne ); + + if( !id || !findOne ){ + cache.clearCache( type ); + } else { + cache.removeRecord( type, id || 0 ); + } + + cache.addToCache( type, id, findOne, result); + + return result; + + } + + return cache.fetch( type, id, findOne ); }, /** diff --git a/app/.gitkeep b/app/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/initializers/main.js b/app/initializers/sl-model.js similarity index 53% rename from lib/initializers/main.js rename to app/initializers/sl-model.js index 9c0e525..0b0e973 100755 --- a/lib/initializers/main.js +++ b/app/initializers/sl-model.js @@ -1,4 +1,6 @@ -module SlModel from 'sl-model'; +import Store from 'sl-model/store'; +import AjaxAdapter from 'sl-model/adapters/ajax'; +import LocalstorageAdapter from 'sl-model/adapters/localstorage'; /** * SL-Model/initializers/main @@ -11,17 +13,17 @@ export default { name: 'sl-model', initialize: function ( container, application ) { - var LocalstorageAdapter = SlModel.LocalstorageAdapter.extend(); + var localstorageAdapter = LocalstorageAdapter.extend(); - LocalstorageAdapter.reopenClass({ + localstorageAdapter.reopenClass({ namespace: container.lookup('application:main').get('modulePrefix') }); - container.register('store:main', SlModel.Store ); + container.register('store:main', Store ); - container.register('adapter:ajax', SlModel.AjaxAdapter ); + container.register('adapter:ajax', AjaxAdapter ); - container.register('adapter:localstorage', LocalstorageAdapter ); + container.register('adapter:localstorage', localstorageAdapter ); application.inject('controller', 'store', 'store:main'); diff --git a/bower.json b/bower.json old mode 100755 new mode 100644 index 7030272..a092aa7 --- a/bower.json +++ b/bower.json @@ -1,35 +1,16 @@ { - "name": "sl-model", - "version": "0.1.5", - "authors": [ - "Matthew Marcum " - ], - "description": "", - "main": "dist/sl-model.js", - "keywords": [], - "license": "?", - "private": true, - "ignore": [ - "**/.*", - "node_modules", - "vendor" - ], + "name": "dummy", "dependencies": { - "loader.js": "~1.0.0", - "sl-modelize": "git@gitlab.softlayer.local:interface/sl-modelize.git", - "ic-ajax": "~2.0.1", - "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.2" - }, - "devDependencies": { - "ember": "~1.6.0", - "ember-resolver": "stefanpenner/ember-jj-abrams-resolver#master", + "handlebars": "~1.3.0", + "jquery": "^1.11.1", + "ember": "1.7.0", + "ember-resolver": "~0.1.7", + "loader": "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", - "sinonjs": "~1.10.2", - "sinon-chai": "~2.5.0", - "mocha": "~1.20.1", - "chai": "~1.9.1", - "chai-as-promised": "~4.1.1", - "ember-mocha-adapter": "~0.2.0", - "ember-qunit": "~0.1.8" + "ember-qunit": "0.1.8", + "ember-qunit-notifications": "0.0.4", + "qunit": "~1.15.0" } } diff --git a/dist/sl-model.js b/dist/sl-model.js deleted file mode 100644 index acd274f..0000000 --- a/dist/sl-model.js +++ /dev/null @@ -1,1004 +0,0 @@ -define("sl-model/adapter", - ["sl-modelize","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var ModelizeMixin = __dependency1__["default"] || __dependency1__; - - /** - * SL-Model/adapter - * - * - * @class adapter - */ - __exports__["default"] = Ember.Object.extend( ModelizeMixin, { - - /** - * Run Pre Query Hooks - * @public - * @method runPreQueryHooks - * @param {object} query an object containing data about the query to be run - */ - runPreQueryHooks: function( query ){ - this.get( 'container' ).lookup( 'store:main' ).runPreQueryHooks( query ); - }, - - /** - * Run Post Query Hooks - * @public - * @method runPostQueryHooks - * @param {object} response an object containing the reponse data - */ - runPostQueryHooks: function( response ){ - this.get( 'container' ).lookup( 'store:main' ).runPostQueryHooks( response ); - }, - - /** - * find place holder function - to be overwritten by child classes - * @public - * @method find - */ - find: function(){ - Ember.assert( 'Your model should overwrite adapterType', true); - } - }); - }); -define("sl-model/adapters/ajax", - ["ember","../adapter","ic-ajax","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"] || __dependency1__; - var Adapter = __dependency2__["default"] || __dependency2__; - var icAjax = __dependency3__; - - /** - * SL-Model/adapters/ajax - * - * - * @class adapters_ajax - */ - __exports__["default"] = Adapter.extend({ - - - /** - * find - * @public - * @method find - * @param {string} type model name - * @param {int} id record id - * @param {object} options hash of options - * @param {bool} findOne force return of single recrord - * @return { ObjectProxy | ArrayProxy } The record or array of records requested - */ - find: function ( type, id, options, findOne ){ - - var url, - cacheKey, - cachedModel, - results, - cachedRequest, - promise, - initialObj = {}, - queryObj, - store = this.get( 'store' ), - model = store.modelFor( type ); - - options = options || {}; - - url = model.getUrlForEndpointAction( options.endpoint, 'get' ); - - Ember.assert('A url is required to find a model', url); - - if ( ! Ember.isNone( id ) ) { - options.data = options.data || {}; - options.data.id = parseInt( id, 10 ); - } - - //set up the results, either an object or an array proxy w/ promise mixin - results = ( ( options.data && options.data.id ) || findOne ) ? - Ember.ObjectProxy.createWithMixins( Ember.PromiseProxyMixin ) : - Ember.ArrayProxy.createWithMixins( Ember.PromiseProxyMixin ); - - queryObj = { - dataType : 'json', - url : url, - data : options.data, - context : this - }; - - this.runPreQueryHooks( queryObj ); - - promise = icAjax.request( queryObj ) - - .then( function ajaxAdapterFindTransformResponse( response ){ - - var tmpResult; - - //since serializer will probably be overwritten by a child class, - //need to make sure it is called in the proper context so _super functionality will work - response = model.callSerializerForEndpointAction( options.endpoint, 'get', response, store ); - - //run the modelize mixin to map keys to models - response = this.modelize( response ); - - if ( results instanceof Ember.ArrayProxy ) { - //reject if the response if empty - if( ! response.length ){ - throw { message: 'No objects found' }; - } - - tmpResult = Ember.A([]); - Ember.makeArray( response ).forEach( function ( child ) { - tmpResult.pushObject( store.createRecord( type, child ) ); - }, this ); - - }else{ - tmpResult = store.createRecord( type, response ); - } - - return tmpResult; - - }.bind( this ) , null, 'sl-model.ajaxAdapter:find - then' ) - - .catch( function ajaxAdapterFindCatch( response ) { - var errorData = { - 'statusCode' : response.status, - 'statusText' : response.statusText, - 'message' : response.responseJSON && response.responseJSON.error || "Service Unavailable" - }; - - throw errorData; - - }.bind( this ), 'sl-model.ajaxAdapter:find - catch' ) - - .finally( function ajaxAdapaterFindFinally( response ) { - - //run post query hooks - this.runPostQueryHooks( response ); - - }.bind( this ), 'sl-model.ajaxAdapter:find - finally'); - - //set the promise on the promiseProxy - results.set( 'promise', promise ); - - return results; - }, - - /** - * Delete record - * - * @public - * @method deleteRecord - * @param {string} url the url to send the DELETE command to - * @param {integer} id - * @return {object} Promise - */ - deleteRecord: function( url, id ) { - - Ember.assert('A url is required to delete a model', url); - - return icAjax.request({ - url : url, - type : 'DELETE', - data : JSON.stringify({ id: id }), - context: this - }) - .finally( function ajaxAdapterDeleteFinally( response ) { - this.runPostQueryHooks( response ); - }.bind( this ) , 'sl-model.ajaxAdapter:deleteRecord - always '); - }, - - /** - * Save record - * - * @public - * @method save - * @param url - * @param context - * @return {object} Promise - */ - save: function( url, content ) { - var promise, - result; - - Ember.assert('A url property is required to save a model', url); - - promise = icAjax.request({ - url : url, - type : 'POST', - data : JSON.stringify( content ), - context : this - }) - - .then( function ajaxAdapterSaveResponse( response ) { - //run the modelize mixin to map keys to models - return this.modelize( response ); - - }.bind( this ), null, 'sl-model:save - then' ) - - .catch( function ajaxAdapterSaveCatch( jqxhr, textStatus, error ) { - var errorData = { - 'statusCode' : jqxhr.status, - 'statusText' : jqxhr.statusText, - 'message' : jqxhr.responseJSON && jqxhr.responseJSON.error || "Service Unavailable", - 'details' : jqxhr.responseJSON && jqxhr.responseJSON.details || "Service Unavailable" - }; - - return errorData; - - }.bind( this ), 'sl-model:save - catch' ) - - .finally( function ajaxAdapterSaveFinally( response ) { - this.runPostQueryHooks( response ); - - }.bind( this ), 'sl-model.ajaxAdapter:save - finally' ); - - - return promise; - - } - }); - }); -define("sl-model/adapters/localstorage", - ["ember","../adapter","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"] || __dependency1__; - var Adapter = __dependency2__["default"] || __dependency2__; - - /** - * SL-Model/adapters/localstorage - * - * - * @class adapters_localstorage - */ - var LocalStorageAdapter = Adapter.extend({ - /** - * find - * @public - * @method find - * @param {int} id record id - * @param {object} options hash of options - * @param {bool} findOne force return of single recrord - * @return { ObjectProxy | ArrayProxy } The record or array of records requested - */ - find: function ( type, id, options, findOne ){ - var url, - results, - promise, - queryObj, - store = this.get( 'store' ), - model = store.modelFor( type ); - - options = options || {}; - - url = model.getUrlForEndpointAction( options.endpoint, 'get' ); - - Ember.assert('A url is required to find a model', url); - - if ( ! Ember.isNone( id ) ) { - options.data = options.data || {}; - options.data.id = parseInt( id, 10 ); - } - - //set up the results, either an object or an array proxy w/ promise mixin - results = ( ( options.data && options.data.id ) || findOne ) ? - Ember.ObjectProxy.createWithMixins( Ember.PromiseProxyMixin ) : - Ember.ArrayProxy.createWithMixins( Ember.PromiseProxyMixin ); - - queryObj = { - id: id - }; - - this.runPreQueryHooks( queryObj ); - - promise = new Ember.RSVP.Promise( function( resolve, reject){ - //todo actual localStorage query - var db, - modelKey, - records, - response, - finalResult; - - db = this._getDb(); - - records = this._getRecords( db, url ); - - if( options.data && options.data.id ){ - response = records.findBy( 'id', options.data.id ); - } - else if( findOne ){ - //we aren't doing queries based on options at this time, - //can add here in the future if needed. - response = records[0]; - } - else { - response = records; - if( ! response.length ){ - reject(); - } - } - - if( ! response ){ - reject(); - } - - response = model.callSerializerForEndpointAction( options.endpoint, 'get', response, store ); - - response = this.modelize( response ); - - if ( results instanceof Ember.ArrayProxy ) { - finalResult = Ember.A([]); - Ember.makeArray( response ).forEach( function ( child ) { - finalResult.pushObject( store.createRecord( type, child ) ); - }, this ); - }else{ - finalResult = store.createRecord( type, response ); - } - - resolve( finalResult ); - - }.bind( this ), 'sl-model.localstorageAdapter:find - Promise '); - - promise.finally( function lsAdapaterFindFinally( response ) { - - - //run post query hooks - this.runPostQueryHooks( response ); - - }.bind( this ), 'sl-model.localstorageAdapter:find - finally'); - - - //set the promise on the promiseProxy - results.set( 'promise', promise ); - - return results; - - }, - /** - * Delete record - * - * @public - * @method deleteRecord - * @param {string} url the url to send the DELETE command to - * @param {object} context - * @return {object} Promise - */ - deleteRecord: function( url, id ) { - var promise; - - Ember.assert('A url is required to delete a model', url); - - promise = new Ember.RSVP.Promise( function( resolve, reject ){ - var db, - records, - errorData, - recordIndex; - - db = this._getDb(); - - records = this._getRecords( db, url ); - - recordIndex = this._getRecordIndexById( records, id ); - - if( recordIndex >= 0 ){ - records.splice( recordIndex, 1 ); - }else{ - errorData = { - statusCode: 404, - statusText: 'id: '+id+' not found at '+url, - message: 'The record with id: `'+id+'` was not found at url:'+url - }; - reject( errorData ); - } - - this._dbWrite( db ); - - resolve(); - - }.bind( this )); - - promise.finally( function lsAdapterDeleteFinally( response ) { - this.runPostQueryHooks( response ); - }.bind( this ) , 'sl-model.localstorageAdapter:deleteRecord - always '); - - return promise; - }, - - /** - * Save record - * - * @public - * @method save - * @param url - * @param context - * @return {object} Promise - */ - save: function( url, content ) { - var promise; - - Ember.assert('A url is required to delete a model', url); - - promise = new Ember.RSVP.Promise( function( resolve, reject ){ - var db, - records, - recordIndex; - - db = this._getDb(); - - records = this._getRecords( db, url ); - - recordIndex = this._getRecordIndexById( records, content.id ); - if( recordIndex >= 0 ){ - records.splice( recordIndex, 1 ); - } - - records.push( content ); - - this._dbWrite( db ); - - resolve( content ); - - }.bind( this )); - - promise.finally( function lsAdapterSaveFinally( response ) { - this.runPostQueryHooks( response ); - }.bind( this ) , 'sl-model.localstorageAdapter:saveRecord - always '); - - return promise; - }, - - /** - * return the adapter's namespace - * @method getNamespace - * @return {string} namespace - */ - getNamespace: function(){ - return this.constructor.namespace; - }, - - /** - * method to get localStorage object, useful for testing - * @private - * @method _getLocalStorage - * @return {object} localStorage or mockup - */ - _getLocalStorage: function(){ - return this.get( 'localStorageMockup' ) || window.localStorage; - }, - - /** - * get the db off of localStorage - * - * @private - * @method _getDb - * - */ - _getDb: function(){ - var lsDb = this._getLocalStorage().getItem( this.getNamespace() ); - if( lsDb ){ - return JSON.parse( lsDb ); - } - - return {}; - }, - - /** - * write the db to localStorage - * - * @private - * @method _dbWrite - */ - _dbWrite: function( db ){ - this._getLocalStorage().setItem( this.getNamespace(), JSON.stringify( db )); - }, - - /** - * return the records for a specific model url - * @method _getRecords - * @param {object} db the object to find the records on - * @param {string} url the key - * @return {array} records - */ - _getRecords: function( db, url ){ - var modelKey = this._normalizeUrl( url ), - records = db[ modelKey ]; - - if( ! records ){ - records = db[ modelKey ] = Ember.A([]); - } - - return records; - }, - - /** - * return the - * @method _getRecordIndexById - * @param {Array} records array to search - * @param {integer} id id to search for - * @return {integer} -1 if not found - */ - _getRecordIndexById: function( records, id ){ - var recordIndex = -1; - if( Array.isArray( records ) ){ - records.forEach( function( item, index ){ - if( item.id === id ){ - recordIndex = index; - } - }); - } - - return recordIndex; - }, - - /** - * normalize a url for using as a key - * @method _normalizeUrl - * @param {string} url - * @return {string} normalized url - */ - _normalizeUrl: function( url ){ - return url.replace(/^\//, '').replace('\/','_'); - } - }); - - LocalStorageAdapter.reopenClass({ - namespace: 'sl-model' - }); - - __exports__["default"] = LocalStorageAdapter; - }); -define("sl-model/initializers/main", - ["sl-model","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var SlModel = __dependency1__; - - /** - * SL-Model/initializers/main - * - * - * @class initializers_main - */ - __exports__["default"] = { - - name: 'sl-model', - - initialize: function ( container, application ) { - var LocalstorageAdapter = SlModel.LocalstorageAdapter.extend(); - - LocalstorageAdapter.reopenClass({ - namespace: container.lookup('application:main').get('modulePrefix') - }); - - container.register('store:main', SlModel.Store ); - - container.register('adapter:ajax', SlModel.AjaxAdapter ); - - container.register('adapter:localstorage', LocalstorageAdapter ); - - application.inject('controller', 'store', 'store:main'); - - application.inject('route', 'store', 'store:main'); - - application.inject('adapter', 'store', 'store:main'); - - } - }; - }); -define("sl-model", - ["./model","./store","./adapter","./adapters/ajax","./adapters/localstorage","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Model = __dependency1__["default"] || __dependency1__; - var Store = __dependency2__["default"] || __dependency2__; - var Adapter = __dependency3__["default"] || __dependency3__; - var AjaxAdapter = __dependency4__["default"] || __dependency4__; - var LocalstorageAdapter = __dependency5__["default"] || __dependency5__; - - /** - * SL-Model exports sl-model/model as its default export. - * - * This allows you to do: - * - * ```javascript - * import SlModel from 'sl-model' - * - * export default SlModel.extend({}) - *``` - * In your model files. - * - * @class sl-model - */ - __exports__["default"] = Model; - - __exports__.Model = Model; - __exports__.Store = Store; - __exports__.Adapter = Adapter; - __exports__.AjaxAdapter = AjaxAdapter; - __exports__.LocalstorageAdapter = LocalstorageAdapter; - }); -define("sl-model/model", - ["ember","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"] || __dependency1__; - - var get = Ember.get; - - /** - * SL-Model/Model - * - * - * @class model - */ - var Model = Ember.ObjectProxy.extend({ - - /** - * Save the contents via the configured adapter - * - * @public - * @method save - */ - save: function( options ) { - var data, - endpoint; - - options = options || {}; - - endpoint = this.constructor.getUrlForEndpointAction( options.endpoint, 'post' ); - - data = this.get( 'content' ); - - Ember.assert( 'Endpoint must be configured on '+this.toString()+' before calling save.', endpoint ); - - - return this.container.lookup( 'adapter:'+this.constructor.adapter ).save( endpoint, data ) - .then( function( response ){ - this.set( 'content', response ); - return this; - }.bind( this ), null, 'sl-model.model:save'); - }, - - /** - * Delete the record via the configured adapter - * - * @public - * @method deleteRecord - * @param {object} optional - * @return {object} jqXHR from jQuery.ajax() - */ - deleteRecord: function( options ) { - var endpoint; - - options = options || {}; - - endpoint = this.constructor.getUrlForEndpointAction( options.endpoint, 'delete' ); - - Ember.assert( 'Enpoint must be configured on '+this.toString()+' before calling deleteRecord.', endpoint ); - - return this.container.lookup( 'adapter:'+this.constructor.adapter ).deleteRecord( endpoint, this.get( 'id' ) ) - .then( function( response ){ - Ember.run(this, 'destroy'); - }.bind( this ), null, 'sl-model.model:deleteRecord' ); - } - }); - - Model.reopenClass({ - - /** - * the default url for this class - * @type {string} - */ - url: null, - - /** - * the default serializer - * @method serializer - * @param {object} response data to be serialized - * @return {object} serialized data - */ - serializer: function( response ){ return response; }, - - /** - * the default adapter, currently either 'ajax' or 'localstorage' - * @type {String} - */ - adapter: "ajax", - - /** - * resolves the url by walking down the endpoints object and defaulting to the root:url string - * @method getUrlForEndpointAction - * @param {string} endpoint the endpoint, leave blank or null for default - * @param {string} action the action, leave blank or null for default - * @return {string} resolved url - */ - getUrlForEndpointAction: function( endpoint, action ) { - var resolvedEndpoint, - testEndpoint; - - endpoint = endpoint || 'default'; - - testEndpoint = get( this, 'endpoints.'+endpoint+'.'+action ) || get( this, 'endpoints.'+endpoint ) || {}; - - if( typeof testEndpoint === 'string' ){ - resolvedEndpoint = testEndpoint; - } else { - resolvedEndpoint = get( testEndpoint, 'url' ) || get( this, 'url' ); - } - - Ember.assert( 'A url needs to be set for '+this.toString(), resolvedEndpoint ); - - return resolvedEndpoint; - }, - - /** - * calls the serializer for the specified endpoint and actions - * @method callSerializerForEndpointAction - * @param {string} endpoint - * @param {string} action - * @param {object} data the data to be serialized - * @param {object} store the app's store, use to store metadata - * @return {object} the serialized data - */ - callSerializerForEndpointAction: function( endpoint, action, data, store ) { - var resolvedSerializer, - testEndpoint, - defaultSerializer; - - endpoint = endpoint || 'default'; - testEndpoint = get( this, 'endpoints.'+endpoint+'.'+action ) || get( this, 'endpoints.'+endpoint ) || {}; - defaultSerializer = get( this, 'endpoints.default.'+action+'.serializer' ) || - get( this, 'endpoints.default.serializer' ) || - get( this, 'serializer' ); - - if( typeof testEndpoint === 'string' ){ - resolvedSerializer = defaultSerializer; - } else { - resolvedSerializer = get( testEndpoint, 'serializer' ) || defaultSerializer; - } - - Ember.assert( 'A serializer needs to be set for '+this.toString(), resolvedSerializer ); - - return resolvedSerializer.call( this, data, store ); - } - - }); - - __exports__["default"] = Model; - }); -define("sl-model/store", - ["ember","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"] || __dependency1__; - - /** - * SL-Model/Store - * - * - * @class store - */ - __exports__["default"] = Ember.Object.extend({ - - /** - * preQueryHooks is an array of functions to be run before an adapter runs a query - * - * @property preQueryHooks - * @type {Array} - */ - preQueryHooks: Ember.A([]), - - /** - * postQueryHooks is an array of functions to be run after an adapter runs a query - * - * @property postQueryHooks - * @type {Array} - */ - postQueryHooks: Ember.A([]), - - /** - * modelFor returns the model class for a given model type - * - * @public - * @method modelFor - * @type {method} - * @param {string} type lower case name of the model class - * @return {function} - model constructor - */ - modelFor: function( type ){ - var normalizedKey = this.container.normalize( 'model:'+type ), - factory = this.container.lookupFactory( normalizedKey ); - - Ember.assert( "No model was found for `"+type+"`", factory ); - - return factory; - }, - - /** - * private variable that store all the metadata for all the models - * - * @property _metadataCache - * @private - * @type {Object} - */ - _metadataCache: {}, - - /** - * metaForType sets the metadata object for the specified model type - * @method metaForType - * @public - * @param {string} type the lowercase model name - * @param {object} metadata the metadata to save - */ - metaForType: function( type, metadata ){ - this.set( '_metadataCache.'+type, metadata ); - }, - - /** - * metadataFor returns the metadata object for the specified model type - * @method metadataFor - * @public - * @param {string} type lower case model name - * @return {object} the metadata object that was saved with metaForType - */ - metadataFor: function( type ){ - return this.get( '_metadataCache.'+type ); - }, - - - /** - * private variable that stores the inflection dictionary for non - * standard words - * - * @property _inflectionDict - * @private - * @type {object} - */ - _inflectionDict: {}, - - pluralize: function( word ){ - return this.get( '_inflectionDict.'+word ) || word.match(/s$/) ? word+'es' : word+'s'; - }, - - singularize: function( word ){ - var inflectionDict = this.get( '_inflectionDict' ), - foundDef = inflectionDict.keys().reduce( function( word, key ){ - var def = inflectionDict.get( key ); - if( RegExp( '^'+word ).test( def ) ){ - return def; - } - return word; - }); - return foundDef || word.replace( /s$/, '' ); - }, - - defineInflection: function( word, pluralizedWord ){ - this.set( '_inflectionDict.'+word, pluralizedWord ); - }, - - /** - * adapterFor returns the configured adapter for the specified model type - * @method adapterFor - * @public - * @param {string} type the lower case name of the model class - * @return {object} the adapter singleton - */ - adapterFor: function( type ){ - var adapterType = this.modelFor(type).adapter, - adapter = this.container.lookup( 'adapter:'+adapterType ); - - return adapter; - }, - - /** - * findOne returns an object proxy, does not use an id to perform a lookup (use the options obj instead). - * @method findOne - * @public - * @param {string} type lower case name of the model - * @param {Object} options hash of options to be passed on to the adapter - * @return {Object} Ember.ObjectProxy - */ - findOne: function( type, options ) { - return this.__find( type, null, options, true ); - }, - - /** - * find a/an record(s) using an id or options - * @method find - * @public - * @param {string} type lower case name of the model class - * @param {int} id - * @param {object} options hash of options to be passed on to the adapter - * @return {object / array} an object or an array depending on whether you specified an id - */ - find: function( type, id, options ) { - if( typeof id === 'object' && typeof options === 'undefined' ){ - return this.__find( type, null, id, false ); - } - if( typeof id === 'undefined' && typeof options === 'undefined' ){ - return this.__find( type, null, null, false ); - } - return this.__find( type, id, options, false ); - }, - - /** - * private find method - * @private - * @method __find - * @param {string} type lowercase model name - * @param {integer / string} id record identifier - * @param {object} options objects containing all options for query - * @param {boolean} findOne force the retrieval of a single record - * @return {object} an ember object / array proxy with the promise proxy mixin - */ - __find: function( type, id, options, findOne ) { - return this.adapterFor( type ).find( type, id, options, findOne ); - }, - - /** - * create a new record, it will not have been saved via an adapter yet - * @method createRecord - * @public - * @param {string} type lower case name of model class - * @return {object} model object, instance of Ember.ObjectProxy - */ - createRecord: function( type, content ){ - var factory = this.modelFor( type ), - record = factory.create( { - container: this.get( 'container' ) - } ); - - record.set( 'content', content || {} ); - - return record; - }, - - /** - * registerPreQueryHook add a function to ther prequery hooks array - * - * @method registerPreQueryHook - * @public - * @param {function} f a function - * - */ - registerPreQueryHook: function( f ){ - this.get( 'preQueryHooks' ).push( f ); - }, - - /** - * runPreQueryHooks - * @method runPreQueryHooks - * @public - * @param {object} query - */ - runPreQueryHooks: function( query ){ - var preQueryHooks = this.get( 'preQueryHooks' ); - if( Ember.isArray( preQueryHooks ) ){ - preQueryHooks.forEach( function( f ){ f( query ); } ); - } - }, - - /** - * registerPostQueryHook add a function to the postquery array - * @method registerPostQueryHook - * @public - * @param {function} f function to be run after a query - */ - registerPostQueryHook: function( f ){ - this.get( 'postQueryHooks' ).push( f ); - }, - - /** - * runPostQueryHooks call the post query hooks with the response obj - * @method runPostQueryHooks - * @public - * @param {object} response the response from the adapter - */ - runPostQueryHooks: function( response ){ - var postQueryHooks = this.get( 'postQueryHooks' ); - if( Ember.isArray( postQueryHooks ) ){ - postQueryHooks.forEach( function( f ){ f( response ); } ); - } - }, - }); - }); \ No newline at end of file diff --git a/ember-addon/main.js b/ember-addon/main.js deleted file mode 100755 index ab6e439..0000000 --- a/ember-addon/main.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; - -function SlModel( project ) { - this.project = project; - this.name = 'Sl-Model'; -} - -function unwatchedTree(dir) { - return { - read: function() { return dir; }, - cleanup: function() { } - }; -} - -SlModel.prototype.treeFor = function treeFor( name ) { - var path = require('path'), - slmodelPath = path.join( 'node_modules', 'sl-model' ), - testTree, - vendorTree, - appTree, - mergeTrees = require( 'broccoli-merge-trees' ), - pickFiles = require( 'broccoli-static-compiler' ); - - if( name === 'vendor' ) { - vendorTree = mergeTrees([ - pickFiles( path.join( slmodelPath, 'node_modules', 'sl-modelize', 'dist' ), { - srcDir : '/', - destDir : 'sl-modelize' - } - ), - pickFiles( path.join( slmodelPath, 'dist' ), { - srcDir : '/', - destDir : 'sl-model' - } - ) - ]); - - return vendorTree; - - } else if ( name === 'app' ) { - appTree = pickFiles( path.join( slmodelPath, 'lib', 'initializers' ), { - srcDir: '/', - files: [ 'main.js' ], - destDir : '/initializers' - } ); - - return appTree; - } -}; - -SlModel.prototype.blueprintsPath = function() { - var path = require( 'path' ); - return path.join( 'node_modules', 'sl-model', 'blueprints' ); -}; - -SlModel.prototype.included = function included( app ) { - this.app = app; - - this.app.import( 'vendor/sl-model/sl-model.js', { - exports: { - 'sl-model': [ - 'default', - 'store', - 'adapter', - 'adapter/ajax', - 'adapter/localstorage' - ] - } - }); - this.app.import( 'vendor/sl-modelize/sl-modelize.js' ); -}; - - -module.exports = SlModel; diff --git a/index.js b/index.js new file mode 100644 index 0000000..51f0f83 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +module.exports = { + name: 'sl-model' +}; diff --git a/lib/main.js b/lib/main.js deleted file mode 100755 index f0b2ff6..0000000 --- a/lib/main.js +++ /dev/null @@ -1,29 +0,0 @@ -import Model from "./model"; -import Store from "./store"; -import Adapter from "./adapter"; -import AjaxAdapter from "./adapters/ajax"; -import LocalstorageAdapter from "./adapters/localstorage"; - -/** - * SL-Model exports sl-model/model as its default export. - * - * This allows you to do: - * - * ```javascript - * import SlModel from 'sl-model' - * - * export default SlModel.extend({}) - *``` - * In your model files. - * - * @class sl-model - */ -export default Model; - -export { - Model, - Store, - Adapter, - AjaxAdapter, - LocalstorageAdapter -}; diff --git a/package.json b/package.json old mode 100755 new mode 100644 index b350957..236127e --- a/package.json +++ b/package.json @@ -1,41 +1,40 @@ { "name": "sl-model", - "version": "0.1.5", - "description": "", - "main": "lib/sl-model.js", - "ember-addon": { - "main": "ember-addon/main.js" + "version": "0.0.0", + "directories": { + "doc": "doc", + "test": "test" }, "scripts": { - "test": "./testrunner.js", - "release": "rm -rf dist;broccoli build dist;", - "docs": "yuidoc ." + "start": "ember server", + "build": "ember build", + "test": "ember test" }, - "repository": { - "type": "git", - "url": "git@gitlab.softlayer.local:interface/sl-model.git" + "repository": "https://github.com/stefanpenner/ember-cli", + "engines": { + "node": ">= 0.10.0" }, - "keywords": [ "ember-addon" ], - "author": "Matt Marcum", - "license": "", - - "dependencies": { - "broccoli-merge-trees": "", - "broccoli-static-compiler": "", - "ic-ajax": "1.0.4", - "rsvp": "^3.0.6", - "sl-modelize": "git+ssh://git@gitlab.softlayer.local:interface/sl-modelize.git#master" + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "configPath": "tests/dummy/config" }, + "author": "", + "license": "MIT", "devDependencies": { - "broccoli": "^0.12.2", - "broccoli-cli": "^0.0.1", - "broccoli-concat": "0.0.6", - "broccoli-es6-module-filter": "^0.1.9", - "broccoli-export-tree": "0.3.1", - "chai": "^1.9.1", - "chai-as-promised": "^4.1.1", - "mocha": "^1.18.0", - "bower": "^1.2.8", - "testem": "0.6.15" + "body-parser": "^1.2.0", + "broccoli-asset-rev": "0.0.17", + "broccoli-ember-hbs-template-compiler": "^1.6.1", + "connect-restreamer": "^1.0.0", + "ember-cli": "0.0.44", + "ember-cli-ember-data": "0.1.0", + "ember-cli-ic-ajax": "0.1.1", + "ember-cli-qunit": "0.0.5", + "express": "^4.8.5", + "glob": "^4.0.5" + }, + "dependencies": { + "sl-modelize": "git+ssh://git@gitlab.softlayer.local:mmarcum/sl-modelize.git" } -} \ No newline at end of file +} diff --git a/server/.jshintrc b/server/.jshintrc new file mode 100644 index 0000000..c1f2978 --- /dev/null +++ b/server/.jshintrc @@ -0,0 +1,3 @@ +{ + "node": true +} diff --git a/server/index.js b/server/index.js new file mode 100644 index 0000000..49a4bff --- /dev/null +++ b/server/index.js @@ -0,0 +1,20 @@ +module.exports = function(app) { + var globSync = require('glob').sync; + var bodyParser = require('body-parser'); + var mocks = globSync('./mocks/**/*.js', { cwd: __dirname }).map(require); + var proxies = globSync('./proxies/**/*.js', { cwd: __dirname }).map(require); + + app.use(bodyParser.json()); + app.use(bodyParser.urlencoded({ + extended: true + })); + + mocks.forEach(function(route) { route(app); }); + + // proxy expects a stream, but express will have turned + // the request stream into an object because bodyParser + // has run. We have to convert it back to stream: + // https://github.com/nodejitsu/node-http-proxy/issues/180 + app.use(require('connect-restreamer')()); + proxies.forEach(function(route) { route(app); }); +}; diff --git a/server/mocks/test.js b/server/mocks/test.js new file mode 100644 index 0000000..c75dde8 --- /dev/null +++ b/server/mocks/test.js @@ -0,0 +1,21 @@ +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/test-helpers/module-for-sl-model.js b/test-support/module-for-sl-model.js similarity index 87% rename from test-helpers/module-for-sl-model.js rename to test-support/module-for-sl-model.js index 97acbbe..dc5972b 100644 --- a/test-helpers/module-for-sl-model.js +++ b/test-support/module-for-sl-model.js @@ -1,13 +1,13 @@ import { moduleFor } from 'ember-qunit'; import Ember from 'ember'; -module SlModel from 'sl-model'; +import SlModelStore from 'sl-model/store'; export default function moduleForSlModel(name, description, callbacks) { moduleFor('model:' + name, description, callbacks, function(container, context, defaultSubject) { - container.register('store:main', SlModel.Store ); + container.register('store:main', SlModelStore ); context.__setup_properties__.store = function(){ return container.lookup('store:main'); diff --git a/test/integration-tests.js b/test/integration-tests.js deleted file mode 100644 index 60e9ec3..0000000 --- a/test/integration-tests.js +++ /dev/null @@ -1,6 +0,0 @@ -Object.keys(require.entries).forEach(function(entry){ - if ( (/integration/).test(entry) ) { - console.log( 'running:', entry ); - require(entry, null, null, true); - } -}); \ No newline at end of file diff --git a/test/integration/main.js b/test/integration/main.js deleted file mode 100644 index a4ee7eb..0000000 --- a/test/integration/main.js +++ /dev/null @@ -1,309 +0,0 @@ -import Resolver from "ember/resolver"; -import loadInitializers from 'ember/load-initializers'; -import slModelInitializer from "sl-model/initializers/main"; -import SlModel from "sl-model"; - -module icAjax from 'ic-ajax'; - -var expect = chai.expect, - defineFixture = icAjax.defineFixture, - lookupFixture = icAjax.lookupFixture, - AppClass, - App, - localStorage, - initializerSpy, - container, - store, - Foo, - fooResponse, - Bar, - barResponse, - Car, - carResponse, - superCarResponse, - crappyCarResponse, - Dog, - dog; - -App = Ember.Application.create({ - modulePrefix: 'SlModelTest', - Resolver: Resolver, - rootElement: '#SlModelTest', - testing: true -}); - -App.setupForTesting(); -App.injectTestHelpers(); - -initializerSpy = sinon.spy( slModelInitializer, 'initialize' ); - -loadInitializers( App, 'sl-model' ); - -localStorage = { - _ns: 'testLSObject', - setItem: function( item, content ){ - this[item] = content; - }, - getItem: function( item ){ - return this[item]; - } - }; - -//set up models -define('SlModelTest/models/foo', [] , function(){ - Foo = SlModel.extend(); - Foo.reopenClass({ url: '/foo' }); - return Foo; -}); -define('SlModelTest/models/bar', [] , function(){ - Bar = SlModel.extend(); - Bar.reopenClass({ url: '/bar' }); - return Bar; -}); -define('SlModelTest/models/car', [ ] , function(){ - Car = SlModel.extend(); - Car.reopenClass({ - url: '/car', - serializer: function( response, store ){ - return response.response; - }, - endpoints: { - 'superCar': '/superCar', - 'crappyCar': { - get: { - url: '/crappyCar', - serializer: function( response, store ){ - return response.cars; - } - } - } - } - - }); - return Car; -}); - -define('SlModelTest/models/dog', [ ] , function(){ - Dog = SlModel.extend(); - Dog.reopenClass({ url: '/dog', adapter: 'localstorage' }); - return Dog; -}); - -//set up icAjax -fooResponse = { id: 1, test: 'foo', 'bar': { id: 1, quiz: 'bar' } }; -barResponse = { id: 1, test: 'bar', 'car': { id: 1, color: 'black' } }; -carResponse = { - response: [ - { id: 1, color: 'blue' }, - { id: 2, color: 'black' }, - { id: 3, color: 'white' } - ], - totalCount: 3, - totalPages: 1 -}; - -superCarResponse = { - response: [ - { id: 11, color: 'super blue' }, - { id: 12, color: 'super black' }, - { id: 13, color: 'super white' } - ], - totalCount: 3, - totalPages: 1 -}; - -crappyCarResponse = { - cars: [ - { id: 21, color: 'dull blue' }, - { id: 22, color: 'washed out black' }, - { id: 23, color: 'dingy white' } - ], - totalCount: 3, - totalPages: 1 -}; - -defineFixture( '/foo', { - response: fooResponse, - jqXHR: {}, - textStatus: 'success' -}); -defineFixture( '/bar', { - response: barResponse, - jqXHR: {}, - textStatus: 'success' -}); -defineFixture( '/car', { - response: carResponse , - jqXHR: {}, - textStatus: 'success' -}); -defineFixture( '/superCar', { - response: superCarResponse, - jqXHR: {}, - textStatus: 'success' -}); -defineFixture( '/crappyCar', { - response: crappyCarResponse, - jqXHR: {}, - textStatus: 'success' -}); - -describe( 'sl-model:Integration', function(){ - beforeEach(function(done){ - //set up ember app - visit( '/' ).then(function(){ - container = App.__container__; - container.lookup('adapter:localstorage').set( 'localStorageMockup', localStorage ); - store = container.lookup( 'store:main'); - done(); - }); - }); - - afterEach( function(){ - App.reset(); - }); - - it( 'should run the initializer', function(){ - initializerSpy.should.have.been.calledOnce; - }); - - it( 'should register the store in the container', function(){ - container.lookup( 'store:main' ).should.exist; - }); - - it( 'should register the ajax adapter in the container', function(){ - container.lookup( 'adapter:ajax' ).should.exist; - }); - - it( 'should inject the store in a route', function(){ - container.lookup( 'route:application' ).get( 'store' ).should.exist; - }); - - it( 'should inject the store in a controller', function(){ - container.lookup( 'controller:application' ).get( 'store' ).should.exist; - }); - - it( 'should create a new record', function(){ - var fooRecord = store.createRecord( 'foo', {test: true}); - fooRecord.get('test').should.equal( true ); - }); - - it( 'should find a single Foo model', function(){ - store.find( 'foo', 1 ).should.eventually.be.instanceof( Foo ); - }); - - it( 'should find a single Foo model with correct content', function( done ){ - var fooRecord = store.find( 'foo', 1 ); - fooRecord.then(function(){ - var ajaxAdapter = container.lookup('adapter:ajax'), - fooModelized = ajaxAdapter.modelize( fooResponse ); - fooRecord.get('content.content').should.deep.equal( fooModelized ); - done(); - },function(err){ - done(err); - }); - }); - - it( 'should find a single Bar model using findOne', function(){ - store.findOne( 'bar' ).should.eventually.be.instanceof( Bar ); - }); - - it( 'should find a single Bar model, using findOne, with correct content', function( done ){ - var barRecord = store.find( 'bar', 1 ); - barRecord.then(function(){ - var ajaxAdapter = container.lookup('adapter:ajax'), - barModelized = ajaxAdapter.modelize( barResponse ); - barRecord.get('content.content').should.deep.equal( barModelized ); - done(); - },function(err){ - done(err); - }); - }); - - it( 'should find an array of Car models', function( done ){ - var cars = store.find( 'car' ) - - cars.should.be.instanceof( Ember.ArrayProxy ); - - cars.then( function(){ - done(); - }).catch( function( reason ){ - done( reason ); - }); - - }); - - it( 'should find an array of Car models, with correct content', function( done ){ - var carRecords = store.find( 'car' ); - carRecords.then(function(){ - var ajaxAdapter = container.lookup('adapter:ajax'), - carModelized = ajaxAdapter.modelize( carResponse ); - expect( carRecords.get('content').mapBy('id') ).to.deep.equal( carModelized.response.mapBy('id') ); - done(); - },function(err){ - done(err); - }); - }); - - - it( 'should find an array of superCar models, with correct content, using an endpoint', function( done ){ - var carRecords = store.find( 'car', { endpoint: 'superCar' } ); - carRecords.then(function(){ - var ajaxAdapter = container.lookup('adapter:ajax'), - carModelized = ajaxAdapter.modelize( superCarResponse ); - expect( carRecords.get('content').mapBy('id') ).to.deep.equal( carModelized.response.mapBy('id') ); - done(); - },function(err){ - done(err); - }); - }); - - it( 'should find an array of crappyCar models, with correct content, using an endpoint', function( done ){ - var carRecords = store.find( 'car', { endpoint: 'crappyCar' } ); - carRecords.then(function(){ - var ajaxAdapter = container.lookup('adapter:ajax'), - carModelized = ajaxAdapter.modelize( crappyCarResponse ); - expect( carRecords.get('content').mapBy('id') ).to.deep.equal( carModelized.cars.mapBy('id') ); - done(); - },function(err){ - done(err); - }); - }); - - it( 'should save a newly created bar and return the model with an id', function( done ){ - var barRecord = store.createRecord( 'bar' ); - barRecord.save().then( function( response ){ - expect( barRecord.get('id') ).to.equal( 1 ); - done(); - }); - }); - - it( 'should destroy a record when calling deleteRecord', function( done ){ - var barRecord = store.createRecord( 'bar', { test: false} ); - - barRecord.set( 'test', true ); - - barRecord.deleteRecord().then( function( response ){ - expect( barRecord.isDestroyed ); - done(); - }); - }); - - it( 'should create a localstorage record', function(){ - var dogRecord = store.createRecord( 'dog', { test: false } ); - dogRecord.get( 'test' ).should.equal( false ); - dogRecord.set( 'test2', 42 ); - dogRecord.get( 'test2' ).should.equal( 42 ); - }); - - it( 'should create a localstorage record and save it', function( done){ - var dogRecord = store.createRecord( 'dog', { test: 42 } ); - dogRecord.save().then(function( result ){ - var foundDog = store.findOne('dog'); - foundDog.then( function(){ - foundDog.get('test').should.equal(42); - done(); - }); - }); - }); -}); diff --git a/test/test.mustache b/test/test.mustache deleted file mode 100644 index 3541685..0000000 --- a/test/test.mustache +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Tests - - - - - - - - - {{#styles}}{{/styles}} - - - -
- - - -
- - - diff --git a/test/unit-tests.js b/test/unit-tests.js deleted file mode 100644 index 48d89ff..0000000 --- a/test/unit-tests.js +++ /dev/null @@ -1,6 +0,0 @@ -Object.keys(require.entries).forEach(function(entry){ - if ( (/unit/).test(entry) ) { - console.log( 'running:', entry ); - require(entry, null, null, true); - } -}); \ No newline at end of file diff --git a/test/unit/adapter.js b/test/unit/adapter.js deleted file mode 100644 index 6601a5c..0000000 --- a/test/unit/adapter.js +++ /dev/null @@ -1,55 +0,0 @@ -import Model from "sl-model"; -import Adapter from 'sl-model/adapter'; - -chai.should(); - -var expect = chai.expect, - adapter= Adapter.create({ - container:{ - lookup: function( type ){ - if( type === 'store:main' ) - return store; - else - Ember.Assert( 'Container could not find "'+type+'"', false); - } - } - }), - store = { - runPostQueryHooks: sinon.spy(), - runPreQueryHooks: sinon.spy() - }; - - -describe( 'sl-model/adapter', function(){ - - describe( 'runPreQueryHooks', function(){ - before(function(){ - adapter.runPreQueryHooks(); - }); - it( 'should run the prequeryhook once', function(){ - store.runPreQueryHooks.should.have.been.calledOnce; - }); - it( 'should not have run postqueryhook', function(){ - store.runPostQueryHooks.should.have.callCount(0); - }); - after(function(){ - store.runPreQueryHooks.reset(); - store.runPostQueryHooks.reset(); - }); - }); - describe( 'runPostQueryHooks', function(){ - before(function(){ - adapter.runPostQueryHooks(); - }); - it( 'should run the postqueryhook once', function(){ - store.runPostQueryHooks.should.have.been.calledOnce; - }); - it( 'should not have run prequeryhook', function(){ - store.runPreQueryHooks.should.have.callCount(0); - }); - after(function(){ - store.runPreQueryHooks.reset(); - store.runPostQueryHooks.reset(); - }); - }); -}); \ No newline at end of file diff --git a/test/unit/adapters/ajax.js b/test/unit/adapters/ajax.js deleted file mode 100644 index 53ab2d4..0000000 --- a/test/unit/adapters/ajax.js +++ /dev/null @@ -1,263 +0,0 @@ -import Model from "sl-model"; -import Adapter from 'sl-model/adapter'; -import Ajaxdapter from 'sl-model/adapters/ajax'; -module icAjax from 'ic-ajax'; - -chai.should(); - -var expect = chai.expect, - ajaxdapter, - store, - container, - Foo = Model.extend(), - Bar = Model.extend(), - Car = Model.extend(), - defineFixture = icAjax.defineFixture, - response, - requestSpy; - -describe( 'sl-model/adapter/ajax', function(){ - - before( function( ){ - - 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 ){ - var item = this.registry.findBy( 'key', key ); - return item ? item.factory : undefined; - } - }; - store = { - container:container, - runPostQueryHooks: sinon.spy(), - runPreQueryHooks: sinon.spy(), - createRecord: function( type, content ){ - var record = this.modelFor( type ).create({conatainer:this.container}).set('content',content); - return record; - }, - modelFor: function( type ){ - return this.container.lookupFactory('model:'+type); - } - }; - - ajaxdapter = Ajaxdapter.create({ - container: container, - store: store - }); - - ajaxdapter.container.registry.push( { key: 'model:foo', factory: Foo } ); - ajaxdapter.container.registry.push( { key: 'model:bar', factory: Bar } ); - ajaxdapter.container.registry.push( { key: 'model:car', factory: Car } ); - ajaxdapter.container.cache['store:main']=store; - - defineFixture( '/foo', { - response: { id: 1, test: 'foo', 'bar': { id: 1, quiz: 'bar' } }, - jqXHR: {}, - testStatus: 'success' - }); - defineFixture( '/bar', { - response: [ { id: 1, quiz: 'bar' }, { id: 2, quiz: 'bar2' } ], - jqXHR: {}, - testStatus: 'success' - }); - defineFixture( '/car', { - response: [], - jqXHR: {}, - testStatus: 'success' - }); - Foo.reopenClass( { url: '/foo'}); - Bar.reopenClass( { url: '/bar'}); - Car.reopenClass( { url: '/car'}); - - //spies - requestSpy = sinon.spy( icAjax, 'request' ); - - }); - - describe( '__find single model with id', function(){ - beforeEach(function( done ){ - //request - response = ajaxdapter.find( 'foo', 1 ); - - response.then( function(){ - done(); - }); - }); - - - it( 'should call icAjax.request with the correct arguments', function(){ - expect( requestSpy.args[0][0].url ).to.equal( '/foo' ); - expect( requestSpy.args[0][0].data.id ).to.equal( 1 ); - }); - - ajaxTestSuite(); - - singleObjectAjaxTestSuite(); - - }); - - describe( '__find single model with no id', function(){ - beforeEach(function( done ){ - var options = {data: {main: true }}; - //request - response = ajaxdapter.find( 'foo', null, options, true ); - - response.finally( function(){ - done(); - }); - }); - - it( 'should call icAjax.request with the correct arguments', function(){ - expect( requestSpy.args[0][0].url ).to.equal( '/foo' ); - expect( requestSpy.args[0][0].data.main ).to.true; - }); - - ajaxTestSuite(); - - singleObjectAjaxTestSuite(); - - }); - - describe( '__find array of models', function(){ - beforeEach(function( done ){ - var options = {data: {main: true }}; - //request - response = ajaxdapter.find( 'bar', null, options, false ); - response.finally( function(){ - done(); - }); - }); - - ajaxTestSuite(); - - it( 'should return an instance of Ember.ArrayProxy', function(){ - response.should.be.instanceOf( Ember.ArrayProxy ); - }); - - it( 'should return an array of Bar models', function(){ - response.content[0].should.to.be.instanceOf( Bar ); - response.content[1].should.to.be.instanceOf( Bar ); - }); - }); - - describe( '__find array with zero items', function(){ - beforeEach(function( done ){ - var options = {data: {main: true }}; - //request - response = ajaxdapter.find( 'car', null, options, false ); - response.finally(function(){done();}); - }); - - it( 'should reject the promise', function( done){ - response.then(function(){ - done( new Error("error: should not have resolved the find" )); - },function(reason){ - done(); - }); - }); - it( 'should still be an array', function(){ - response.should.be.instanceOf( Ember.ArrayProxy ); - }); - it( 'should be an empty array', function(){ - response.get('length').should.equal(0); - }); - - after( function(){ - requestSpy.reset(); - }); - }); - - describe( 'save', function(){ - before( function( done ){ - var foo = Foo.create({ test: 'foo', 'bar': { id: 1, quiz: 'bar' } }); - response = ajaxdapter.save( '/foo', foo ); - response.then( function(){ done(); } ); - }); - after( function(){ - requestSpy.reset(); - }); - - it( 'should call icAjax.request once', function(){ - requestSpy.should.be.calledOnce; - }); - it( 'should call $.ajax with the correct arguments', function(){ - expect( requestSpy.args[0][0].url ).to.equal( '/foo' ); - expect( requestSpy.args[0][0].type ).to.equal( 'POST' ); - expect( requestSpy.args[0][0].data ).to.be.a( 'string' ); - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - }); - - }); - - describe( 'delete', function(){ - before(function( done ){ - //request - var foo = Foo.create({ id: 1, test: 'foo', 'bar': { id: 1, quiz: 'bar' } }); - response = ajaxdapter.deleteRecord( '/foo', 1 ); - response.then( function(){ done(); }); - }); - after( function(){ - requestSpy.reset(); - }); - it( 'should call icAjax.request once', function(){ - requestSpy.should.be.calledOnce; - }); - - it( 'should call $.ajax with the correct arguments', function(){ - expect( requestSpy.args[0][0].url ).to.equal( '/foo' ); - expect( requestSpy.args[0][0].type ).to.equal( 'DELETE' ); - expect( requestSpy.args[0][0].data ).to.be.a( 'string' ); - expect( requestSpy.args[0][0].data ).to.equal( JSON.stringify({ id: 1}) ); - - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - }); - - }); -}); - - -function ajaxTestSuite(){ - afterEach(function(){ - //reset spies - requestSpy.reset(); - }); - - it( 'should call icAjax.request once', function(){ - requestSpy.should.be.calledOnce; - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - expect( Ember.PromiseProxyMixin.detect( response ) ); - - }); - -} - -function singleObjectAjaxTestSuite(){ - it( 'should return an instanceof Foo', function(done){ - response.then(function(r){ - response.get('content').should.be.instanceOf( Foo ); - done(); - }); - }); -} - - diff --git a/test/unit/adapters/localstorage.js b/test/unit/adapters/localstorage.js deleted file mode 100644 index c9bad9b..0000000 --- a/test/unit/adapters/localstorage.js +++ /dev/null @@ -1,285 +0,0 @@ -import Model from "sl-model"; -import Adapter from 'sl-model/adapter'; -import LocalStorageAdapter from 'sl-model/adapters/localstorage'; - -chai.should(); - -var expect = chai.expect, - localstoragedapter, - Foo = Model.extend(), - Bar = Model.extend(), - Car = Model.extend(), - localStorage, - defineFixture, - response, - responseFromCache, - responseFromRequestCache, - requestSpy, - saveSpy, - store, - container; - -describe( 'sl-model/adapter/localstorage', function(){ - - before( function( ){ - 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 ){ - var item = this.registry.findBy( 'key', key ); - return item ? item.factory : undefined; - } - }; - store = { - container:container, - runPostQueryHooks: sinon.spy(), - runPreQueryHooks: sinon.spy(), - createRecord: function( type, content ){ - var record = this.modelFor( type ).create({conatainer:this.container}).set('content',content); - return record; - }, - modelFor: function( type ){ - return this.container.lookupFactory('model:'+type); - } - }; - - - localStorage = { - _ns: 'testLSObject', - setItem: function( item, content ){ - this[item] = content; - }, - getItem: function( item ){ - return this[item]; - } - }; - - localstoragedapter = LocalStorageAdapter.create({ - container: container, - store:store - }); - - //register mock data - localstoragedapter.container.cache['store:main']={ - runPostQueryHooks: sinon.spy(), - runPreQueryHooks: sinon.spy() - }; - - localstoragedapter.container.registry.push( { key: 'model:foo', factory: Foo } ); - localstoragedapter.container.registry.push( { key: 'model:bar', factory: Bar } ); - localstoragedapter.container.registry.push( { key: 'model:car', factory: Car } ); - - localstoragedapter.set( 'localStorageMockup', localStorage ); - - Foo.reopenClass( { url: '/foo' } ); - Bar.reopenClass( { url: '/bar' } ); - Car.reopenClass( { url: '/car' } ); - - //spies - requestSpy = sinon.spy( localStorage, 'getItem' ); - saveSpy = sinon.spy( localStorage, 'setItem' ); - - - localstoragedapter.save( '/foo', {id: 1, test: 'foo', 'bar': { id: 1, quiz: 'bar' } } ); - - localstoragedapter.save( '/bar', { id: 1, quiz: 'bar' } ); - - localstoragedapter.save( '/bar', { id: 2, quiz: 'bar2' } ); - }); - - describe( '__find single model with id', function(){ - beforeEach(function( done ){ - //request - response = localstoragedapter.find( 'foo', 1, { label: '1' } ); - response.finally(function(){done();}); - }); - - it( 'should call localStorage.getItem with the correct arguments', function(){ - expect( requestSpy.args[0][0] ).to.equal( 'sl-model' ); - }); - - localstorageTestSuite(); - - singleObjectTestSuite(); - - it( 'should reject when no model was found', function( done ){ - response = localstoragedapter.find( 'car', 1, { label: '1' } ); - response.then( function(result){ - throw 'error, find should have been rejecteed' ; - }); - response.catch( function(result){ - done(); - }); - }); - - }); - - - - describe( '__find single model with no id', function(){ - beforeEach(function(done){ - var options = {data: {main: true }}; - //request - response = localstoragedapter.find( 'foo', null, options, true ); - response.then(function(){done();}); - }); - - it( 'should call localStorage.getItem with the correct arguments', function(){ - expect( requestSpy.args[0][0] ).to.equal( 'sl-model' ); - }); - - localstorageTestSuite(); - - singleObjectTestSuite(); - - it( 'should reject when no model was found', function( done ){ - response = localstoragedapter.find( 'car', null, {data: {main: true }}, true ); - response.then( function(result){ - throw( 'error, find should have been rejecteed' ); - }); - response.catch( function(result){ - done(); - }); - }); - - }); - - describe( '__find array of models', function(){ - beforeEach(function( done ){ - var options = {data: {main: true }}; - //request - response = localstoragedapter.find( 'bar', null, options, false ); - response.then(function(){done();}); - }); - - localstorageTestSuite(); - - it( 'should return an instance of Ember.ArrayProxy', function(){ - response.should.be.instanceOf( Ember.ArrayProxy ); - }); - - it( 'should return an array of Bar models', function(){ - response.content[0].should.to.be.instanceOf( Bar ); - response.content[1].should.to.be.instanceOf( Bar ); - }); - }); - - describe( '__find array with zero items', function(){ - beforeEach(function( done ){ - var options = {data: {main: true }}; - //request - response = localstoragedapter.find( 'car', null, options, false ); - response.finally(function(){done();}); - }); - - it( 'should reject the promise', function( done){ - response.then(function(){ - done( new Error("error: should not have resolved the find" )); - },function(reason){ - done(); - }); - }); - it( 'should still be an array', function(){ - response.should.be.instanceOf( Ember.ArrayProxy ); - }); - it( 'should be an empty array', function(){ - response.get('length').should.equal(0); - }); - - after( function(){ - requestSpy.reset(); - }); - }); - - - describe( 'save', function(){ - before( function( done ){ - var fooContent = { id: 2, test: 'foo', 'bar': { id: 1, quiz: 'bar2' } }, - foo = Foo.create( fooContent ); - response = localstoragedapter.save( '/foo', foo ); - response.then( function(){ done(); } ); - }); - after( function(){ - requestSpy.reset(); - }); - - it( 'should call localStorage.getItem once', function(){ - requestSpy.should.be.calledOnce; - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - }); - - it( 'should add the record to the localStorage mock object', function(){ - var fooRecords = Ember.A( JSON.parse(localStorage.getItem('sl-model')).foo ), - fooRecord = fooRecords.findBy( 'id', 2 ); - - expect( fooRecord.id ).to.equal( 2 ); - - }); - - }); - - describe( 'delete', function(){ - before(function( done ){ - //request - var response = localstoragedapter.deleteRecord( '/foo', 2 ); - response.then( function(){ done(); }); - }); - after( function(){ - requestSpy.reset(); - }); - it( 'should call localStorage.getItem once', function(){ - requestSpy.should.be.calledOnce; - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - }); - - it( 'should delete the record from the localStorage mock object', function(){ - - var fooRecords = Ember.A( JSON.parse(localStorage.getItem('sl-model')).foo ), - fooRecord = fooRecords.findBy( 'id', 2 ); - - expect( fooRecord ).to.be.undefined; - - }); - - }); -}); - - -function localstorageTestSuite(){ - afterEach(function(){ - //reset spies - requestSpy.reset(); - }); - - it( 'should return a promise proxy', function(){ - response.then.should.exist; - expect( Ember.PromiseProxyMixin.detect( response ) ); - - }); - - -} - -function singleObjectTestSuite(){ - it( 'should return an instanceof Foo', function(){ - response.get('content').should.be.instanceOf( Foo ); - }); -} - - diff --git a/test/unit/model.js b/test/unit/model.js deleted file mode 100644 index 16703eb..0000000 --- a/test/unit/model.js +++ /dev/null @@ -1,286 +0,0 @@ -import Model from "sl-model"; -import Ember from "ember"; - -chai.should(); - - - - -describe( 'sl-model:model', function(){ - var expect = chai.expect, - Foo, - foo, - Bar, - bar, - adapter, - container, - fooResponse = { id: 1, test: 'true' }, - ajaxMock = function(){ - return new Ember.RSVP.Promise(function(resolve){ resolve( fooResponse ); }); - }, - serRespons1 = { test: true }, - serResponse2 = { test: false }, - serializer1 = function( response, store ){ return response }, - serializer2 = function( response, store ){ return response }; - - before( function(){ - Foo = Model.extend(); - Foo.reopenClass({ - url:'/foo', - endpoints: { - doo: { - url: '/doo' - }, - goo: { - serializer: serializer1, - post: { - url: '/goo', - serializer: serializer2 - } - } - } - }); - Bar = Model.extend(); - Bar.reopenClass({ - url: '/bar', - endpoints: { - default: { - post: '/barUpdate', - delete: '/barDelete', - serializer: serializer1 - }, - car: { - post: { - url: '/carUpdate', - serializer: serializer2, - }, - delete: '/carDelete' - } - } - }); - adapter = { - save: ajaxMock, - deleteRecord: ajaxMock, - }; - - sinon.spy( adapter, 'save' ); - sinon.spy( adapter, 'deleteRecord' ); - - 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 ){ - var item = this.registry.findBy( 'key', key ); - return item ? item.factory : undefined; - } - }; - - container.cache['adapter:ajax']=adapter; - - foo = Foo.create({ - content: { - test: 'foo', - 'bar': { id: 1, quiz: 'bar' }, - }, - container: container - }); - - - bar = Bar.create({ - content: { - test: 'bar', - 'car': { id: 1, quiz: 'car' }, - }, - container: container - }); - }); - - describe( 'getUrlForEndpointAction', function(){ - it( 'should return /bar for ( null, `get` ) ', function(){ - expect( Bar.getUrlForEndpointAction( null, 'get' )).to.equal( '/bar' ); - }); - - it( 'should return /barUpdate for ( null, `post` ) ', function(){ - expect( Bar.getUrlForEndpointAction( null, 'post' )).to.equal( '/barUpdate' ); - }); - - it( 'should return /barDelete for ( null, `delete` ) ', function(){ - expect( Bar.getUrlForEndpointAction( null, 'delete' )).to.equal( '/barDelete' ); - }); - - it( 'should return /bar for ( `default`, `get` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'default', 'get' )).to.equal( '/bar' ); - }); - - it( 'should return /barUpdate for ( `default`, `post` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'default', 'post' )).to.equal( '/barUpdate' ); - }); - - it( 'should return /barDelete for ( `default`, `delete` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'default', 'delete' )).to.equal( '/barDelete' ); - }); - - it( 'should return /bar for ( `car`, `get` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'car', 'get' )).to.equal( '/bar' ); - }); - - it( 'should return /carUpdate for ( `car`, `post` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'car', 'post' )).to.equal( '/carUpdate' ); - }); - - it( 'should return /carDelete for ( `car`, `delete` ) ', function(){ - expect( Bar.getUrlForEndpointAction( 'car', 'delete' )).to.equal( '/carDelete' ); - }); - - it( 'should return /foo for ( `car`, `delete` ) ', function(){ - expect( Foo.getUrlForEndpointAction( 'car', 'delete' )).to.equal( '/foo' ); - }); - - }); - - describe( 'callSerializerForEndpointAction', function(){ - var testResponse1 = { test:true }, - testResponse2 = { test: false }, - TestModel = Model.extend({}); - TestModel.reopenClass({ - serializer: function( response, store ){ - return testResponse1; - }, - endpoints: { - test: { - get: { - serializer: function( response, store ){ - return testResponse2; - } - } - } - } - }); - - it( 'should return testResponse1 for TestModel - ( `null`, `get` )', function(){ - expect( TestModel.callSerializerForEndpointAction( null, 'get', {} )).to.equal( testResponse1 ); - - }); - it( 'should return testResponse2 for TestModel - ( `test`, `get` )', function(){ - expect( TestModel.callSerializerForEndpointAction( 'test', 'get', {} )).to.equal( testResponse2 ); - }); - - }); - - describe( 'save-default', function(){ - before(function( done ){ - foo.save().then(function(){ done(); }); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.save with correct arguments', function(){ - expect( adapter.save.args[0][0] ).to.equal( '/foo' ); - expect( adapter.save.args[0][1].test ).to.equal( 'foo' ); - }); - it( 'should update its content with fooResponse', function(){ - expect( foo.get('content') ).to.deep.equal( fooResponse ); - }); - }); - - describe( 'save-endpoint', function(){ - before(function( done ){ - bar.save().then(function(){done();}); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.save with correct arguments', function(){ - expect( adapter.save.args[0][0] ).to.equal( '/barUpdate' ); - expect( adapter.save.args[0][1].test ).to.equal( 'bar' ); - }); - it( 'should update its content with fooResponse', function(){ - expect( bar.get('content') ).to.deep.equal( fooResponse ); - }); - }); - - describe( 'save-endpoint:car', function(){ - before(function( done ){ - bar = Bar.create({ - content: { - test: 'bar', - 'car': { id: 1, quiz: 'car' }, - }, - container: container - }); - bar.save({endpoint:'car'}).then(function(){done();}); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.save with correct arguments', function(){ - expect( adapter.save.args[0][0] ).to.equal( '/carUpdate' ); - expect( adapter.save.args[0][1].test ).to.equal( 'bar' ); - }); - it( 'should update its content with fooResponse', function(){ - expect( bar.get('content') ).to.deep.equal( fooResponse ); - }); - }); - - describe( 'delete', function(){ - before(function( done ){ - var p = foo.deleteRecord().then(function(){ done(); }); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.deleteRecord with correct arguments', function(){ - adapter.deleteRecord.should.have.been.calledWith( '/foo' ); - }); - it( 'should destroy foo', function(){ - expect( foo.isDestroyed ); - }); - }); - - describe( 'delete-endpoint', function(){ - before(function( done ){ - var p = bar.deleteRecord().then(function(){ done(); }); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.delete with correct arguments', function(){ - adapter.deleteRecord.should.have.been.calledWith( '/barDelete' ); - }); - it( 'should destroy bar', function(){ - expect( bar.isDestroyed ); - }); - }); - - describe( 'delete-endpoint:car', function(){ - before(function( done ){ - var p = bar.deleteRecord({endpoint:'car'}).then(function(){ done(); }); - }); - after(function(){ - adapter.save.reset(); - adapter.deleteRecord.reset(); - }); - it( 'should call adapter.delete with correct arguments', function(){ - adapter.deleteRecord.should.have.been.calledWith( '/carDelete' ); - }); - it( 'should destroy bar', function(){ - expect( bar.isDestroyed ); - }); - }); - -}); diff --git a/test/unit/store.js b/test/unit/store.js deleted file mode 100644 index 5349b84..0000000 --- a/test/unit/store.js +++ /dev/null @@ -1,203 +0,0 @@ -import Model from "sl-model"; -import Store from 'sl-model/store'; - -chai.should(); - -var expect = chai.expect, - store, - - AjaxAdapter, - ajaxadapter, - LocalstorageAdapter, - Foo, - Bar, - queryHook = sinon.spy(); - - -describe( 'sl-model/store', function(){ - - beforeEach(function(){ - - AjaxAdapter = Ember.Object.extend({ type: 'ajax', __find: function(){} }); - LocalstorageAdapter = Ember.Object.extend({ type: 'localstorage' }); - Foo = Model.extend(); - Foo.reopenClass({url:'/foo'}); - Bar = Model.extend(); - Bar.reopenClass({ adapter: '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 } ); - }); - - describe( 'modelFor', function(){ - it( 'should return the model "Foo" for type "foo" ', function(){ - expect( store.modelFor( 'foo' ) ).to.equal( Foo ); - }); - - it( 'should return the model "Bar" for type "bar" ', function(){ - expect( store.modelFor( 'bar' ) ).to.equal( Bar ); - }); - - }); - - describe( 'adapterFor', function(){ - it( 'should return the adapter "ajax" for model type "foo"', function(){ - expect( store.adapterFor( 'foo' ) ).to.be.an.instanceof( AjaxAdapter ); - }); - - it( 'should return the adapter "localstorage" for model type "bar"', function(){ - expect( store.adapterFor( 'bar' ) ).to.be.an.instanceof( LocalstorageAdapter ); - }); - }); - - - describe( 'findOne', function(){ - it( 'should have called __find with correct args', function(){ - var options = { "otherId": 1 }; - store.__find = sinon.spy(); - store.findOne( 'foo', options ); - store.__find.should.have.been.calledWith( 'foo', null, options, true ); - }); - - }); - - describe( 'find with numeric id', function(){ - it( 'should have called __find with the correct args', function(){ - var options = { "otherId": 1 }; - store.__find = sinon.spy(); - store.find( 'foo', 1, options ); - store.__find.should.have.been.calledWith( 'foo', 1, options, false ); - }); - }); - - describe( 'find with object for first param', function(){ - it( 'should have called __find with the correct args', function(){ - var options = { "otherId": 1 }; - store.__find = sinon.spy(); - store.find( 'foo', options ); - store.__find.should.have.been.calledWith( 'foo', null, options, false ); - }); - }); - - describe( 'find with only type', function(){ - it( 'should have called __find with the correct args', function(){ - store.__find = sinon.spy(); - store.find( 'foo' ); - store.__find.should.have.been.calledWith( 'foo', null, null, false ); - }); - }); - - - describe( '__find', function(){ - beforeEach( function(){ - ajaxadapter = store.container.lookup( 'adapter:ajax'); - ajaxadapter.find = sinon.spy(); - sinon.spy( store, "modelFor" ); - sinon.spy( store, "adapterFor" ); - store.__find( 'foo', 1, {}, false ); - }); - - it( 'should have called modelFor with the correct args', function(){ - store.modelFor.should.have.been.calledWith( 'foo' ); - }); - it( 'should have called adapterFor with the correct args', function(){ - store.adapterFor.should.have.been.calledWith( 'foo' ); - }); - it( 'should have called AjaxAdapter.find with the correct args', function(){ - ajaxadapter.find.should.have.been.calledWith( 'foo', 1, {}, false ); - }); - }); - - describe( 'createRecord', function(){ - beforeEach( function(){ - sinon.spy( store, 'modelFor' ); - sinon.spy( Foo, 'create' ); - store.createRecord( 'foo' ); - }); - it( 'should have called modelFor with "foo"', function(){ - store.modelFor.should.have.been.calledWith( 'foo' ); - }); - it( 'should have called Foo.create once', function(){ - expect( Foo.create.should.have.been.called.once ); - }); - it( 'should have called Foo.create with an object container', function(){ - Foo.create.should.have.been.calledWith( { container: store.container } ); - }); - - }); - - describe( 'registerPreQueryHook', function(){ - before( function(){ - store.registerPreQueryHook( queryHook ); - }); - after( function(){ - store.preQueryHooks = Ember.A([]); - }); - it( 'should add an entry to preQueryHooks', function(){ - expect( store.get( 'preQueryHooks' ) ).to.have.length(1); - }); - }); - - describe( 'runPreQueryHooks', function(){ - before( function(){ - store.registerPreQueryHook( queryHook ); - store.runPreQueryHooks(); - }); - after( function(){ - store.preQueryHooks = Ember.A([]); - queryHook.reset(); - }); - it( 'should have run queryHook once', function(){ - queryHook.should.have.been.calledOnce; - }); - }); - - describe( 'registerPostQueryHook', function(){ - beforeEach( function(){ - store.registerPostQueryHook( queryHook ); - }); - after( function(){ - store.postQueryHooks = Ember.A([]); - }); - it( 'should add an entry to postQueryHooks', function(){ - expect( store.get( 'postQueryHooks' ) ).to.have.length(1); - }); - }); - - describe( 'runPostQueryHooks', function(){ - before( function(){ - store.registerPostQueryHook( queryHook ); - store.runPostQueryHooks(); - }); - after( function(){ - store.postQueryHooks = Ember.A([]); - queryHook.reset(); - }); - it( 'should have run queryHook once', function(){ - queryHook.should.have.been.calledOnce; - }); - }); -}); diff --git a/testem.json b/testem.json index 6ff0afe..eff93f9 100644 --- a/testem.json +++ b/testem.json @@ -1,5 +1,11 @@ { - "framework": "mocha", - "test_page": "test/test.mustache", - "cwd": "tmp/output" + "framework": "qunit", + "test_page": "tests/index.html", + "launch_in_ci": [ + "PhantomJS" + ], + "launch_in_dev": [ + "PhantomJS", + "Chrome" + ] } diff --git a/testrunner.js b/testrunner.js deleted file mode 100755 index 43ca11e..0000000 --- a/testrunner.js +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -process.title = 'testrunner'; - -var fs = require( 'fs' ), - broccoli = require( 'broccoli' ), - mergeTrees = require( 'broccoli-merge-trees' ), - filterES6Modules = require( 'broccoli-es6-module-filter' ), - pickFiles = require( 'broccoli-static-compiler' ), - Testem = require( 'testem' ), - exportTree = require( 'broccoli-export-tree' ), - broconcat = require( 'broccoli-concat' ), - tree = broccoli.loadBrocfile(), - builder, - Watcher, - watcher, - testem; - -tree = mergeTrees( - [ - tree, - broconcat( - mergeTrees( - [ - pickFiles( 'vendor/jquery/dist', { - srcDir : '/', - files : [ 'jquery.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/handlebars', { - srcDir : '/', - files : [ 'handlebars.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/loader.js', { - srcDir : '/', - files : [ 'loader.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember', { - srcDir : '/', - files : [ 'ember.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember-resolver/dist', { - srcDir : '/', - files : [ 'ember-resolver.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember-load-initializers/', { - srcDir : '/', - files : [ 'ember-load-initializers.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/mocha/', { - srcDir : '/', - files : [ 'mocha.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/chai/', { - srcDir : '/', - files : [ 'chai.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/chai-as-promised/lib/', { - srcDir : '/', - files : [ 'chai-as-promised.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/sinonjs/', { - srcDir : '/', - files : [ 'sinon.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/sinon-chai/lib', { - srcDir : '/', - files : [ 'sinon-chai.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/sl-modelize/dist', { - srcDir : '/', - files : [ 'sl-modelize.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ic-ajax/dist/named-amd', { - srcDir : '/', - files : [ 'main.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember-cli-shims', { - srcDir : '/', - files : [ 'app-shims.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember-mocha-adapter', { - srcDir : '/', - files : [ 'adapter.js' ], - destDir : '/assets' - } ), - pickFiles( 'vendor/ember-qunit/dist/named-amd', { - srcDir : '/', - files : [ 'main.js' ], - destDir : '/assets/ember-qunit' - } ) - ], - { overwrite : true } - ), - { - inputFiles : [ - 'assets/loader.js', - 'assets/jquery.js', - 'assets/handlebars.js', - 'assets/ember.js', - 'assets/app-shims.js', - 'assets/ember-resolver.js', - 'assets/ember-load-initializers.js', - 'assets/mocha.js', - 'assets/chai.js', - 'assets/sinon-chai.js', - 'assets/sinon.js', - 'assets/app-shims.js', - 'assets/adapter.js', - 'assets/main.js', - 'assets/ember-qunit/main.js', - '**/*.js' - ], - outputFile : '/assets/vendor.js', - wrapInEval : false - } - ), - broconcat( - filterES6Modules( - pickFiles( 'test', { - srcDir : '/', - inputFiles : [ '**/*.js' ], - destDir : '/test' - } ), - { - moduleType : 'amd', - anonymous : false, - compatFix : true, - packageName : 'sl-model-test' - } - ), - { - inputFiles : [ '**/*.js' ], - outputFile : '/test/tests.js', - wrapInEval : false - } - ), - pickFiles( 'test',{ - srcDir : '/', - files : [ 'test.mustache' ], - destDir : '/test' - } ) - ], - { overwrite : true } - ); - -tree = mergeTrees( [ - tree, - exportTree( tree, { - destDir : 'tmp/output' - } ) -],{ overwrite : true } ); - -builder = new broccoli.Builder( tree ); -Watcher = require( 'broccoli/lib/watcher' ); -watcher = new Watcher( builder ); - -watcher.then( - function(){ - testem = new Testem(); - - testem.startDev( { 'file' : './testem.json' }, function( code ) { - process.exit( code ); - } ); - }, - function( reason ){ - console.log( 'broccoli build failed:', reason ); - process.exit( 1 ); - } -); - -watcher.on( 'change', function() { - testem.restart(); -} ); - -process.on( 'SIGINT', function () { - process.exit( 1 ); -} ); - -process.on( 'SIGTERM', function () { - process.exit( 1 ); -} ); - -process.addListener( 'exit', function () { - console.log( 'exiting' ); - builder.cleanup(); - fs.rmdir( 'tmp' ); -} ); - -console.log( 'starting...' ); \ No newline at end of file diff --git a/.jshintrc b/tests/.jshintrc similarity index 81% rename from .jshintrc rename to tests/.jshintrc index 8917c75..95db7f3 100644 --- a/.jshintrc +++ b/tests/.jshintrc @@ -4,9 +4,8 @@ "window", "location", "setTimeout", - "Ember", - "Em", "$", + "-Promise", "QUnit", "define", "console", @@ -25,13 +24,19 @@ "ok", "strictEqual", "module", + "moduleFor", + "moduleForComponent", + "moduleForModel", "process", + "expect", "visit", "exists", "fillIn", "click", "keyEvent", + "triggerEvent", "find", + "findWithAssert", "wait", "DS", "keyEvent", @@ -40,20 +45,11 @@ "andThen", "currentURL", "currentPath", - "currentRouteName", - "mocha", - "before", - "beforeEach", - "after", - "afterEach", - "describe", - "it", - "chai", - "sinon" + "currentRouteName" ], - "node" : true, - "browser" : false, - "boss" : true, + "node": false, + "browser": false, + "boss": true, "curly": false, "debug": false, "devel": false, diff --git a/tests/dummy/.jshintrc b/tests/dummy/.jshintrc new file mode 100644 index 0000000..427d89f --- /dev/null +++ b/tests/dummy/.jshintrc @@ -0,0 +1,33 @@ +{ + "predef": { + "document": true, + "window": true, + "-Promise": true, + "DummyENV": true + }, + "browser" : true, + "boss" : true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true, + "unused": true +} diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js new file mode 100644 index 0000000..5727e51 --- /dev/null +++ b/tests/dummy/app/app.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; +import Resolver from 'ember/resolver'; +import loadInitializers from 'ember/load-initializers'; + +Ember.MODEL_FACTORY_INJECTIONS = true; + +var App = Ember.Application.extend({ + modulePrefix: 'dummy', // TODO: loaded via config + Resolver: Resolver +}); + +loadInitializers(App, 'dummy'); + +export default App; diff --git a/tests/dummy/app/components/.gitkeep b/tests/dummy/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/controllers/.gitkeep b/tests/dummy/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/helpers/.gitkeep b/tests/dummy/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html new file mode 100644 index 0000000..028dd91 --- /dev/null +++ b/tests/dummy/app/index.html @@ -0,0 +1,26 @@ + + + + + + Dummy + + + + {{BASE_TAG}} + + + + + + + + + + + diff --git a/tests/dummy/app/models/.gitkeep b/tests/dummy/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/models/test.js b/tests/dummy/app/models/test.js new file mode 100644 index 0000000..83cd3b8 --- /dev/null +++ b/tests/dummy/app/models/test.js @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..d650ea7 --- /dev/null +++ b/tests/dummy/app/router.js @@ -0,0 +1,10 @@ +import Ember from 'ember'; + +var Router = Ember.Router.extend({ + location: DummyENV.locationType +}); + +Router.map(function() { +}); + +export default Router; diff --git a/tests/dummy/app/routes/.gitkeep b/tests/dummy/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/routes/application.js b/tests/dummy/app/routes/application.js new file mode 100644 index 0000000..946cd3e --- /dev/null +++ b/tests/dummy/app/routes/application.js @@ -0,0 +1,15 @@ +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/styles/.gitkeep b/tests/dummy/app/styles/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/styles/app.css b/tests/dummy/app/styles/app.css new file mode 100644 index 0000000..9adb5ad --- /dev/null +++ b/tests/dummy/app/styles/app.css @@ -0,0 +1,3 @@ +html, body { + margin: 20px; +} diff --git a/tests/dummy/app/templates/.gitkeep b/tests/dummy/app/templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs new file mode 100644 index 0000000..d08c11f --- /dev/null +++ b/tests/dummy/app/templates/application.hbs @@ -0,0 +1,3 @@ +

Welcome to Ember.js

+ +{{outlet}} diff --git a/tests/dummy/app/templates/components/.gitkeep b/tests/dummy/app/templates/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/views/.gitkeep b/tests/dummy/app/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js new file mode 100644 index 0000000..47490a8 --- /dev/null +++ b/tests/dummy/config/environment.js @@ -0,0 +1,38 @@ +/* jshint node: true */ + +module.exports = function(environment) { + var ENV = { + environment: environment, + baseURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. 'with-controller': true + } + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + } + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + ENV.baseURL = '/'; // Testem prefers this... + } + + if (environment === 'production') { + + } + + return ENV; +}; diff --git a/tests/dummy/public/.gitkeep b/tests/dummy/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/public/crossdomain.xml b/tests/dummy/public/crossdomain.xml new file mode 100644 index 0000000..29a035d --- /dev/null +++ b/tests/dummy/public/crossdomain.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/tests/dummy/public/robots.txt b/tests/dummy/public/robots.txt new file mode 100644 index 0000000..ee2cc21 --- /dev/null +++ b/tests/dummy/public/robots.txt @@ -0,0 +1,3 @@ +# robotstxt.org/ + +User-agent: * diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js new file mode 100644 index 0000000..62fc58f --- /dev/null +++ b/tests/helpers/resolver.js @@ -0,0 +1,9 @@ +import Resolver from 'ember/resolver'; + +var resolver = Resolver.create(); + +resolver.namespace = { + modulePrefix: 'dummy' +}; + +export default resolver; diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js new file mode 100644 index 0000000..a5d62ca --- /dev/null +++ b/tests/helpers/start-app.js @@ -0,0 +1,28 @@ +import Ember from 'ember'; +import Application from 'dummy/app'; +import Router from 'dummy/router'; + +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; + + Router.reopen({ + location: 'none' + }); + + Ember.run(function() { + App = Application.create(attributes); + App.setupForTesting(); + App.injectTestHelpers(); + }); + + App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL" + + return App; +} diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..e88d21d --- /dev/null +++ b/tests/index.html @@ -0,0 +1,49 @@ + + + + + + Dummy Tests + + + + {{BASE_TAG}} + + + + + + + +
+
+ + + + + + + + + + diff --git a/tests/test-helper.js b/tests/test-helper.js new file mode 100644 index 0000000..f77e5a2 --- /dev/null +++ b/tests/test-helper.js @@ -0,0 +1,15 @@ +import resolver from './helpers/resolver'; +import { + setResolver +} from 'ember-qunit'; + +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'; +} diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/vendor/.gitkeep b/vendor/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/yuidoc.json b/yuidoc.json deleted file mode 100644 index 722bfb3..0000000 --- a/yuidoc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "Sl-Model", - "description": "SL-Model: an ember model layer library", - "version": "0.1", - "url": "https://gitlab.softlayer.local/interface/sl-model", - "options": { - "exclude": "node_modules,tmp,vendor,test,dist,ember-addon", - "outdir": "doc", - "paths": [ - "./lib" - ] - } -} \ No newline at end of file