diff --git a/README.md b/README.md index c96d6de..614e822 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Both the parent window and iFrame must load COMB.

Chaperone!

diff --git a/src/index.ts b/src/index.ts index 19d0896..6041616 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,8 +73,8 @@ const COMB = { * @example * const child = await COMB.connect( "http://localhost:8002" ); */ - async connect(url, timeout) { - const child = new ChildAPI(url, timeout); + async connect(url, timeout, signalCb) { + const child = new ChildAPI(url, timeout, signalCb); await child.connect(); return child; }, @@ -115,21 +115,23 @@ class ChildAPI { handshake: any; class_name: string; loaded: boolean; + signalCb: any; /** * Initialize a child frame using the given URL. * * @class ChildAPI * - * @param {string} url - URL that is used as 'src' for the iframe + * @param {string} url - URL that is used as 'src' for the iframe * - * @prop {string} url - iFrame URL - * @prop {number} msg_count - Incrementing message ID - * @prop {object} responses - Dictionary of request Promises waiting for their responses - * @prop {object} msg_bus - Postmate instance - * @prop {promise} handshake - Promise that is waiting for connection confirmation - * @prop {string} class_name - iFrame's unique class name - * @prop {boolean} loaded - Indicates if iFrame successfully loaded + * @prop {string} url - iFrame URL + * @prop {number} msg_count - Incrementing message ID + * @prop {object} responses - Dictionary of request Promises waiting for their responses + * @prop {object} msg_bus - Postmate instance + * @prop {promise} handshake - Promise that is waiting for connection confirmation + * @prop {string} class_name - iFrame's unique class name + * @prop {boolean} loaded - Indicates if iFrame successfully loaded + * @prop {any} signalCb - A callback that's run when we receive a signal * * @example * const child = new ChildAPI( url ); @@ -138,12 +140,14 @@ class ChildAPI { * await child.set("mode", mode ); * let response = await child.run("signIn"); */ - constructor(url, timeout = 5_000) { + constructor(url, timeout = 5_000, signalCb) { this.url = url; this.msg_count = 0; this.responses = {}; this.loaded = false; + this.signalCb = signalCb; + this.class_name = "comb-frame-" + ChildAPI.frame_count++; this.handshake = async_with_timeout(async () => { // log.info("Init Postmate handshake"); @@ -186,8 +190,7 @@ class ChildAPI { if (this.loaded) { // log.error("iFrame loaded but could not communicate with COMB"); throw new TimeoutError("Failed to complete COMB handshake", err.timeout); - } - else { + } else { // log.error("iFrame did not trigger load event"); throw new TimeoutError("Failed to load iFrame", err.timeout); } @@ -212,6 +215,10 @@ class ChildAPI { delete this.responses[k]; }); + if (this.signalCb) { + child.on('signal', this.signalCb) + } + this.msg_bus = child; return this; @@ -223,9 +230,9 @@ class ChildAPI { * @async * @private * - * @param {string} method - Internally consistent Postmate method - * @param {string} name - Function name or property name - * @param {*} data - Variable input that is handled by child API + * @param {string} method - Internally consistent Postmate method + * @param {string} name - Function name or property name + * @param {*} data - Variable input that is handled by child API * * @return {*} Response from child */ @@ -256,8 +263,8 @@ class ChildAPI { * * @async * - * @param {string} key - Property name - * @param {*} value - Property value + * @param {string} key - Property name + * @param {*} value - Property value * * @return {boolean} Success status * @@ -303,13 +310,13 @@ class ParentAPI { * * @class ParentAPI * - * @param {object} methods - Functions that are available for the parent to call. - * @param {object} properties - Properties to memorize in the instance for later use, optional + * @param {object} methods - Functions that are available for the parent to call. + * @param {object} properties - Properties to memorize in the instance for later use, optional * - * @prop {promise} listener - Promise that is waiting for parent to connect - * @prop {object} msg_bus - Postmate instance - * @prop {object} methods - Method storage - * @prop {object} properties - Set properties storage + * @prop {promise} listener - Promise that is waiting for parent to connect + * @prop {object} msg_bus - Postmate instance + * @prop {object} methods - Method storage + * @prop {object} properties - Set properties storage * * @example * const parent = new ParentAPI({ @@ -320,6 +327,7 @@ class ParentAPI { * await parent.connect(); */ constructor(methods, properties = {}) { + this.methods = methods; this.properties = properties; @@ -367,12 +375,31 @@ class ParentAPI { * }); * await parent.connect(); */ - async connect() { + async connect () { this.msg_bus = await this.listener; return this; } + /** + * Send holochain conductor signal to parent. + * + * @async + * + * @param {object} signal - The signal + * + * @example + * const parent = new ParentAPI({ + * "hello": async function () { + * return "Hello world"; + * } + * }); + * await parent.sendSignal(signal); + */ + async sendSignal (signal) { + this.msg_bus.emit('signal', signal) + } + } export { diff --git a/tests/integration/test_comb.js b/tests/integration/test_comb.js index 5611369..18f4428 100644 --- a/tests/integration/test_comb.js +++ b/tests/integration/test_comb.js @@ -159,6 +159,28 @@ describe("Testing COMB", function () { } }); + it("should call the provided signalCb when sendSignal is called on the parent", async function () { + try { + // have to setup our spy function in the puppeteer evaluation context + await page.evaluate(() => { + window.signalCb = function(signal) { + window.signalCbCalledWith = signal + } + }); + + const expectedSignal = "Hello COMB"; + + const signalCbCalledWith = await page.evaluate(async function (chap_url, expectedSignal) { + window.child = await COMB.connect(chap_url, 5000, window.signalCb); + await child.run("test_signal", expectedSignal); + return window.signalCbCalledWith + }, chap_url, expectedSignal); + + expect(signalCbCalledWith).to.equal(expectedSignal); + } finally { + } + }); + it("should timeout because of wrong frame URL", async function () { try { const result = await page.evaluate(async function () {