gristlabs_grist-core/test/client/lib/koUtil.js
Paul Fitzpatrick bcbf57d590 (core) bump mocha version to allow parallel tests; move more tests to core
Summary:
This uses a newer version of mocha in grist-core so that tests can be run in parallel. That allows more tests to be moved without slowing things down overall. Tests moved are venerable browser tests; only the ones that "just work" or worked without too much trouble to are moved, in order to keep the diff from growing too large. Will wrestle with more in follow up.

Parallelism is at the file level, rather than the individual test.

The newer version of mocha isn't needed for grist-saas repo; tests are parallelized in our internal CI by other means. I've chosen to allocate files to workers in a cruder way than our internal CI, based on initial characters rather than an automated process. The automated process would need some reworking to be compatible with mocha running in parallel mode.

Test Plan: this diff was tested first on grist-core, then ported to grist-saas so saas repo history will correctly track history of moved files.

Reviewers: jarek

Reviewed By: jarek

Subscribers: jarek

Differential Revision: https://phab.getgrist.com/D3927
2023-06-27 02:55:34 -04:00

125 lines
4.3 KiB
JavaScript

var assert = require('assert');
var ko = require('knockout');
var sinon = require('sinon');
var koUtil = require('app/client/lib/koUtil');
describe('koUtil', function() {
describe("observableWithDefault", function() {
it("should be an observable with a default", function() {
var foo = ko.observable();
var bar1 = koUtil.observableWithDefault(foo, 'defaultValue');
var obj = { prop: 17 };
var bar2 = koUtil.observableWithDefault(foo, function() { return this.prop; }, obj);
assert.equal(bar1(), 'defaultValue');
assert.equal(bar2(), 17);
foo('hello');
assert.equal(bar1(), 'hello');
assert.equal(bar2(), 'hello');
obj.prop = 28;
foo(0);
assert.equal(bar1(), 'defaultValue');
assert.equal(bar2(), 28);
bar1('world');
assert.equal(foo(), 'world');
assert.equal(bar1(), 'world');
assert.equal(bar2(), 'world');
bar2('blah');
assert.equal(foo(), 'blah');
assert.equal(bar1(), 'blah');
assert.equal(bar2(), 'blah');
bar1(null);
assert.equal(foo(), null);
assert.equal(bar1(), 'defaultValue');
assert.equal(bar2(), 28);
});
});
describe('computedAutoDispose', function() {
function testAutoDisposeValue(pure) {
var obj = [{dispose: sinon.spy()}, {dispose: sinon.spy()}, {dispose: sinon.spy()}];
var which = ko.observable(0);
var computedBody = sinon.spy(function() { return obj[which()]; });
var foo = koUtil.computedAutoDispose({ read: computedBody, pure: pure });
// An important difference between pure and not is whether it is immediately evaluated.
assert.equal(computedBody.callCount, pure ? 0 : 1);
assert.strictEqual(foo(), obj[0]);
assert.equal(computedBody.callCount, 1);
which(1);
assert.strictEqual(foo(), obj[1]);
assert.equal(computedBody.callCount, 2);
assert.equal(obj[0].dispose.callCount, 1);
assert.equal(obj[1].dispose.callCount, 0);
// Another difference is whether changes cause immediate re-evaluation.
which(2);
assert.equal(computedBody.callCount, pure ? 2 : 3);
assert.equal(obj[1].dispose.callCount, pure ? 0 : 1);
foo.dispose();
assert.equal(obj[0].dispose.callCount, 1);
assert.equal(obj[1].dispose.callCount, 1);
assert.equal(obj[2].dispose.callCount, pure ? 0 : 1);
}
it("autoDisposeValue for pure computed should be pure", function() {
testAutoDisposeValue(true);
});
it("autoDisposeValue for non-pure computed should be non-pure", function() {
testAutoDisposeValue(false);
});
});
describe('computedBuilder', function() {
it("should create appropriate dependencies and dispose values", function() {
var index = ko.observable(0);
var foo = ko.observable('foo'); // used in the builder's constructor
var faz = ko.observable('faz'); // used in the builder's dispose
var obj = [{dispose: sinon.spy(() => faz())}, {dispose: sinon.spy(() => faz())}];
var builder = sinon.spy(function(i) { obj[i].foo = foo(); return obj[i]; });
// The built observable should depend on index(), should NOT depend on foo() or faz(), and
// returned values should get disposed.
var built = koUtil.computedBuilder(function() { return builder.bind(null, index()); });
assert.equal(builder.callCount, 1);
assert.strictEqual(built(), obj[0]);
assert.equal(built().foo, 'foo');
foo('bar');
assert.equal(builder.callCount, 1);
faz('baz');
assert.equal(builder.callCount, 1);
// Changing index should dispose the previous value and rebuild.
index(1);
assert.equal(obj[0].dispose.callCount, 1);
assert.equal(builder.callCount, 2);
assert.strictEqual(built(), obj[1]);
assert.equal(built().foo, 'bar');
// Changing foo() or faz() should continue to have no effect (i.e. disposing the previous
// value should not have created any dependencies.)
foo('foo');
assert.equal(builder.callCount, 2);
faz('faz');
assert.equal(builder.callCount, 2);
// Disposing the built observable should dispose the last returned value.
assert.equal(obj[1].dispose.callCount, 0);
built.dispose();
assert.equal(obj[1].dispose.callCount, 1);
});
});
});