UNPKG

blossom

Version:

Modern, Cross-Platform Application Framework

174 lines (126 loc) 5.49 kB
// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Apple Inc. and contributors. // License: Licensed under MIT license (see license.js) // ========================================================================== /*globals module ok equals same test MyApp */ // NOTE: The test below are based on the Data Hashes state chart. This models // the "commit" event in the NestedStore portion of the diagram. var parent, store, child, storeKey, json, args; suite("SC.NestedStore#commitChanges", { setup: function() { SC.RunLoop.begin(); parent = SC.Store.create(); json = { string: "string", number: 23, bool: true }; args = []; storeKey = SC.Store.generateStoreKey(); store = parent.chain(); // create nested store child = store.chain(); // test multiple levels deep // override commitChangesFromNestedStore() so we can ensure it is called // save call history for later evaluation parent.commitChangesFromNestedStore = child.commitChangesFromNestedStore = store.commitChangesFromNestedStore = function(store, changes, force) { args.push({ target: this, store: store, changes: changes, force: force }); }; SC.RunLoop.end(); } }); // .......................................................... // BASIC STATE TRANSITIONS // function testStateTransition(shouldIncludeStoreKey, shouldCallParent) { // attempt to commit equals(store.commitChanges(), store, 'should return receiver'); // verify result equals(store.storeKeyEditState(storeKey), SC.Store.INHERITED, 'data edit state'); if (shouldCallParent === false) { ok(!args || args.length===0, 'should not call commitChangesFromNestedStore'); } else { equals(args.length, 1, 'should have called commitChangesFromNestedStore'); var opts = args[0] || {}; // avoid exceptions equals(opts.target, parent, 'should have called on parent store'); // verify if changes passed to callback included storeKey var changes = opts.changes; var didInclude = changes && changes.contains(storeKey); if (shouldIncludeStoreKey) { ok(didInclude, 'passed set of changes should include storeKey'); } else { ok(!didInclude, 'passed set of changes should NOT include storeKey'); } } equals(store.get('hasChanges'), false, 'hasChanges should be cleared'); ok(!store.chainedChanges || store.chainedChanges.length===0, 'should have empty chainedChanges set'); } test("state = INHERITED", function() { // write in some data to parent parent.writeDataHash(storeKey, json); // check preconditions equals(store.storeKeyEditState(storeKey), SC.Store.INHERITED, 'precond - data edit state'); testStateTransition(false, false); }); test("state = LOCKED", function() { // write in some data to parent parent.writeDataHash(storeKey, json); parent.editables = null ; // manually force to lock state store.readDataHash(storeKey); // check preconditions equals(store.storeKeyEditState(storeKey), SC.Store.LOCKED, 'precond - data edit state'); ok(!store.chainedChanges || !store.chainedChanges.contains(storeKey), 'locked record should not be in chainedChanges set'); testStateTransition(false, false); }); test("state = EDITABLE", function() { // write in some data to parent store.writeDataHash(storeKey, json); store.dataHashDidChange(storeKey); // check preconditions equals(store.storeKeyEditState(storeKey), SC.Store.EDITABLE, 'precond - data edit state'); ok(store.chainedChanges && store.chainedChanges.contains(storeKey), 'editable record should be in chainedChanges set'); testStateTransition(true, true); }); // .......................................................... // SPECIAL CASES // test("commiting a changed record should immediately notify outstanding records in parent store", function() { var Rec = SC.Record.extend({ fooCnt: 0, fooDidChange: function() { this.fooCnt++; }.observes('foo'), statusCnt: 0, statusDidChange: function() { this.statusCnt++; }.observes('status'), reset: function() { this.fooCnt = this.statusCnt = 0; }, equals: function(fooCnt, statusCnt, str) { if (!str) str = '' ; equals(this.get('fooCnt'), fooCnt, str + ':fooCnt'); equals(this.get('statusCnt'), statusCnt, str + ':statusCnt'); } }); SC.RunLoop.begin(); var store = SC.Store.create(); var prec = store.createRecord(Rec, { foo: "bar", guid: 1 }); var child = store.chain(); var crec = child.find(Rec, prec.get('id')); // check assumptions ok(!!crec, 'prerec - should find child record'); equals(crec.get('foo'), 'bar', 'prerec - child record should have foo'); // modify child record - should not modify parent prec.reset(); crec.set('foo', 'baz'); equals(prec.get('foo'), 'bar', 'should not modify parent before commit'); prec.equals(0,0, 'before commitChanges'); // commit changes - note: still inside runloop child.commitChanges(); equals(prec.get('foo'), 'baz', 'should push data to parent'); prec.equals(1,1, 'after commitChanges'); // should notify immediately SC.RunLoop.end(); // should not notify again after runloop - nothing to do prec.equals(1,1,'after runloop ends - should not notify again'); });