diff --git a/Makefile b/Makefile index 521b9dd..efeb6d5 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ compile: - coffee -c backbone.dualstorage.coffee spec/*.coffee - coffee -cbo spec backbone.dualstorage.coffee - cat amd.header.js spec/backbone.dualstorage.js amd.footer.js > backbone.dualstorage.amd.js + coffee -cj backbone.dualstorage.js backbone.dualstorage.adapters.coffee backbone.dualstorage.coffee + coffee -c spec/*.coffee + coffee -cbj spec/backbone.dualstorage.js backbone.dualstorage.adapters.coffee backbone.dualstorage.coffee + cat amd.header.js backbone.dualstorage.js amd.footer.js > backbone.dualstorage.amd.js infinite: compile read # (press Enter to recompile) diff --git a/SpecRunner.html b/SpecRunner.html index f879d56..0a1398a 100644 --- a/SpecRunner.html +++ b/SpecRunner.html @@ -9,6 +9,7 @@ + @@ -23,6 +24,7 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/test.adapters.coffee b/test/test.adapters.coffee new file mode 100644 index 0000000..21e4467 --- /dev/null +++ b/test/test.adapters.coffee @@ -0,0 +1,50 @@ +StickyStorage = Backbone.storageAdapters.StickyStorageAdapter + +describe 'StorageAdapters', -> + for storageName, storageClass of Backbone.storageAdapters + do (storageName, storageClass) -> + _describe = if storageClass is StickyStorage then describe.skip else describe + _describe storageName, -> + + it 'takes a name in its constructor and initializes', (done) -> + storage = new storageClass 'SuperSizedStorage' + storage.initialize().done -> + expect(storage.name).to.equal 'SuperSizedStorage' + expect(storage.store).to.exist + storage.clear().done -> + done() + + _describe 'methods', -> + {storage} = {} + + beforeEach (done) -> + storage = new storageClass + storage.initialize().done -> + done() + + afterEach (done) -> + storage.clear().done -> + done() + + it 'sets and gets a record', (done) -> + storage.set('item', foo: 'bar').done -> + storage.get('item').done (item) -> + expect(item).to.eql foo: 'bar' + done() + + it 'deletes a record', (done) -> + storage.set('item', foo: 'bar').done -> + storage.remove('item').done -> + storage.get('item').done (item) -> + expect(item).to.not.ok + done() + + it 'clears all records', (done) -> + storage.set('item1', 1).done -> + storage.set('item2', 2).done -> + storage.clear().done -> + storage.get('item1').done (item1) -> + expect(item1).to.not.ok + storage.get('item2').done (item2) -> + expect(item2).to.not.ok + done() diff --git a/test/test.adapters.js b/test/test.adapters.js new file mode 100644 index 0000000..619f771 --- /dev/null +++ b/test/test.adapters.js @@ -0,0 +1,85 @@ +// Generated by CoffeeScript 1.6.3 +var StickyStorage; + +StickyStorage = Backbone.storageAdapters.StickyStorageAdapter; + +describe('StorageAdapters', function() { + var storageClass, storageName, _ref, _results; + _ref = Backbone.storageAdapters; + _results = []; + for (storageName in _ref) { + storageClass = _ref[storageName]; + _results.push((function(storageName, storageClass) { + var _describe; + _describe = storageClass === StickyStorage ? describe.skip : describe; + return _describe(storageName, function() { + it('takes a name in its constructor and initializes', function(done) { + var storage; + storage = new storageClass('SuperSizedStorage'); + return storage.initialize().done(function() { + expect(storage.name).to.equal('SuperSizedStorage'); + expect(storage.store).to.exist; + return storage.clear().done(function() { + return done(); + }); + }); + }); + return _describe('methods', function() { + var storage; + storage = {}.storage; + beforeEach(function(done) { + storage = new storageClass; + return storage.initialize().done(function() { + return done(); + }); + }); + afterEach(function(done) { + return storage.clear().done(function() { + return done(); + }); + }); + it('sets and gets a record', function(done) { + return storage.set('item', { + foo: 'bar' + }).done(function() { + return storage.get('item').done(function(item) { + expect(item).to.eql({ + foo: 'bar' + }); + return done(); + }); + }); + }); + it('deletes a record', function(done) { + return storage.set('item', { + foo: 'bar' + }).done(function() { + return storage.remove('item').done(function() { + return storage.get('item').done(function(item) { + expect(item).to.not.ok; + return done(); + }); + }); + }); + }); + return it('clears all records', function(done) { + return storage.set('item1', 1).done(function() { + return storage.set('item2', 2).done(function() { + return storage.clear().done(function() { + return storage.get('item1').done(function(item1) { + expect(item1).to.not.ok; + return storage.get('item2').done(function(item2) { + expect(item2).to.not.ok; + return done(); + }); + }); + }); + }); + }); + }); + }); + }); + })(storageName, storageClass)); + } + return _results; +}); diff --git a/test/test.localSync.coffee b/test/test.localSync.coffee new file mode 100644 index 0000000..d1d02aa --- /dev/null +++ b/test/test.localSync.coffee @@ -0,0 +1,25 @@ +describe 'localSync', -> + for storageName, storageClass of Backbone.storageAdapters + do (storageName, storageClass) -> + + _describe = if storageClass is StickyStorage then describe.skip else describe + _describe "with #{storageName}", -> + {storage, store, model} = {} + + beforeEach (done) -> + storage = new storageClass + store = new Backbone.Store 'Store', storage + model = new Backbone.Model + id: 1 + abc: 123 + storage.initialize().done -> + store.initialize().done -> done() + + afterEach (done) -> + store.clear().done -> + storage.clear().done -> + done() + + it 'works correctly when merge == false', (done) -> + + Backbone. \ No newline at end of file diff --git a/test/test.localSync.js b/test/test.localSync.js new file mode 100644 index 0000000..357240d --- /dev/null +++ b/test/test.localSync.js @@ -0,0 +1,39 @@ +// Generated by CoffeeScript 1.6.3 +describe('localSync', function() { + var storageClass, storageName, _ref, _results; + _ref = Backbone.storageAdapters; + _results = []; + for (storageName in _ref) { + storageClass = _ref[storageName]; + _results.push((function(storageName, storageClass) { + var _describe; + _describe = storageClass === StickyStorage ? describe.skip : describe; + return _describe("with " + storageName, function() { + var model, storage, store, _ref1; + _ref1 = {}, storage = _ref1.storage, store = _ref1.store, model = _ref1.model; + beforeEach(function(done) { + storage = new storageClass; + store = new Backbone.Store('Store', storage); + model = new Backbone.Model({ + id: 1, + abc: 123 + }); + return storage.initialize().done(function() { + return store.initialize().done(function() { + return done(); + }); + }); + }); + afterEach(function(done) { + return store.clear().done(function() { + return storage.clear().done(function() { + return done(); + }); + }); + }); + return it('works correctly when merge == false', function(done) {}); + }); + })(storageName, storageClass)); + } + return _results; +}); diff --git a/test/test.store.coffee b/test/test.store.coffee new file mode 100644 index 0000000..41627d7 --- /dev/null +++ b/test/test.store.coffee @@ -0,0 +1,301 @@ +describe 'Store', -> + for storageName, storageClass of Backbone.storageAdapters + do (storageName, storageClass) -> + + _describe = if storageClass is StickyStorage then describe.skip else describe + _describe "with #{storageName}", -> + {storage} = {} + + beforeEach (done) -> + storage = new storageClass + storage.initialize().done -> + done() + + afterEach (done) -> + storage.clear().done -> + done() + + it 'takes a name and a storage adapter in its constructor', -> + store = new Backbone.Store 'Store', storage + + it 'initializes correctly', (done) -> + store = new Backbone.Store 'Store', storage + expect(store.data).to.deep.eql {} + store.initialize().done -> + expect(store.data.dirty).to.eql [] + expect(store.data.destroyed).to.eql [] + expect(store.data.local).to.eql [] + expect(store.data.records).to.eql [] + expect(store.data.recordsById).to.eql {} + done() + + {model, otherModel, store} = {} + storeSetup = (done) -> + model = new Backbone.Model + id: 1 + abc: 123 + otherModel = new Backbone.Model + id: 2 + xxx: 666 + store = new Backbone.Store 'Store', storage + store.initialize().done -> done() + + storeClear = (done) -> + store.clear().done -> done() + + describe 'when adding', -> + beforeEach storeSetup + afterEach storeClear + + it 'adds one model to the store', (done) -> + store.add(model).done (saved) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(saved.attributes).to.deep.eql model.attributes + expect(saved.attributes).to.deep.eql storeData.recordsById[1] + expect(store.data).to.deep.eql + records: [1] + recordsById: 1: model.attributes + local: [] + dirty: [] + destroyed: [] + done() + + it 'adds many models to the store', (done) -> + models = [model, otherModel] + store.add(models).done (saved) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(saved[0].attributes).to.deep.eql model.attributes + expect(saved[0].attributes).to.deep.eql storeData.recordsById[1] + expect(saved[1].attributes).to.deep.eql otherModel.attributes + expect(saved[1].attributes).to.deep.eql storeData.recordsById[2] + expect(store.data).to.deep.eql + records: [1, 2] + recordsById: + 1: model.attributes + 2: otherModel.attributes + local: [] + dirty: [] + destroyed: [] + done() + + it 'adds the model creating a unique id using idAttribute', (done) -> + model = new Backbone.Model + abc: 123 + model.idAttribute = '_id' + store.add(model).done (saved) -> + storage.get('Store').done (storeData) -> + expectedAttr = abc: 123, _id: model.id + expect(storeData).to.deep.eql store.data + expect(saved.attributes).to.deep.eql expectedAttr + expect(saved.attributes).to.deep.eql storeData.recordsById[model.id] + expect(saved.id).to.equal model.id + recordsById = {} + recordsById[model.id] = model.attributes + expect(store.data).to.deep.eql + records: [model.id] + recordsById: recordsById + local: [model.id] + dirty: [] + destroyed: [] + done() + + it 'throws an error if the model is already in the store', (done) -> + store.add(model).done (saved) -> + expect(-> store.add(model)).to.throw(/already in the store/) + done() + + describe 'when updating', -> + beforeEach storeSetup + afterEach storeClear + + it 'updates the model in the store', (done) -> + store.add(model).done -> + model.set abc: 666 + store.update(model).done (updated) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(updated.attributes).to.deep.eql model.attributes + expect(updated.attributes).to.deep.eql storeData.recordsById[1] + expect(store.data).to.deep.eql + records: [1] + recordsById: {1: model.attributes} + local: [] + dirty: [] + destroyed: [] + done() + + it 'throws an error if the model does not have an id', -> + model = new Backbone.Model + expect(-> store.update(model)).to.throw(/model does not have an id/) + + it 'throws an error if the model is not in the store', -> + expect(-> store.update(model)).to.throw(/is not in the store/) + + describe 'when removing', -> + beforeEach storeSetup + afterEach storeClear + + it 'removes the model from the store', (done) -> + store.add(model).done -> + store.remove(model).done (removed) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(removed.attributes).to.deep.eql model.attributes + expect(store.data).to.deep.eql + records: [] + recordsById: {} + local: [] + dirty: [] + destroyed: [] + done() + + it 'removes a local model from the store', (done) -> + model = new Backbone.Model + store.add(model).done -> + store.remove(model).done () -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(store.data).to.deep.eql + records: [] + recordsById: {} + local: [] + dirty: [] + destroyed: [] + done() + + it 'removes the model from the dirty list', (done) -> + store.add(model).done -> + store.isDirty(model, true).done -> + store.remove(model).done () -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(store.data).to.deep.eql + records: [] + recordsById: {} + local: [] + dirty: [] + destroyed: [] + done() + + it 'clears the store removing all saved data', (done) -> + store.add(model).done -> + store.isDirty(model, true).done -> + store.isDestroyed(otherModel, true).done -> + store.clear().done -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql {} + expect(store.data).to.deep.eql {} + done() + + describe 'when searching', -> + beforeEach storeSetup + afterEach storeClear + + it 'finds a model', (done) -> + store.add(model).done -> + expect(store.find 1).to.deep.eql model.attributes + done() + + it 'finds all models', (done) -> + store.add(model).done -> + store.add(otherModel).done -> + models = [model.attributes, otherModel.attributes] + expect(store.find()).to.deep.eql models + done() + + it 'finds all dirty models', (done) -> + store.add(model).done -> + store.isDirty(model, true).done -> + expect(store.findDirty()).to.deep.eql [model.attributes] + done() + + it 'finds all destroyed models', (done) -> + store.isDestroyed(model, true).done -> + expect(store.findDestroyed()).to.deep.eql [model.id] + done() + + it 'returns correct values when model is not found', -> + expect(store.find 1).to.be.undefined + expect(store.findDirty 1).to.be.undefined + expect(store.findDestroyed 1).to.be.false + + describe 'dirty / destroyed flags', (done) -> + beforeEach storeSetup + afterEach storeClear + + it 'marks a model as dirty', (done) -> + store.add(model).done -> + store.isDirty(model, true).done (dirtyModel) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(dirtyModel.attributes).to.deep.eql model.attributes + expect(store.data).to.deep.eql + records: [1] + recordsById: {1: model.attributes} + local: [] + dirty: [1] + destroyed: [] + done() + + it 'marks a model as destroyed', (done) -> + store.isDestroyed(model, true).done (destroyedModel) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(destroyedModel.attributes).to.deep.eql model.attributes + expect(store.data).to.deep.eql + records: [] + recordsById: {} + local: [] + dirty: [] + destroyed: [1] + done() + + it 'unmarks a model as dirty', (done) -> + store.add(model).done -> + store.isDirty(model, true).done () -> + store.isDirty(model, false).done (dirtyModel) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(dirtyModel.attributes).to.deep.eql model.attributes + expect(store.data).to.deep.eql + records: [1] + recordsById: {1: model.attributes} + local: [] + dirty: [] + destroyed: [] + done() + + it 'unmarks a model as destroyed', (done) -> + store.isDestroyed(model, true).done () -> + store.isDestroyed(model, false).done (dirtyModel) -> + storage.get('Store').done (storeData) -> + expect(storeData).to.deep.eql store.data + expect(dirtyModel.attributes).to.deep.eql model.attributes + expect(store.data).to.deep.eql + records: [] + recordsById: {} + local: [] + dirty: [] + destroyed: [] + done() + + it 'reports correctly if there are dirty models', (done) -> + store.add(model).done -> + store.isDirty(model, true).done -> + expect(store.hasDirtyOrDestroyed).to.be.ok + done() + + it 'reports correctly if there are destroyed models', (done) -> + store.isDestroyed(model, true).done -> + expect(store.hasDirtyOrDestroyed).to.be.ok + done() + + it 'throws an error if the model is not in the store', -> + expect(-> store.isDirty(model, true)).to.throw(/is not in the store/) + + it 'throws an error if trying to mark a stored model as destroyed', (done) -> + store.add(model).done -> + expect(-> store.isDestroyed(model, true)).to.throw(/is still in the store/) + done() diff --git a/test/test.store.js b/test/test.store.js new file mode 100644 index 0000000..9b95724 --- /dev/null +++ b/test/test.store.js @@ -0,0 +1,409 @@ +// Generated by CoffeeScript 1.6.3 +describe('Store', function() { + var storageClass, storageName, _ref, _results; + _ref = Backbone.storageAdapters; + _results = []; + for (storageName in _ref) { + storageClass = _ref[storageName]; + _results.push((function(storageName, storageClass) { + var _describe; + _describe = storageClass === StickyStorage ? describe.skip : describe; + return _describe("with " + storageName, function() { + var model, otherModel, storage, store, storeClear, storeSetup, _ref1; + storage = {}.storage; + beforeEach(function(done) { + storage = new storageClass; + return storage.initialize().done(function() { + return done(); + }); + }); + afterEach(function(done) { + return storage.clear().done(function() { + return done(); + }); + }); + it('takes a name and a storage adapter in its constructor', function() { + var store; + return store = new Backbone.Store('Store', storage); + }); + it('initializes correctly', function(done) { + var store; + store = new Backbone.Store('Store', storage); + expect(store.data).to.deep.eql({}); + return store.initialize().done(function() { + expect(store.data.dirty).to.eql([]); + expect(store.data.destroyed).to.eql([]); + expect(store.data.local).to.eql([]); + expect(store.data.records).to.eql([]); + expect(store.data.recordsById).to.eql({}); + return done(); + }); + }); + _ref1 = {}, model = _ref1.model, otherModel = _ref1.otherModel, store = _ref1.store; + storeSetup = function(done) { + model = new Backbone.Model({ + id: 1, + abc: 123 + }); + otherModel = new Backbone.Model({ + id: 2, + xxx: 666 + }); + store = new Backbone.Store('Store', storage); + return store.initialize().done(function() { + return done(); + }); + }; + storeClear = function(done) { + return store.clear().done(function() { + return done(); + }); + }; + describe('when adding', function() { + beforeEach(storeSetup); + afterEach(storeClear); + it('adds one model to the store', function(done) { + return store.add(model).done(function(saved) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(saved.attributes).to.deep.eql(model.attributes); + expect(saved.attributes).to.deep.eql(storeData.recordsById[1]); + expect(store.data).to.deep.eql({ + records: [1], + recordsById: { + 1: model.attributes + }, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + it('adds many models to the store', function(done) { + var models; + models = [model, otherModel]; + return store.add(models).done(function(saved) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(saved[0].attributes).to.deep.eql(model.attributes); + expect(saved[0].attributes).to.deep.eql(storeData.recordsById[1]); + expect(saved[1].attributes).to.deep.eql(otherModel.attributes); + expect(saved[1].attributes).to.deep.eql(storeData.recordsById[2]); + expect(store.data).to.deep.eql({ + records: [1, 2], + recordsById: { + 1: model.attributes, + 2: otherModel.attributes + }, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + it('adds the model creating a unique id using idAttribute', function(done) { + model = new Backbone.Model({ + abc: 123 + }); + model.idAttribute = '_id'; + return store.add(model).done(function(saved) { + return storage.get('Store').done(function(storeData) { + var expectedAttr, recordsById; + expectedAttr = { + abc: 123, + _id: model.id + }; + expect(storeData).to.deep.eql(store.data); + expect(saved.attributes).to.deep.eql(expectedAttr); + expect(saved.attributes).to.deep.eql(storeData.recordsById[model.id]); + expect(saved.id).to.equal(model.id); + recordsById = {}; + recordsById[model.id] = model.attributes; + expect(store.data).to.deep.eql({ + records: [model.id], + recordsById: recordsById, + local: [model.id], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + return it('throws an error if the model is already in the store', function(done) { + return store.add(model).done(function(saved) { + expect(function() { + return store.add(model); + }).to["throw"](/already in the store/); + return done(); + }); + }); + }); + describe('when updating', function() { + beforeEach(storeSetup); + afterEach(storeClear); + it('updates the model in the store', function(done) { + return store.add(model).done(function() { + model.set({ + abc: 666 + }); + return store.update(model).done(function(updated) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(updated.attributes).to.deep.eql(model.attributes); + expect(updated.attributes).to.deep.eql(storeData.recordsById[1]); + expect(store.data).to.deep.eql({ + records: [1], + recordsById: { + 1: model.attributes + }, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + it('throws an error if the model does not have an id', function() { + model = new Backbone.Model; + return expect(function() { + return store.update(model); + }).to["throw"](/model does not have an id/); + }); + return it('throws an error if the model is not in the store', function() { + return expect(function() { + return store.update(model); + }).to["throw"](/is not in the store/); + }); + }); + describe('when removing', function() { + beforeEach(storeSetup); + afterEach(storeClear); + it('removes the model from the store', function(done) { + return store.add(model).done(function() { + return store.remove(model).done(function(removed) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(removed.attributes).to.deep.eql(model.attributes); + expect(store.data).to.deep.eql({ + records: [], + recordsById: {}, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + it('removes a local model from the store', function(done) { + model = new Backbone.Model; + return store.add(model).done(function() { + return store.remove(model).done(function() { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(store.data).to.deep.eql({ + records: [], + recordsById: {}, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + it('removes the model from the dirty list', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function() { + return store.remove(model).done(function() { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(store.data).to.deep.eql({ + records: [], + recordsById: {}, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + }); + return it('clears the store removing all saved data', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function() { + return store.isDestroyed(otherModel, true).done(function() { + return store.clear().done(function() { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql({}); + expect(store.data).to.deep.eql({}); + return done(); + }); + }); + }); + }); + }); + }); + }); + describe('when searching', function() { + beforeEach(storeSetup); + afterEach(storeClear); + it('finds a model', function(done) { + return store.add(model).done(function() { + expect(store.find(1)).to.deep.eql(model.attributes); + return done(); + }); + }); + it('finds all models', function(done) { + return store.add(model).done(function() { + return store.add(otherModel).done(function() { + var models; + models = [model.attributes, otherModel.attributes]; + expect(store.find()).to.deep.eql(models); + return done(); + }); + }); + }); + it('finds all dirty models', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function() { + expect(store.findDirty()).to.deep.eql([model.attributes]); + return done(); + }); + }); + }); + it('finds all destroyed models', function(done) { + return store.isDestroyed(model, true).done(function() { + expect(store.findDestroyed()).to.deep.eql([model.id]); + return done(); + }); + }); + return it('returns correct values when model is not found', function() { + expect(store.find(1)).to.be.undefined; + expect(store.findDirty(1)).to.be.undefined; + return expect(store.findDestroyed(1)).to.be["false"]; + }); + }); + return describe('dirty / destroyed flags', function(done) { + beforeEach(storeSetup); + afterEach(storeClear); + it('marks a model as dirty', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function(dirtyModel) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(dirtyModel.attributes).to.deep.eql(model.attributes); + expect(store.data).to.deep.eql({ + records: [1], + recordsById: { + 1: model.attributes + }, + local: [], + dirty: [1], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + it('marks a model as destroyed', function(done) { + return store.isDestroyed(model, true).done(function(destroyedModel) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(destroyedModel.attributes).to.deep.eql(model.attributes); + expect(store.data).to.deep.eql({ + records: [], + recordsById: {}, + local: [], + dirty: [], + destroyed: [1] + }); + return done(); + }); + }); + }); + it('unmarks a model as dirty', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function() { + return store.isDirty(model, false).done(function(dirtyModel) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(dirtyModel.attributes).to.deep.eql(model.attributes); + expect(store.data).to.deep.eql({ + records: [1], + recordsById: { + 1: model.attributes + }, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + }); + it('unmarks a model as destroyed', function(done) { + return store.isDestroyed(model, true).done(function() { + return store.isDestroyed(model, false).done(function(dirtyModel) { + return storage.get('Store').done(function(storeData) { + expect(storeData).to.deep.eql(store.data); + expect(dirtyModel.attributes).to.deep.eql(model.attributes); + expect(store.data).to.deep.eql({ + records: [], + recordsById: {}, + local: [], + dirty: [], + destroyed: [] + }); + return done(); + }); + }); + }); + }); + it('reports correctly if there are dirty models', function(done) { + return store.add(model).done(function() { + return store.isDirty(model, true).done(function() { + expect(store.hasDirtyOrDestroyed).to.be.ok; + return done(); + }); + }); + }); + it('reports correctly if there are destroyed models', function(done) { + return store.isDestroyed(model, true).done(function() { + expect(store.hasDirtyOrDestroyed).to.be.ok; + return done(); + }); + }); + it('throws an error if the model is not in the store', function() { + return expect(function() { + return store.isDirty(model, true); + }).to["throw"](/is not in the store/); + }); + return it('throws an error if trying to mark a stored model as destroyed', function(done) { + return store.add(model).done(function() { + expect(function() { + return store.isDestroyed(model, true); + }).to["throw"](/is still in the store/); + return done(); + }); + }); + }); + }); + })(storageName, storageClass)); + } + return _results; +});