spiegel-keyman/common/predictive-text/unit_tests/headless/worker-initialization.js
2022-05-13 09:52:08 +10:00

215 lines
6.4 KiB
JavaScript

var assert = require('chai').assert;
var sinon = require('sinon');
var fs = require('fs');
let LMLayerWorker = require('../../../web/lm-worker/build/intermediate.js');
// Unit tests for instantiating and initializing the LMLayer Worker in isolation.
//
// Although the LMLayerWorker expected to be used inside a DedicatedWorkerGlobalScope,
// these unit tests DO NOT run inside a Worker, and instead use Sinon fakes to assert
// behavior.
describe('LMLayerWorker', function() {
describe('#constructor()', function() {
it('should allow for the mocking of postMessage()', function () {
var fakePostMessage = sinon.fake();
var context = {
postMessage: fakePostMessage
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
// First the worker must receive config data...
configWorker(worker);
// Sending it the `load` message should notify us that it's loaded!
worker.onMessage(createMessageEventWithData({
message: 'load',
source: {
type: 'file',
file: "./unit_tests/in_browser/resources/models/simple-dummy.js"
}
}));
assert(fakePostMessage.calledOnce);
});
});
describe('#onMessage()', function() {
it('should fail if not given the `message` attribute', function () {
var context = {
postMessage: sinon.fake()
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
// Every message is a discriminated union with the tag being `message`.
// If it doesn't see 'message', something is deeply wrong,
// and it should loudly let us know.
assert.throws(function () {
worker.onMessage(createMessageEventWithData({
model: 'dummy attribute'
}));
});
});
});
describe('.install()', function () {
it('should create a new instance, installed on our global object', function () {
var fakeWorkerGlobal = {
onmessage: undefined,
postMessage: new sinon.fake(),
};
fakeWorkerGlobal.importScripts = importScriptsWith(fakeWorkerGlobal);
// Instantiate and install a worker on our global object.
var worker = LMLayerWorker.install(fakeWorkerGlobal);
assert.instanceOf(worker, LMLayerWorker);
// It should have installed a callback.
assert.isFunction(fakeWorkerGlobal.onmessage);
// First the worker must receive config data...
configWorker(worker);
// Send a message; we should get something back.
worker.onMessage(createMessageEventWithData({
message: 'load',
source: {
type: 'file',
file: "./unit_tests/in_browser/resources/models/simple-dummy.js"
}
}));
// It called the postMessage() in its global scope.
assert.isTrue(fakeWorkerGlobal.postMessage.calledOnce)
});
});
describe('Message: config', function () {
it('should disallow any other message', function () {
var context = {
postMessage: sinon.fake()
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
// It should not respond to 'predict'
assert.throws(function () {
worker.onMessage(createMessageEventWithData({
message: 'predict',
}));
}, /invalid message/i);
});
it('accepts a capability set and transitions to the "modelless" state', function () {
var context = {
postMessage: sinon.fake()
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
// Trigger the config message
configWorker(worker);
assert.equal(worker.state.name, 'modelless');
});
});
describe('Message: load', function () {
it('should disallow any other message', function () {
var context = {
postMessage: sinon.fake()
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
configWorker(worker);
// It should not respond to 'predict'
assert.throws(function () {
worker.onMessage(createMessageEventWithData({
message: 'predict',
}));
}, /invalid message/i);
});
it('should send back a "ready" message when given a file', function () {
var fakePostMessage = sinon.fake();
var context = {
postMessage: fakePostMessage
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
configWorker(worker);
worker.onMessage(createMessageEventWithData({
message: 'load',
source: {
type: 'file',
file: "./unit_tests/in_browser/resources/models/simple-dummy.js"
}
}));
assert(fakePostMessage.calledOnceWith(sinon.match({
message: 'ready'
})));
});
it('should send back a "ready" message when given raw code', function () {
var fakePostMessage = sinon.fake();
var context = {
postMessage: fakePostMessage
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
configWorker(worker);
let modelCode = fs.readFileSync("./unit_tests/in_browser/resources/models/simple-dummy.js").toString();
worker.onMessage(createMessageEventWithData({
message: 'load',
source: {
type: 'raw',
code: modelCode
}
}));
assert(fakePostMessage.calledOnceWith(sinon.match({
message: 'ready'
})), 'mocked callback was not called');
});
it('should send back configuration', function () {
var fakePostMessage = sinon.fake();
var context = {
postMessage: fakePostMessage
};
context.importScripts = importScriptsWith(context);
var worker = LMLayerWorker.install(context);
configWorker(worker);
// simple-dummy.js is set with the following.
var maxCodeUnits = 64;
worker.onMessage(createMessageEventWithData({
message: 'load',
source: {
type: 'file',
file: "./unit_tests/in_browser/resources/models/simple-dummy.js"
}
}));
sinon.assert.calledWithMatch(fakePostMessage, {
message: 'ready',
configuration: {
leftContextCodePoints: maxCodeUnits,
rightContextCodePoints: 0,
}
});
});
});
});