Add a real test!

This commit is contained in:
Timothy Farrell 2016-12-27 22:07:25 -06:00
parent 2034139846
commit 342c46df6f
3 changed files with 97 additions and 24 deletions

View File

@ -15,7 +15,8 @@
"build:umd:gzip": "build:umd:gzip":
"npm run build:umd:min && gzip -c9 dist/worker-portal.min.js > dist/worker-portal.min.js.gz", "npm run build:umd:min && gzip -c9 dist/worker-portal.min.js > dist/worker-portal.min.js.gz",
"build": "npm run build:umd:gzip && ls -l dist/", "build": "npm run build:umd:gzip && ls -l dist/",
"prepublish": "npm run clean && npm run build" "prepublish": "npm run clean && npm run build",
"test": "npm run build:lib && ava --verbose"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -29,6 +30,7 @@
}, },
"homepage": "https://gitlab.com/explorigin/worker-portal", "homepage": "https://gitlab.com/explorigin/worker-portal",
"devDependencies": { "devDependencies": {
"ava": "^0.17.0",
"babel-cli": "6.18.0", "babel-cli": "6.18.0",
"babel-core": "6.21.0", "babel-core": "6.21.0",
"babel-eslint": "7.1.1", "babel-eslint": "7.1.1",

View File

@ -12,14 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
export function isWorker() {
try {
return self !== window;
} catch (e) {
return true;
}
}
function tryJSON(type, destination, id, data) { function tryJSON(type, destination, id, data) {
const packet = [type, destination, id, data]; const packet = [type, destination, id, data];
try { try {
@ -29,7 +21,7 @@ function tryJSON(type, destination, id, data) {
} }
} }
export function WorkerPortal(context, worker, serialize) { export function WorkerPortal(context, worker, isSlave, serialize) {
const responseMap = new Map(); const responseMap = new Map();
const _worker = worker || self; const _worker = worker || self;
const contextIndex = Object.keys(context); const contextIndex = Object.keys(context);
@ -84,29 +76,25 @@ export function WorkerPortal(context, worker, serialize) {
} }
function injectionPointFactory(fnId, callbackFactory) { function injectionPointFactory(fnId, callbackFactory) {
return () => return function(...args) {
new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!enabled) { if (!enabled && fnId !== 0) {
reject(new Error('Portal disabled')); reject(new Error('Portal disabled'));
} }
const id = callCount; const id = callCount;
callCount += 1; callCount += 1;
responseMap.set(id, [callbackFactory ? callbackFactory(resolve) : resolve, reject]); responseMap.set(id, [callbackFactory ? callbackFactory(resolve) : resolve, reject]);
post(0, id, fnId, Array.from(arguments)); post(0, id, fnId, args);
}); });
};
} }
function resolveExternalInterfaceFactory(resolve) { function resolveExternalInterfaceFactory(resolve) {
return linkedFunctionNames => { return (linkedFunctionNames, ...rest) => {
const externalInterface = {}; const externalInterface = {};
linkedFunctionNames.forEach((fnName, index) => { linkedFunctionNames.forEach((fnName, index) => {
externalInterface[fnName] = injectionPointFactory(index); externalInterface[fnName] = injectionPointFactory(index);
}); });
if (!isWorker()) {
externalInterface._cleanup = injectionPointFactory(linkedFunctionNames.length, resolve =>
resolve(cleanup())
);
}
enabled = true; enabled = true;
resolve(externalInterface); resolve(externalInterface);
return contextIndex; return contextIndex;
@ -125,13 +113,16 @@ export function WorkerPortal(context, worker, serialize) {
_worker.addEventListener('message', dispatcher); _worker.addEventListener('message', dispatcher);
if (isWorker()) { if (isSlave) {
return new Promise(resolve => { return new Promise(resolve => {
contextIndex.splice(0, 0, '__init', '__cleanup'); contextIndex.splice(0, 0, '__init', '__cleanupSlave');
context.__init = resolveExternalInterfaceFactory(resolve); context.__init = resolveExternalInterfaceFactory(resolve);
context.__cleanup = cleanup; context.__cleanupSlave = cleanup;
}); });
} }
return injectionPointFactory(0, resolveExternalInterfaceFactory)(contextIndex); return injectionPointFactory(0, resolveExternalInterfaceFactory)(contextIndex).then(api => ({
...api,
_cleanup: injectionPointFactory(1, resolve => resolve(cleanup()))
}));
} }

80
packages/portal/test.js Normal file
View File

@ -0,0 +1,80 @@
import test from 'ava';
import { WorkerPortal } from './lib';
function FakeWorkerPair() {
let cbA = null;
let cbB = null;
const objA = {
postMessage: data => {
cbB({ data: data });
},
addEventListener: (eventName, fn) => {
cbA = (...r) => {
fn(...r);
};
},
removeEventListener: (eventName, fn) => {
cbA = null;
}
};
const objB = {
postMessage: data => {
cbA({ data: data });
},
addEventListener: (eventName, fn) => {
cbB = (...r) => {
fn(...r);
};
},
removeEventListener: (eventName, fn) => {
cbB = null;
}
};
return [objA, objB];
}
test('Workers can call and respond equally', async t => {
const [a, b] = FakeWorkerPair();
const slave = WorkerPortal(
{
slaveAdd: (a, b) => a + b
},
a,
true
);
const master = WorkerPortal(
{
masterSubtract: (a, b) => a - b
},
b,
false
);
const masterApi = await master;
const slaveApi = await slave;
t.deepEqual(Object.keys(masterApi), ['__init', '__cleanupSlave', 'slaveAdd', '_cleanup']);
t.deepEqual(Object.keys(slaveApi), ['masterSubtract']);
t.is(await slaveApi.masterSubtract(9, 2), 7);
t.is(await masterApi.slaveAdd(9, 2), 11);
t.is(await masterApi.slaveAdd(5, 2), 7);
t.is(await slaveApi.masterSubtract(2, 2), 0);
await masterApi._cleanup();
return masterApi
.slaveAdd(9, 2)
.then(e => {
t.fail('Expected rejection');
})
.catch(e => {
t.is(e.message, 'Portal disabled');
});
});