Skip to content

Commit

Permalink
chore(web): converts common/predictive-text browser-based tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jahorton committed Apr 29, 2024
1 parent 56d526a commit 9e445db
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 78 deletions.
29 changes: 0 additions & 29 deletions common/predictive-text/unit_tests/in_browser/cases/test-config.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import { assert } from '../../../../../node_modules/chai/chai.js';
import { assert } from 'chai';

import { LMLayer, Worker as WorkerBuilder } from "../../../build/lib/web/index.mjs";
import * as helpers from "../helpers.mjs";
import { LMLayer, Worker as WorkerBuilder } from "@keymanapp/lexical-model-layer/web";
import { defaultCapabilities } from '../helpers.mjs';

describe('LMLayer', function () {
this.timeout(testconfig.timeouts.standard);
this.timeout(5000);

describe('[[constructor]]', function () {
it('should construct with a single argument', function () {
let lmLayer = new LMLayer(helpers.defaultCapabilities, WorkerBuilder.constructInstance(), true);
let lmLayer = new LMLayer(defaultCapabilities, WorkerBuilder.constructInstance(), true);
assert.instanceOf(lmLayer, LMLayer);
lmLayer.shutdown();
});
});

describe.skip('#asBlobURI()', function () {
describe('#asBlobURI()', function () {
// #asBlobURI() requires browser APIs, hence why it cannot be tested headless in Node.
it('should take a function and convert it into a blob function', function (done) {
let uri = WorkerBuilder.asBlobURI(function dummyHandler() {
function dummyHandler() {
// Post something weird, so we can be reasonably certain the Web Worker is...
// well, working.
// WARNING: Do NOT refactor this string as a variable. It **MUST** remain a string
// in this function body, because the code in this function's body gets
// stringified!
postMessage('fhqwhgads');
});
}

// Note: the full declaration exists; the code we want is wrapped within the func.
// So... let's just call the func.
const workerSrc = dummyHandler.toString() + "\ndummyHandler()";
let uri = WorkerBuilder.asBlobURI(workerSrc);
assert.match(uri, /^blob:/);

let worker = new Worker(uri);
Expand All @@ -33,6 +38,8 @@ describe('LMLayer', function () {
worker.terminate();
done();
};

worker.postMessage('test');
})
})
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { assert } from '../../../../../node_modules/chai/chai.js';
import { assert } from 'chai';

import { LMLayer, Worker } from "../../../build/lib/web/index.mjs";
import * as helpers from "../helpers.mjs";
import { LMLayer, Worker } from "@keymanapp/lexical-model-layer/web";
import { defaultCapabilities } from '../helpers.mjs';

import { getConfig } from '@web/test-runner-core/browser/session.js';

// Import assertions, even using 'with', aren't yet supported in Firefox's engine.
// import hazelModel from '@keymanapp/common-test-resources/json/models/future_suggestions/i_got_distracted_by_hazel.json' with { type: 'json' };

/** @type {import('@web/test-runner-core/browser/session.js').RuntimeConfig} */
let config;
/** @type {string} */
let repoRoot;

let hazelModel;

/*
* Shows off the LMLayer API, using the full prediction interface.
Expand All @@ -12,14 +24,24 @@ import * as helpers from "../helpers.mjs";
* of suggestions when loaded and return them sequentially.
*/
describe('LMLayer using dummy model', function () {
this.timeout(testconfig.timeouts.standard);
this.timeout(5000);

before(async () => {
config = await getConfig();
let loc = document.location;
// config.testFile generally starts with a '/', with the path resembling the actual full local
// filesystem for the drive.
const cwd = `${loc.protocol}/${loc.host}${config.testFile.substring(0, config.testFile.lastIndexOf('/'))}`;
repoRoot = `${cwd}/../../../../..`;

// Since Firefox can't do JSON imports quite yet.
const hazelFixture = await fetch(new URL(`${repoRoot}/common/test/resources/json/models/future_suggestions/i_got_distracted_by_hazel.json`));
hazelModel = await hazelFixture.json();
});

describe('Prediction', function () {
it('will predict future suggestions', function () {
this.timeout(testconfig.timeouts.standard * 3); // This one makes multiple subsequent calls across
// the WebWorker boundary, so we should be generous here.

var lmLayer = new LMLayer(helpers.defaultCapabilities, Worker.constructInstance(), true);
var lmLayer = new LMLayer(defaultCapabilities, Worker.constructInstance(), true);

var stripIDs = function(suggestions) {
suggestions.forEach(function(suggestion) {
Expand All @@ -32,26 +54,26 @@ describe('LMLayer using dummy model', function () {
// alas some of our browsers don't support it.
return lmLayer.loadModel(
// We need to provide an absolute path since the worker is based within a blob.
document.location.protocol + '//' + document.location.host + "/resources/models/simple-dummy.js"
`${repoRoot}/common/test/resources/models/simple-dummy.js`
).then(function (actualConfiguration) {
return Promise.resolve();
}).then(function () {
return lmLayer.predict(zeroTransform(), emptyContext());
}).then(function (suggestions) {
stripIDs(suggestions);
assert.deepEqual(suggestions, iGotDistractedByHazel()[0]);
assert.deepEqual(suggestions, hazelModel[0]);
return lmLayer.predict(zeroTransform(), emptyContext());
}).then(function (suggestions) {
stripIDs(suggestions);
assert.deepEqual(suggestions, iGotDistractedByHazel()[1]);
assert.deepEqual(suggestions, hazelModel[1]);
return lmLayer.predict(zeroTransform(), emptyContext());
}).then(function (suggestions) {
stripIDs(suggestions);
assert.deepEqual(suggestions, iGotDistractedByHazel()[2]);
assert.deepEqual(suggestions, hazelModel[2]);
return lmLayer.predict(zeroTransform(), emptyContext());
}).then(function (suggestions) {
stripIDs(suggestions);
assert.deepEqual(suggestions, iGotDistractedByHazel()[3]);
assert.deepEqual(suggestions, hazelModel[3]);
lmLayer.shutdown();
return Promise.resolve();
});
Expand All @@ -60,16 +82,14 @@ describe('LMLayer using dummy model', function () {

describe('Wordbreaking', function () {
it('will perform (default) wordbreaking and return word at caret', function () {
this.timeout(testconfig.timeouts.standard * 3); // This one makes multiple subsequent calls across
// the WebWorker boundary, so we should be generous here.
var lmLayer = new LMLayer(helpers.defaultCapabilities, Worker.constructInstance());
var lmLayer = new LMLayer(defaultCapabilities, Worker.constructInstance());

// We're testing many as asynchronous messages in a row.
// this would be cleaner using async/await syntax, but
// alas some of our browsers don't support it.
return lmLayer.loadModel(
// We need to provide an absolute path since the worker is based within a blob.
document.location.protocol + '//' + document.location.host + "/resources/models/simple-dummy.js"
`${repoRoot}/common/test/resources/models/simple-dummy.js`
).then(function (actualConfiguration) {
return Promise.resolve();
}).then(function () {
Expand All @@ -94,8 +114,4 @@ describe('LMLayer using dummy model', function () {
function zeroTransform() {
return { insert: '', deleteLeft: 0 };
}

function iGotDistractedByHazel() {
return __json__['models/future_suggestions/i_got_distracted_by_hazel'];
}
});
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
import { assert } from '../../../../../node_modules/chai/chai.js';
import { assert } from 'chai';

import { LMLayer, Worker } from "../../../build/lib/web/index.mjs";
import * as helpers from "../helpers.mjs";
import { LMLayer, Worker } from "@keymanapp/lexical-model-layer/web";
import { defaultCapabilities } from '../helpers.mjs';

import { getConfig } from '@web/test-runner-core/browser/session.js';

// Import assertions, even using 'with', aren't yet supported in Firefox's engine.
// import hazelModel from '@keymanapp/common-test-resources/json/models/future_suggestions/i_got_distracted_by_hazel.json' with { type: 'json' };

/** @type {import('@web/test-runner-core/browser/session.js').RuntimeConfig} */
let config;
/** @type {string} */
let repoRoot;

/*
* How to run the worlist
*/
describe('LMLayer using the trie model', function () {
this.timeout(testconfig.timeouts.standard);
this.timeout(5000);

before(async () => {
config = await getConfig();
let loc = document.location;
// config.testFile generally starts with a '/', with the path resembling the actual full local
// filesystem for the drive.
//
// We need to use the same pattern for specifying dynamically-loaded filepaths to be passed into the worker.
// Yaaaaaay.
const cwd = `${loc.protocol}/${loc.host}${config.testFile.substring(0, config.testFile.lastIndexOf('/'))}`;
repoRoot = `${cwd}/../../../../..`;
});

describe('Prediction', function () {
var EXPECTED_SUGGESTIONS = 3;
it('will predict an empty buffer', function () {
this.timeout(testconfig.timeouts.standard * 3); // This one makes multiple subsequent calls across
// the WebWorker boundary, so we should be generous here.

// Parameter 3 = true: enables 'test mode', disables correction-search timeout.
// This helps prevent the correction-search timeout from flaking out periodically during unit tests in
// CI, since remote servers / devices are involved.
var lmLayer = new LMLayer(helpers.defaultCapabilities, Worker.constructInstance(), true);
var lmLayer = new LMLayer(defaultCapabilities, Worker.constructInstance(), true);

// We're testing many as asynchronous messages in a row.
// this would be cleaner using async/await syntax, but
// alas some of our browsers don't support it.
return lmLayer.loadModel(
// We need to provide an absolute path since the worker is based within a blob.
document.location.protocol + '//' + document.location.host + "/resources/models/simple-trie.js"
`${repoRoot}/common/test/resources/models/simple-trie.js`
).then(function (_actualConfiguration) {
return Promise.resolve();
}).then(function () {
Expand Down Expand Up @@ -60,11 +79,11 @@ describe('LMLayer using the trie model', function () {
//
// https://community.software.sil.org/t/search-term-to-key-in-lexical-model-not-working-both-ways-by-default/3133
it('should use the default searchTermToKey()', function () {
var lmLayer = new LMLayer(helpers.defaultCapabilities, Worker.constructInstance());
var lmLayer = new LMLayer(defaultCapabilities, Worker.constructInstance());

return lmLayer.loadModel(
// We need to provide an absolute path since the worker is based within a blob.
document.location.protocol + '//' + document.location.host + "/resources/models/naive-trie.js"
`${repoRoot}/common/test/resources/models/naive-trie.js`
).then(function (_actualConfiguration) {
return Promise.resolve();
}).then(function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { assert } from '../../../../../node_modules/chai/chai.js';
import { assert } from 'chai';

import { Worker as WorkerBuilder } from "../../../build/lib/web/index.mjs";
import { LMLayerWorkerCode } from "/base/common/web/lm-worker/build/lib/worker-main.wrapped.min.js";
import * as helpers from "../helpers.mjs";
import { Worker as WorkerBuilder } from "@keymanapp/lexical-model-layer/web";
import { LMLayerWorkerCode } from "@keymanapp/lm-worker/worker-main.wrapped.js";

import { defaultCapabilities } from '../helpers.mjs';

describe('LMLayerWorker', function () {
// This one makes multiple subsequent calls across the WebWorker boundary, so we should be generous here.
this.timeout(Math.max(testconfig.timeouts.standard, 5000));
this.timeout(5000);

describe('LMLayerWorkerCode', function() {
it('should exist!', function() {
Expand All @@ -28,8 +29,8 @@ describe('LMLayerWorker', function () {
// While the config message doesn't trigger a reply message, we have to send it a configuration message first.
worker.postMessage({
message: 'config',
capabilities: helpers.defaultCapabilities
})
capabilities: defaultCapabilities
});
worker.postMessage({
message: 'load',
// Since the worker's based in a blob, it's not on the 'same domain'. We need to absolute-path the model file.
Expand Down
Loading

0 comments on commit 9e445db

Please sign in to comment.