test('Compute.async operate on single value', function() { var a = new Compute(1); var b = new Compute(2); var obj = Compute.async({}, function(curVal) { if(a.get()) { curVal.a = a.get(); } else { delete curVal.a; } if(b.get()) { curVal.b = b.get(); } else { delete curVal.b; } return curVal; }); obj.bind('change', function() {}); deepEqual(obj.get(), {a: 1, b: 2}, 'object has all properties'); a.set(0); deepEqual(obj.get(), {b: 2}, 'removed a'); b.set(0); deepEqual(obj.get(), {}, 'removed b'); });
test('a compute updated by source changes within a batch is part of that batch', function () { var computeA = new Compute('a'); var computeB = new Compute('b'); var combined1 = new Compute(function() { return computeA.get() + ' ' + computeB.get(); }); var combined2 = new Compute(function() { return computeA.get() + ' ' + computeB.get(); }); var combo = new Compute(function() { return combined1.get() + ' ' + combined2.get(); }); var callbacks = 0; combo.bind('change', function(){ if(callbacks === 0){ ok(true, 'called change once'); } else { ok(false, 'called change multiple times'); } callbacks++; }); canBatch.start(); computeA.set('A'); computeB.set('B'); canBatch.stop(); });
test('compute.truthy', function() { var result = 0; var num = new Compute(3); var truthy = Compute.truthy(num); var tester = new Compute(function() { if(truthy.get()) { return ++result; } else { return ++result; } }); tester.bind('change', function(ev, newVal, oldVal) { if (num.get() === 0) { equal(newVal, 2, '2 is the new val'); } else if (num.get() === -1) { equal(newVal, 3, '3 is the new val'); } else { ok(false, 'change should not be called'); } }); equal(tester.get(), 1, 'on bind, we call tester once'); num.set(2); num.set(1); num.set(0); num.set(-1); });
test('a binding compute does not double read', function () { var sourceAge = 30, timesComputeIsCalled = 0; var age = new Compute(function (newVal) { timesComputeIsCalled++; if (timesComputeIsCalled === 1) { ok(true, 'reading age to get value'); } else if (timesComputeIsCalled === 2) { equal(newVal, 31, 'the second time should be an update'); } else if (timesComputeIsCalled === 3) { ok(true, 'called after set to get the value'); } else { ok(false, 'You\'ve called the callback ' + timesComputeIsCalled + ' times'); } if (arguments.length) { sourceAge = newVal; } else { return sourceAge; } }); var info = new Compute(function () { return 'I am ' + age.get(); }); var k = function () {}; info.bind('change', k); equal(info.get(), 'I am 30'); age.set(31); equal(info.get(), 'I am 31'); });
test('single value compute', function () { expect(2); var num = new Compute(1); num.bind('change', function (ev, newVal, oldVal) { equal(newVal, 2, 'newVal'); equal(oldVal, 1, 'oldVal'); }); num.set(2); });
test("trace", function(){ var rootA = new Compute('a'); var rootB = new Compute('b'); var childA = new Compute(function() { return "childA"+rootA.get(); }); var fn = function() { var b = rootB.get(); if (b === "b") { return "grandChild->b"; } var a = childA.get(); return "grandChild->"+a; }; var grandChild = new Compute(fn); childA.bind('change', function(ev, newVal, oldVal) {}); grandChild.bind('change', function(ev, newVal, oldVal) { equal(newVal, "grandChild->childAA"); }); var out = grandChild.trace(); equal(out.definition, fn, "got the right function"); equal(out.computeValue, "grandChild->b"); grandChild.log(); canBatch.start(); rootA.set('A'); rootB.set('B'); canBatch.stop(); grandChild.log(); });
test("Change propagation in a batch with late bindings (#2412)", function(){ console.clear(); var rootA = new Compute('a'); var rootB = new Compute('b'); var childA = new Compute(function() { return "childA"+rootA.get(); }); var grandChild = new Compute(function() { var b = rootB.get(); if (b === "b") { return "grandChild->b"; } var a = childA.get(); return "grandChild->"+a; }); childA.bind('change', function(ev, newVal, oldVal) {}); grandChild.bind('change', function(ev, newVal, oldVal) { equal(newVal, "grandChild->childAA"); }); canBatch.start(); rootA.set('A'); rootB.set('B'); canBatch.stop(); });
test('compute updated method uses get and old value (#732)', function () { expect(9); var input = { value: 1 }; var value = new Compute('', { get: function () { return input.value; }, set: function (newVal) { input.value = newVal; }, on: function (update) { input.onchange = update; }, off: function () { delete input.onchange; } }); equal(value.get(), 1, 'original value'); ok(!input.onchange, 'nothing bound'); value.set(2); equal(value.get(), 2, 'updated value'); equal(input.value, 2, 'updated input.value'); value.bind('change', function (ev, newVal, oldVal) { equal(newVal, 3, 'newVal'); equal(oldVal, 2, 'oldVal'); value.unbind('change', this.Constructor); }); ok(input.onchange, 'binding to onchange'); input.value = 3; input.onchange({}); ok(!input.onchange, 'removed binding'); equal(value.get(), 3); });
{newVal: 'b', oldVal: 'a', run: function() { b.set(0); }},
{newVal: 'a', oldVal: undefined, run: function() { a.set(0); } },