656 lines
19 KiB
JavaScript
656 lines
19 KiB
JavaScript
|
/**
|
|||
|
* Copyright 2017 Google Inc. All Rights Reserved.
|
|||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
* you may not use this file except in compliance with the License.
|
|||
|
* You may obtain a copy of the License at
|
|||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
* Unless required by applicable law or agreed to in writing, software
|
|||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
* See the License for the specific language governing permissions and
|
|||
|
* limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
import * as Comlink from "/base/dist/esm/comlink.mjs";
|
|||
|
|
|||
|
class SampleClass {
|
|||
|
constructor(counterInit = 1) {
|
|||
|
this._counter = counterInit;
|
|||
|
this._promise = Promise.resolve(4);
|
|||
|
}
|
|||
|
|
|||
|
static get SOME_NUMBER() {
|
|||
|
return 4;
|
|||
|
}
|
|||
|
|
|||
|
static ADD(a, b) {
|
|||
|
return a + b;
|
|||
|
}
|
|||
|
|
|||
|
get counter() {
|
|||
|
return this._counter;
|
|||
|
}
|
|||
|
|
|||
|
set counter(value) {
|
|||
|
this._counter = value;
|
|||
|
}
|
|||
|
|
|||
|
get promise() {
|
|||
|
return this._promise;
|
|||
|
}
|
|||
|
|
|||
|
method() {
|
|||
|
return 4;
|
|||
|
}
|
|||
|
|
|||
|
increaseCounter(delta = 1) {
|
|||
|
this._counter += delta;
|
|||
|
}
|
|||
|
|
|||
|
promiseFunc() {
|
|||
|
return new Promise((resolve) => setTimeout((_) => resolve(4), 100));
|
|||
|
}
|
|||
|
|
|||
|
proxyFunc() {
|
|||
|
return Comlink.proxy({
|
|||
|
counter: 0,
|
|||
|
inc() {
|
|||
|
this.counter++;
|
|||
|
},
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
throwsAnError() {
|
|||
|
throw Error("OMG");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
describe("Comlink in the same realm", function () {
|
|||
|
beforeEach(function () {
|
|||
|
const { port1, port2 } = new MessageChannel();
|
|||
|
port1.start();
|
|||
|
port2.start();
|
|||
|
this.port1 = port1;
|
|||
|
this.port2 = port2;
|
|||
|
});
|
|||
|
|
|||
|
it("can work with objects", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose({ value: 4 }, this.port2);
|
|||
|
expect(await thing.value).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with functions on an object", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose({ f: (_) => 4 }, this.port2);
|
|||
|
expect(await thing.f()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with functions", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((_) => 4, this.port2);
|
|||
|
expect(await thing()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with objects that have undefined properties", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose({ x: undefined }, this.port2);
|
|||
|
expect(await thing.x).to.be.undefined;
|
|||
|
});
|
|||
|
|
|||
|
it("can keep the stack and message of thrown errors", async function () {
|
|||
|
let stack;
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((_) => {
|
|||
|
const error = Error("OMG");
|
|||
|
stack = error.stack;
|
|||
|
throw error;
|
|||
|
}, this.port2);
|
|||
|
try {
|
|||
|
await thing();
|
|||
|
throw "Should have thrown";
|
|||
|
} catch (err) {
|
|||
|
expect(err).to.not.eq("Should have thrown");
|
|||
|
expect(err.message).to.equal("OMG");
|
|||
|
expect(err.stack).to.equal(stack);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
it("can forward an async function error", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(
|
|||
|
{
|
|||
|
async throwError() {
|
|||
|
throw new Error("Should have thrown");
|
|||
|
},
|
|||
|
},
|
|||
|
this.port2
|
|||
|
);
|
|||
|
try {
|
|||
|
await thing.throwError();
|
|||
|
} catch (err) {
|
|||
|
expect(err.message).to.equal("Should have thrown");
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
it("can rethrow non-error objects", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((_) => {
|
|||
|
throw { test: true };
|
|||
|
}, this.port2);
|
|||
|
try {
|
|||
|
await thing();
|
|||
|
throw "Should have thrown";
|
|||
|
} catch (err) {
|
|||
|
expect(err).to.not.equal("Should have thrown");
|
|||
|
expect(err.test).to.equal(true);
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
it("can rethrow scalars", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((_) => {
|
|||
|
throw "oops";
|
|||
|
}, this.port2);
|
|||
|
try {
|
|||
|
await thing();
|
|||
|
throw "Should have thrown";
|
|||
|
} catch (err) {
|
|||
|
expect(err).to.not.equal("Should have thrown");
|
|||
|
expect(err).to.equal("oops");
|
|||
|
expect(typeof err).to.equal("string");
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
it("can rethrow null", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((_) => {
|
|||
|
throw null;
|
|||
|
}, this.port2);
|
|||
|
try {
|
|||
|
await thing();
|
|||
|
throw "Should have thrown";
|
|||
|
} catch (err) {
|
|||
|
expect(err).to.not.equal("Should have thrown");
|
|||
|
expect(err).to.equal(null);
|
|||
|
expect(typeof err).to.equal("object");
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
it("can work with parameterized functions", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((a, b) => a + b, this.port2);
|
|||
|
expect(await thing(1, 3)).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with functions that return promises", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(
|
|||
|
(_) => new Promise((resolve) => setTimeout((_) => resolve(4), 100)),
|
|||
|
this.port2
|
|||
|
);
|
|||
|
expect(await thing()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with classes", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.method()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can pass parameters to class constructor", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing(23);
|
|||
|
expect(await instance.counter).to.equal(23);
|
|||
|
});
|
|||
|
|
|||
|
it("can access a class in an object", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose({ SampleClass }, this.port2);
|
|||
|
const instance = await new thing.SampleClass();
|
|||
|
expect(await instance.method()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance properties", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance._counter).to.equal(1);
|
|||
|
});
|
|||
|
|
|||
|
it("can set class instance properties", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance._counter).to.equal(1);
|
|||
|
await (instance._counter = 4);
|
|||
|
expect(await instance._counter).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance methods", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.counter).to.equal(1);
|
|||
|
await instance.increaseCounter();
|
|||
|
expect(await instance.counter).to.equal(2);
|
|||
|
});
|
|||
|
|
|||
|
it("can handle throwing class instance methods", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
return instance
|
|||
|
.throwsAnError()
|
|||
|
.then((_) => Promise.reject())
|
|||
|
.catch((err) => {});
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance methods multiple times", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.counter).to.equal(1);
|
|||
|
await instance.increaseCounter();
|
|||
|
await instance.increaseCounter(5);
|
|||
|
expect(await instance.counter).to.equal(7);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance methods that return promises", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.promiseFunc()).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance properties that are promises", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance._promise).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance getters that are promises", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.promise).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with static class properties", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
expect(await thing.SOME_NUMBER).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with static class methods", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
expect(await thing.ADD(1, 3)).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with bound class instance methods", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.counter).to.equal(1);
|
|||
|
const method = instance.increaseCounter.bind(instance);
|
|||
|
await method();
|
|||
|
expect(await instance.counter).to.equal(2);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance getters", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance.counter).to.equal(1);
|
|||
|
await instance.increaseCounter();
|
|||
|
expect(await instance.counter).to.equal(2);
|
|||
|
});
|
|||
|
|
|||
|
it("can work with class instance setters", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
expect(await instance._counter).to.equal(1);
|
|||
|
await (instance.counter = 4);
|
|||
|
expect(await instance._counter).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
const hasBroadcastChannel = (_) => "BroadcastChannel" in self;
|
|||
|
guardedIt(hasBroadcastChannel)(
|
|||
|
"will work with BroadcastChannel",
|
|||
|
async function () {
|
|||
|
const b1 = new BroadcastChannel("comlink_bc_test");
|
|||
|
const b2 = new BroadcastChannel("comlink_bc_test");
|
|||
|
const thing = Comlink.wrap(b1);
|
|||
|
Comlink.expose((b) => 40 + b, b2);
|
|||
|
expect(await thing(2)).to.equal(42);
|
|||
|
}
|
|||
|
);
|
|||
|
|
|||
|
// Buffer transfers seem to have regressed in Safari 11.1, it’s fixed in 11.2.
|
|||
|
const isNotSafari11_1 = (_) =>
|
|||
|
!/11\.1(\.[0-9]+)? Safari/.test(navigator.userAgent);
|
|||
|
guardedIt(isNotSafari11_1)("will transfer buffers", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((b) => b.byteLength, this.port2);
|
|||
|
const buffer = new Uint8Array([1, 2, 3]).buffer;
|
|||
|
expect(await thing(Comlink.transfer(buffer, [buffer]))).to.equal(3);
|
|||
|
expect(buffer.byteLength).to.equal(0);
|
|||
|
});
|
|||
|
|
|||
|
guardedIt(isNotSafari11_1)("will copy TypedArrays", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((b) => b, this.port2);
|
|||
|
const array = new Uint8Array([1, 2, 3]);
|
|||
|
const receive = await thing(array);
|
|||
|
expect(array).to.not.equal(receive);
|
|||
|
expect(array.byteLength).to.equal(receive.byteLength);
|
|||
|
expect([...array]).to.deep.equal([...receive]);
|
|||
|
});
|
|||
|
|
|||
|
guardedIt(isNotSafari11_1)("will copy nested TypedArrays", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((b) => b, this.port2);
|
|||
|
const array = new Uint8Array([1, 2, 3]);
|
|||
|
const receive = await thing({
|
|||
|
v: 1,
|
|||
|
array,
|
|||
|
});
|
|||
|
expect(array).to.not.equal(receive.array);
|
|||
|
expect(array.byteLength).to.equal(receive.array.byteLength);
|
|||
|
expect([...array]).to.deep.equal([...receive.array]);
|
|||
|
});
|
|||
|
|
|||
|
guardedIt(isNotSafari11_1)(
|
|||
|
"will transfer deeply nested buffers",
|
|||
|
async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((a) => a.b.c.d.byteLength, this.port2);
|
|||
|
const buffer = new Uint8Array([1, 2, 3]).buffer;
|
|||
|
expect(
|
|||
|
await thing(Comlink.transfer({ b: { c: { d: buffer } } }, [buffer]))
|
|||
|
).to.equal(3);
|
|||
|
expect(buffer.byteLength).to.equal(0);
|
|||
|
}
|
|||
|
);
|
|||
|
|
|||
|
it("will transfer a message port", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose((a) => a.postMessage("ohai"), this.port2);
|
|||
|
const { port1, port2 } = new MessageChannel();
|
|||
|
await thing(Comlink.transfer(port2, [port2]));
|
|||
|
return new Promise((resolve) => {
|
|||
|
port1.onmessage = (event) => {
|
|||
|
expect(event.data).to.equal("ohai");
|
|||
|
resolve();
|
|||
|
};
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap marked return values", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(
|
|||
|
(_) =>
|
|||
|
Comlink.proxy({
|
|||
|
counter: 0,
|
|||
|
inc() {
|
|||
|
this.counter += 1;
|
|||
|
},
|
|||
|
}),
|
|||
|
this.port2
|
|||
|
);
|
|||
|
const obj = await thing();
|
|||
|
expect(await obj.counter).to.equal(0);
|
|||
|
await obj.inc();
|
|||
|
expect(await obj.counter).to.equal(1);
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap marked return values from class instance methods", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
const obj = await instance.proxyFunc();
|
|||
|
expect(await obj.counter).to.equal(0);
|
|||
|
await obj.inc();
|
|||
|
expect(await obj.counter).to.equal(1);
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap marked parameter values", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
const local = {
|
|||
|
counter: 0,
|
|||
|
inc() {
|
|||
|
this.counter++;
|
|||
|
},
|
|||
|
};
|
|||
|
Comlink.expose(async function (f) {
|
|||
|
await f.inc();
|
|||
|
}, this.port2);
|
|||
|
expect(local.counter).to.equal(0);
|
|||
|
await thing(Comlink.proxy(local));
|
|||
|
expect(await local.counter).to.equal(1);
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap marked assignments", function (done) {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
const obj = {
|
|||
|
onready: null,
|
|||
|
call() {
|
|||
|
this.onready();
|
|||
|
},
|
|||
|
};
|
|||
|
Comlink.expose(obj, this.port2);
|
|||
|
|
|||
|
thing.onready = Comlink.proxy(() => done());
|
|||
|
thing.call();
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap marked parameter values, simple function", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(async function (f) {
|
|||
|
await f();
|
|||
|
}, this.port2);
|
|||
|
// Weird code because Mocha
|
|||
|
await new Promise(async (resolve) => {
|
|||
|
thing(Comlink.proxy((_) => resolve()));
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
it("will wrap multiple marked parameter values, simple function", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(async function (f1, f2, f3) {
|
|||
|
return (await f1()) + (await f2()) + (await f3());
|
|||
|
}, this.port2);
|
|||
|
// Weird code because Mocha
|
|||
|
expect(
|
|||
|
await thing(
|
|||
|
Comlink.proxy((_) => 1),
|
|||
|
Comlink.proxy((_) => 2),
|
|||
|
Comlink.proxy((_) => 3)
|
|||
|
)
|
|||
|
).to.equal(6);
|
|||
|
});
|
|||
|
|
|||
|
it("will proxy deeply nested values", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
const obj = {
|
|||
|
a: {
|
|||
|
v: 4,
|
|||
|
},
|
|||
|
b: Comlink.proxy({
|
|||
|
v: 5,
|
|||
|
}),
|
|||
|
};
|
|||
|
Comlink.expose(obj, this.port2);
|
|||
|
|
|||
|
const a = await thing.a;
|
|||
|
const b = await thing.b;
|
|||
|
expect(await a.v).to.equal(4);
|
|||
|
expect(await b.v).to.equal(5);
|
|||
|
await (a.v = 8);
|
|||
|
await (b.v = 9);
|
|||
|
// Workaround for a weird scheduling inconsistency in Firefox.
|
|||
|
// This test failed, but not when run in isolation, and only
|
|||
|
// in Firefox. I think there might be problem with task ordering.
|
|||
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
|||
|
expect(await thing.a.v).to.equal(4);
|
|||
|
expect(await thing.b.v).to.equal(9);
|
|||
|
});
|
|||
|
|
|||
|
it("will handle undefined parameters", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose({ f: (_) => 4 }, this.port2);
|
|||
|
expect(await thing.f(undefined)).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can handle destructuring", async function () {
|
|||
|
Comlink.expose(
|
|||
|
{
|
|||
|
a: 4,
|
|||
|
get b() {
|
|||
|
return 5;
|
|||
|
},
|
|||
|
c() {
|
|||
|
return 6;
|
|||
|
},
|
|||
|
},
|
|||
|
this.port2
|
|||
|
);
|
|||
|
const { a, b, c } = Comlink.wrap(this.port1);
|
|||
|
expect(await a).to.equal(4);
|
|||
|
expect(await b).to.equal(5);
|
|||
|
expect(await c()).to.equal(6);
|
|||
|
});
|
|||
|
|
|||
|
it("lets users define transfer handlers", function (done) {
|
|||
|
Comlink.transferHandlers.set("event", {
|
|||
|
canHandle(obj) {
|
|||
|
return obj instanceof Event;
|
|||
|
},
|
|||
|
serialize(obj) {
|
|||
|
return [obj.data, []];
|
|||
|
},
|
|||
|
deserialize(data) {
|
|||
|
return new MessageEvent("message", { data });
|
|||
|
},
|
|||
|
});
|
|||
|
|
|||
|
Comlink.expose((ev) => {
|
|||
|
expect(ev).to.be.an.instanceOf(Event);
|
|||
|
expect(ev.data).to.deep.equal({ a: 1 });
|
|||
|
done();
|
|||
|
}, this.port1);
|
|||
|
const thing = Comlink.wrap(this.port2);
|
|||
|
|
|||
|
const { port1, port2 } = new MessageChannel();
|
|||
|
port1.addEventListener("message", thing.bind(this));
|
|||
|
port1.start();
|
|||
|
port2.postMessage({ a: 1 });
|
|||
|
});
|
|||
|
|
|||
|
it("can tunnels a new endpoint with createEndpoint", async function () {
|
|||
|
Comlink.expose(
|
|||
|
{
|
|||
|
a: 4,
|
|||
|
c() {
|
|||
|
return 5;
|
|||
|
},
|
|||
|
},
|
|||
|
this.port2
|
|||
|
);
|
|||
|
const proxy = Comlink.wrap(this.port1);
|
|||
|
const otherEp = await proxy[Comlink.createEndpoint]();
|
|||
|
const otherProxy = Comlink.wrap(otherEp);
|
|||
|
expect(await otherProxy.a).to.equal(4);
|
|||
|
expect(await proxy.a).to.equal(4);
|
|||
|
expect(await otherProxy.c()).to.equal(5);
|
|||
|
expect(await proxy.c()).to.equal(5);
|
|||
|
});
|
|||
|
|
|||
|
it("released proxy should no longer be useable and throw an exception", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1);
|
|||
|
Comlink.expose(SampleClass, this.port2);
|
|||
|
const instance = await new thing();
|
|||
|
await instance[Comlink.releaseProxy]();
|
|||
|
expect(() => instance.method()).to.throw();
|
|||
|
});
|
|||
|
|
|||
|
it("released proxy should invoke finalizer", async function () {
|
|||
|
let finalized = false;
|
|||
|
Comlink.expose(
|
|||
|
{
|
|||
|
a: "thing",
|
|||
|
[Comlink.finalizer]: () => {
|
|||
|
finalized = true;
|
|||
|
},
|
|||
|
},
|
|||
|
this.port2
|
|||
|
);
|
|||
|
const instance = Comlink.wrap(this.port1);
|
|||
|
expect(await instance.a).to.equal("thing");
|
|||
|
await instance[Comlink.releaseProxy]();
|
|||
|
// wait a beat to let the events process
|
|||
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
|||
|
expect(finalized).to.be.true;
|
|||
|
});
|
|||
|
|
|||
|
// commented out this test as it could be unreliable in various browsers as
|
|||
|
// it has to wait for GC to kick in which could happen at any timing
|
|||
|
// this does seem to work when testing locally
|
|||
|
it.skip("released proxy via GC should invoke finalizer", async function () {
|
|||
|
let finalized = false;
|
|||
|
Comlink.expose(
|
|||
|
{
|
|||
|
a: "thing",
|
|||
|
[Comlink.finalizer]: () => {
|
|||
|
finalized = true;
|
|||
|
},
|
|||
|
},
|
|||
|
this.port2
|
|||
|
);
|
|||
|
|
|||
|
let registry;
|
|||
|
|
|||
|
// set a long enough timeout to wait for a garbage collection
|
|||
|
this.timeout(10000);
|
|||
|
// promise will resolve when the proxy is garbage collected
|
|||
|
await new Promise(async (resolve, reject) => {
|
|||
|
registry = new FinalizationRegistry((heldValue) => {
|
|||
|
heldValue();
|
|||
|
});
|
|||
|
|
|||
|
const instance = Comlink.wrap(this.port1);
|
|||
|
registry.register(instance, resolve);
|
|||
|
expect(await instance.a).to.equal("thing");
|
|||
|
});
|
|||
|
// wait a beat to let the events process
|
|||
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
|||
|
expect(finalized).to.be.true;
|
|||
|
});
|
|||
|
|
|||
|
it("can proxy with a given target", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1, { value: {} });
|
|||
|
Comlink.expose({ value: 4 }, this.port2);
|
|||
|
expect(await thing.value).to.equal(4);
|
|||
|
});
|
|||
|
|
|||
|
it("can handle unserializable types", async function () {
|
|||
|
const thing = Comlink.wrap(this.port1, { value: {} });
|
|||
|
Comlink.expose({ value: () => "boom" }, this.port2);
|
|||
|
|
|||
|
try {
|
|||
|
await thing.value;
|
|||
|
} catch (err) {
|
|||
|
expect(err.message).to.equal("Unserializable return value");
|
|||
|
}
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
function guardedIt(f) {
|
|||
|
return f() ? it : xit;
|
|||
|
}
|