diff --git a/tensorboard/components/plugin_lib/BUILD b/tensorboard/components/plugin_lib/BUILD
new file mode 100644
index 0000000000..f609151c57
--- /dev/null
+++ b/tensorboard/components/plugin_lib/BUILD
@@ -0,0 +1,32 @@
+package(default_visibility = ["//tensorboard:internal"])
+
+load("//tensorboard/defs:web.bzl", "tf_web_library")
+
+licenses(["notice"]) # Apache 2.0
+
+# TODO(stephanwlee): figure out how this tf_web_library can be used to create
+# maybe a NPM package.
+tf_web_library(
+ name = "plugin_lib",
+ srcs = [
+ "runs.ts",
+ "tf-plugin-lib.html",
+ ],
+ path = "/",
+ deps = [
+ "//tensorboard/components/plugin_util:plugin_guest",
+ ],
+)
+
+tf_web_library(
+ name = "host_impls",
+ srcs = [
+ "runs-host-impl.ts",
+ "tf-plugin-host-impls.html",
+ ],
+ path = "/tf-plugin-lib",
+ deps = [
+ "//tensorboard/components/plugin_util:plugin_host",
+ "//tensorboard/components/tf_backend",
+ ],
+)
diff --git a/tensorboard/components/plugin_lib/runs-host-impl.ts b/tensorboard/components/plugin_lib/runs-host-impl.ts
new file mode 100644
index 0000000000..d5faf6f6ed
--- /dev/null
+++ b/tensorboard/components/plugin_lib/runs-host-impl.ts
@@ -0,0 +1,27 @@
+/* Copyright 2017 The TensorFlow Authors. 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.
+==============================================================================*/
+/**
+ * Implements run related plugin APIs.
+ */
+tb.plugin.lib.host.listen('experimental.GetRuns', () => {
+ return tf_backend.runsStore.getRuns();
+});
+
+tf_backend.runsStore.addListener(() => {
+ return tb.plugin.lib.host.broadcast(
+ 'experimental.RunsChange',
+ tf_backend.runsStore.getRuns()
+ );
+});
diff --git a/tensorboard/components/plugin_util/test/iframe.ts b/tensorboard/components/plugin_lib/runs.ts
similarity index 68%
rename from tensorboard/components/plugin_util/test/iframe.ts
rename to tensorboard/components/plugin_lib/runs.ts
index c1c979687c..1a7ae23955 100644
--- a/tensorboard/components/plugin_util/test/iframe.ts
+++ b/tensorboard/components/plugin_lib/runs.ts
@@ -12,8 +12,12 @@ 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.
==============================================================================*/
+namespace tb.plugin.lib.run {
+ export async function getRuns() {
+ return tb.plugin.lib.internal.sendMessage('experimental.GetRuns');
+ }
-import {sendMessage, listen, unlisten, _guestIPC} from '../plugin-guest.js';
-
-const win = window as any;
-win.test = {sendMessage, listen, unlisten, _guestIPC};
+ export function addRunsChangeListener(callback: (runs: string[]) => void) {
+ return tb.plugin.lib.internal.listen('experimental.RunsChange', callback);
+ }
+}
diff --git a/tensorboard/components/plugin_lib/test/BUILD b/tensorboard/components/plugin_lib/test/BUILD
new file mode 100644
index 0000000000..85d3d5461b
--- /dev/null
+++ b/tensorboard/components/plugin_lib/test/BUILD
@@ -0,0 +1,22 @@
+package(default_visibility = ["//tensorboard:internal"])
+
+load("//tensorboard/defs:web.bzl", "tf_web_library")
+
+licenses(["notice"]) # Apache 2.0
+
+tf_web_library(
+ name = "test",
+ testonly = True,
+ srcs = [
+ "test.html",
+ "test.ts",
+ "testable-iframe.html",
+ ],
+ path = "/tf-plugin-lib/test",
+ deps = [
+ "//tensorboard/components/plugin_lib",
+ "//tensorboard/components/plugin_lib:host_impls",
+ "//tensorboard/components/tf_backend",
+ "//tensorboard/components/tf_imports:web_component_tester",
+ ],
+)
diff --git a/tensorboard/components/plugin_lib/test/test.html b/tensorboard/components/plugin_lib/test/test.html
new file mode 100644
index 0000000000..4c443aa806
--- /dev/null
+++ b/tensorboard/components/plugin_lib/test/test.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/tensorboard/components/plugin_lib/test/test.ts b/tensorboard/components/plugin_lib/test/test.ts
new file mode 100644
index 0000000000..bded353153
--- /dev/null
+++ b/tensorboard/components/plugin_lib/test/test.ts
@@ -0,0 +1,72 @@
+/* Copyright 2019 The TensorFlow Authors. 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.
+==============================================================================*/
+
+async function createIframe(): Promise {
+ return new Promise((resolve) => {
+ const iframe = document.createElement('iframe') as HTMLIFrameElement;
+ document.body.appendChild(iframe);
+ iframe.src = './testable-iframe.html';
+ iframe.onload = () => resolve(iframe);
+ });
+}
+
+describe('plugin lib integration', () => {
+ const {expect} = chai;
+
+ beforeEach(async function() {
+ this.sandbox = sinon.sandbox.create({useFakeServer: true});
+ this.sandbox.server.respondImmediately = true;
+ this.iframe = await createIframe();
+ });
+
+ afterEach(function() {
+ document.body.removeChild(this.iframe);
+ this.sandbox.restore();
+ });
+
+ describe('tb.plugin.lib.run', () => {
+ describe('#getRuns', () => {
+ it('returns list of runs', async function() {
+ this.sandbox
+ .stub(tf_backend.runsStore, 'getRuns')
+ .returns(['foo', 'bar', 'baz']);
+
+ const runs = await (this.iframe.contentWindow as any).getRuns();
+
+ expect(runs).to.deep.equal(['foo', 'bar', 'baz']);
+ });
+ });
+ describe('#addRunsChangeListener', () => {
+ it('lets plugins to subscribe to runs change', async function() {
+ const runsChanged = this.sandbox.stub();
+ const promise = new Promise((resolve) => {
+ (this.iframe.contentWindow as any).addRunsChangeListener(resolve);
+ }).then(runsChanged);
+ this.sandbox.server.respondWith([
+ 200,
+ {'Content-Type': 'application/json'},
+ '["foo", "bar"]',
+ ]);
+
+ await tf_backend.runsStore.refresh();
+ await promise;
+
+ expect(runsChanged).to.have.been.calledOnce;
+ expect(runsChanged).to.have.been.calledWith(['foo', 'bar']);
+ });
+ });
+ });
+});
+1;
diff --git a/tensorboard/components/plugin_lib/test/testable-iframe.html b/tensorboard/components/plugin_lib/test/testable-iframe.html
new file mode 100644
index 0000000000..ab1d38f27c
--- /dev/null
+++ b/tensorboard/components/plugin_lib/test/testable-iframe.html
@@ -0,0 +1,21 @@
+
+
+
diff --git a/tensorboard/components/plugin_lib/tf-plugin-host-impls.html b/tensorboard/components/plugin_lib/tf-plugin-host-impls.html
new file mode 100644
index 0000000000..9786493117
--- /dev/null
+++ b/tensorboard/components/plugin_lib/tf-plugin-host-impls.html
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/tensorboard/components/plugin_lib/tf-plugin-lib.html b/tensorboard/components/plugin_lib/tf-plugin-lib.html
new file mode 100644
index 0000000000..8576315366
--- /dev/null
+++ b/tensorboard/components/plugin_lib/tf-plugin-lib.html
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/tensorboard/components/plugin_util/BUILD b/tensorboard/components/plugin_util/BUILD
index 622dfeef6e..df5e9e0fb1 100644
--- a/tensorboard/components/plugin_util/BUILD
+++ b/tensorboard/components/plugin_util/BUILD
@@ -5,24 +5,12 @@ load("//tensorboard/defs:web.bzl", "tf_web_library")
licenses(["notice"]) # Apache 2.0
tf_web_library(
- name = "plugin_host",
- srcs = [
- "plugin-host.html",
- "plugin-host.ts",
- ],
- path = "/tf-plugin",
- deps = [
- ":plugin_lib",
- "//tensorboard/components/tf_backend",
- ],
-)
-
-tf_web_library(
- name = "plugin_lib",
+ name = "message",
srcs = [
+ "message.html",
"message.ts",
],
- path = "/tf-plugin",
+ path = "/tf-plugin-lib",
)
tf_web_library(
@@ -31,9 +19,20 @@ tf_web_library(
"plugin-guest.html",
"plugin-guest.ts",
],
- path = "/tf-plugin",
- visibility = ["//visibility:public"],
- deps = [
- ":plugin_lib",
+ path = "/tf-plugin-lib",
+ visibility = [
+ "//tensorboard/components/plugin_lib:__subpackages__",
+ "//tensorboard/components/plugin_util/test:__subpackages__",
+ ],
+ deps = [":message"],
+)
+
+tf_web_library(
+ name = "plugin_host",
+ srcs = [
+ "plugin-host.html",
+ "plugin-host.ts",
],
+ path = "/tf-plugin-lib",
+ deps = [":message"],
)
diff --git a/tensorboard/components/plugin_util/message.html b/tensorboard/components/plugin_util/message.html
new file mode 100644
index 0000000000..bd98b715f5
--- /dev/null
+++ b/tensorboard/components/plugin_util/message.html
@@ -0,0 +1,17 @@
+
+
diff --git a/tensorboard/components/plugin_util/message.ts b/tensorboard/components/plugin_util/message.ts
index d9efb9612c..b9dac401da 100644
--- a/tensorboard/components/plugin_util/message.ts
+++ b/tensorboard/components/plugin_util/message.ts
@@ -12,112 +12,108 @@ 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.
==============================================================================*/
-
-export type PayloadType =
- | null
- | undefined
- | string
- | string[]
- | boolean
- | boolean[]
- | number
- | number[]
- | object
- | object[];
-
-export interface Message {
- type: string;
- id: string;
- payload: PayloadType;
- error: string | null;
-}
-
-export type MessageType = string;
-export type MessageCallback = (payload: any) => any;
-
-interface PromiseResolver {
- resolve: (data: any) => void;
- reject: (error: Error) => void;
-}
-
-export abstract class IPC {
- private idPrefix: string;
- private id = 0;
- private readonly responseWaits = new Map();
- private readonly listeners = new Map();
-
- constructor() {
- window.addEventListener('message', this.onMessage.bind(this));
-
- // TODO(tensorboard-team): remove this by using MessageChannel.
- const randomArray = new Uint8Array(16);
- window.crypto.getRandomValues(randomArray);
- this.idPrefix = Array.from(randomArray)
- .map((int: number) => int.toString(16))
- .join('');
+namespace tb.plugin.lib.internal {
+ /**
+ * This file defines utilities shared by TensorBoard (plugin host) and the
+ * dynamic plugin library, used by plugin authors.
+ */
+
+ export type PayloadType =
+ | null
+ | undefined
+ | string
+ | string[]
+ | boolean
+ | boolean[]
+ | number
+ | number[]
+ | object
+ | object[];
+
+ export interface Message {
+ type: string;
+ id: string;
+ payload: PayloadType;
+ error: string | null;
+ isReply: boolean;
}
- listen(type: MessageType, callback: MessageCallback) {
- this.listeners.set(type, callback);
- }
+ export type MessageType = string;
+ export type MessageCallback = (payload: any) => any;
- unlisten(type: MessageType) {
- this.listeners.delete(type);
+ interface PromiseResolver {
+ resolve: (data: any) => void;
+ reject: (error: Error) => void;
}
- private async onMessage(event: MessageEvent) {
- // There are instances where random browser extensions send messages.
- if (typeof event.data !== 'string') return;
-
- const message = JSON.parse(event.data) as Message;
- const callback = this.listeners.get(message.type);
-
- if (this.responseWaits.has(message.id)) {
- const {id, payload, error} = message;
- const {resolve, reject} = this.responseWaits.get(id);
- this.responseWaits.delete(id);
- if (error) {
- reject(new Error(error));
- } else {
- resolve(payload);
- }
- return;
+ export class IPC {
+ private id = 0;
+ private readonly responseWaits = new Map();
+ private readonly listeners = new Map();
+ private readonly port: MessagePort;
+
+ constructor(port) {
+ this.port = port;
+ port.addEventListener('message', this.onMessage.bind(this));
+ }
+
+ listen(type: MessageType, callback: MessageCallback) {
+ this.listeners.set(type, callback);
+ }
+
+ unlisten(type: MessageType) {
+ this.listeners.delete(type);
}
- let payload = null;
- let error = null;
- if (this.listeners.has(message.type)) {
+ private async onMessage(event: MessageEvent) {
+ const message = JSON.parse(event.data) as Message;
const callback = this.listeners.get(message.type);
- try {
- const result = await callback(message.payload);
- payload = result;
- } catch (e) {
- error = e;
+
+ if (message.isReply) {
+ if (!this.responseWaits.has(message.id)) return;
+ const {id, payload, error} = message;
+ const {resolve, reject} = this.responseWaits.get(id);
+ this.responseWaits.delete(id);
+ if (error) {
+ reject(new Error(error));
+ } else {
+ resolve(payload);
+ }
+ return;
+ }
+
+ let payload = null;
+ let error = null;
+ if (this.listeners.has(message.type)) {
+ const callback = this.listeners.get(message.type);
+ try {
+ const result = await callback(message.payload);
+ payload = result;
+ } catch (e) {
+ error = e;
+ }
}
+ const replyMessage: Message = {
+ type: message.type,
+ id: message.id,
+ payload,
+ error,
+ isReply: true,
+ };
+ this.postMessage(replyMessage);
}
- const replyMessage: Message = {
- type: message.type,
- id: message.id,
- payload,
- error,
- };
- this.postMessage(event.source, JSON.stringify(replyMessage));
- }
- private postMessage(targetWindow: Window, message: string) {
- targetWindow.postMessage(message, '*');
- }
+ private postMessage(message: Message) {
+ this.port.postMessage(JSON.stringify(message));
+ }
- protected sendMessageToWindow(
- targetWindow: Window,
- type: MessageType,
- payload: PayloadType
- ): Promise {
- const id = `${this.idPrefix}_${this.id++}`;
- const message: Message = {type, id, payload, error: null};
- this.postMessage(targetWindow, JSON.stringify(message));
- return new Promise((resolve, reject) => {
- this.responseWaits.set(id, {resolve, reject});
- });
+ sendMessage(type: MessageType, payload: PayloadType): Promise {
+ const id = `${this.id++}`;
+ const message: Message = {type, id, payload, error: null, isReply: false};
+ this.postMessage(message);
+ return new Promise((resolve, reject) => {
+ this.responseWaits.set(id, {resolve, reject});
+ });
+ }
}
-}
+} // namespace tb.plugin.lib.internal
diff --git a/tensorboard/components/plugin_util/plugin-guest.html b/tensorboard/components/plugin_util/plugin-guest.html
index 807d96f6e7..9c0ccdfb86 100644
--- a/tensorboard/components/plugin_util/plugin-guest.html
+++ b/tensorboard/components/plugin_util/plugin-guest.html
@@ -14,5 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+
+
-
diff --git a/tensorboard/components/plugin_util/plugin-guest.ts b/tensorboard/components/plugin_util/plugin-guest.ts
index 9557c92a10..0914af5915 100644
--- a/tensorboard/components/plugin_util/plugin-guest.ts
+++ b/tensorboard/components/plugin_util/plugin-guest.ts
@@ -12,36 +12,44 @@ 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 {IPC, Message, MessageType, PayloadType} from './message.js';
-
-class GuestIPC extends IPC {
+namespace tb.plugin.lib.internal {
/**
- * payload must be JSON serializable.
+ * This code is part of a public bundle provided to plugin authors,
+ * and runs within an IFrame to setup communication with TensorBoard's frame.
*/
- sendMessage(type: MessageType, payload: PayloadType): Promise {
- return this.sendMessageToWindow(window.parent, type, payload);
+ if (!window.parent) {
+ throw Error(
+ 'This library must be run from within a loaded TensorBoard dynamic plugin.'
+ );
}
-}
-
-// Only export for testability.
-export const _guestIPC = new GuestIPC();
-
-/**
- * Sends a message to the parent frame.
- * @return Promise that resolves with a payload from parent in response to this message.
- *
- * @example
- * const someList = await sendMessage('v1.some.type.parent.understands');
- * // do fun things with someList.
- */
-export const sendMessage = _guestIPC.sendMessage.bind(_guestIPC);
-
-/**
- * Subscribes a callback to a message with particular type.
- */
-export const listen = _guestIPC.listen.bind(_guestIPC);
-
-/**
- * Unsubscribes a callback to a message.
- */
-export const unlisten = _guestIPC.unlisten.bind(_guestIPC);
+
+ const channel = new MessageChannel();
+ const ipc = new IPC(channel.port1);
+ channel.port1.start();
+
+ const VERSION = 'experimental';
+ window.parent.postMessage(`${VERSION}.bootstrap`, '*', [channel.port2]);
+
+ // Only export for testability.
+ export const _guestIPC = ipc;
+
+ /**
+ * Sends a message to the parent frame.
+ * @return Promise that resolves with a payload from parent in response to this message.
+ *
+ * @example
+ * const someList = await sendMessage('v1.some.type.parent.understands');
+ * // do fun things with someList.
+ */
+ export const sendMessage = _guestIPC.sendMessage.bind(_guestIPC);
+
+ /**
+ * Subscribes a callback to a message with particular type.
+ */
+ export const listen = _guestIPC.listen.bind(_guestIPC);
+
+ /**
+ * Unsubscribes a callback to a message.
+ */
+ export const unlisten = _guestIPC.unlisten.bind(_guestIPC);
+} // namespace tb.plugin.lib.internal
diff --git a/tensorboard/components/plugin_util/plugin-host.html b/tensorboard/components/plugin_util/plugin-host.html
index d1b6f3ae89..4dae3ba4bb 100644
--- a/tensorboard/components/plugin_util/plugin-host.html
+++ b/tensorboard/components/plugin_util/plugin-host.html
@@ -14,7 +14,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+
-
diff --git a/tensorboard/components/plugin_util/plugin-host.ts b/tensorboard/components/plugin_util/plugin-host.ts
index 48da663013..11c935388a 100644
--- a/tensorboard/components/plugin_util/plugin-host.ts
+++ b/tensorboard/components/plugin_util/plugin-host.ts
@@ -12,46 +12,60 @@ 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 {IPC, Message, MessageType, PayloadType} from './message.js';
-
-class HostIPC extends IPC {
- sendMessage(
- iframe: HTMLIFrameElement,
- type: MessageType,
- payload: PayloadType
- ): Promise {
- return this.sendMessageToWindow(iframe.contentWindow, type, payload);
+namespace tb.plugin.lib.host {
+ const portIPCs = new Set();
+ const VERSION = 'experimental';
+ const ipcToFrame = new WeakMap();
+ const callbacks = new Map<
+ lib.internal.MessageType,
+ lib.internal.MessageCallback
+ >();
+
+ // The initial Window-level listener is needed to bootstrap only.
+ // All further communication is done over MessagePorts.
+ window.addEventListener('message', (event) => {
+ if (event.data !== `${VERSION}.bootstrap`) return;
+ const port = event.ports[0];
+ if (!port) return;
+ const frame = event.source ? event.source.frameElement : null;
+ if (!frame) return;
+
+ const portIPC = new lib.internal.IPC(port);
+ portIPCs.add(portIPC);
+ ipcToFrame.set(portIPC, frame as HTMLIFrameElement);
+ port.start();
+
+ [...callbacks].forEach(([type, callback]) => {
+ portIPC.listen(type, callback);
+ });
+ // TODO: install API.
+ });
+
+ function _broadcast(
+ type: lib.internal.MessageType,
+ payload: lib.internal.PayloadType
+ ): Promise {
+ // Clean up disconnected iframes, since they won't respond.
+ for (const ipc of portIPCs) {
+ if (!ipcToFrame.get(ipc).isConnected) {
+ portIPCs.delete(ipc);
+ ipcToFrame.delete(ipc);
+ }
+ }
+
+ const ipcs = [...portIPCs];
+ const promises = ipcs.map((ipc) => ipc.sendMessage(type, payload));
+ return Promise.all(promises);
+ }
+
+ export const broadcast = _broadcast;
+ export function listen(
+ type: lib.internal.MessageType,
+ callback: lib.internal.MessageCallback
+ ) {
+ callbacks.set(type, callback);
+ [...portIPCs].forEach((ipc) => {
+ ipc.listen(type, callback);
+ });
}
-}
-
-const hostIPC = new HostIPC();
-const _listen = hostIPC.listen.bind(hostIPC);
-const _unlisten = hostIPC.unlisten.bind(hostIPC);
-const _sendMessage = hostIPC.sendMessage.bind(hostIPC);
-
-export const sendMessage = _sendMessage;
-export const listen = _listen;
-export const unlisten = _unlisten;
-
-// Export for testability.
-export const _hostIPC = hostIPC;
-
-namespace tf_plugin {
- /**
- * Sends a message to the frame specified.
- * @return Promise that resolves with a payload from frame in response to the message.
- *
- * @example
- * const someList = await sendMessage('v1.some.type.guest.understands');
- * // do fun things with someList.
- */
- export const sendMessage = _sendMessage;
- /**
- * Subscribes to messages from specified frame of a type specified.
- */
- export const listen = _listen;
- /**
- * Unsubscribes to messages from specified frame of a type specified.
- */
- export const unlisten = _unlisten;
-} // namespace tf_plugin
+} // namespace tb.plugin.lib.host
diff --git a/tensorboard/components/plugin_util/test/BUILD b/tensorboard/components/plugin_util/test/BUILD
index 0de10f7665..0a7c420cd7 100644
--- a/tensorboard/components/plugin_util/test/BUILD
+++ b/tensorboard/components/plugin_util/test/BUILD
@@ -10,51 +10,50 @@ licenses(["notice"]) # Apache 2.0
tf_web_test(
name = "test",
+ src = "/tf-plugin/test/test_binary.html",
web_library = ":test_web_library",
- src = "/tf-plugin/test/test_binary.html"
)
-# HACK: specifying tensorboard_html_binary on tf_web_test causes certain
-# environment to throw exception but wrapping tensorbard_html_binary with
-# tf_web_library seems to be okay.
-tf_web_library(
- name = "test_web_library",
- srcs = [
- ":test_binary.html",
- ],
- path = "/tf-plugin/test",
- deps = [
- ":test_lib",
- "//tensorboard/components/tf_imports:web_component_tester",
- ],
-)
+# # HACK: specifying tensorboard_html_binary on tf_web_test causes certain
+# # environment to throw exception but wrapping tensorbard_html_binary with
+# # tf_web_library seems to be okay.
+# tf_web_library(
+# name = "test_web_library",
+# srcs = [
+# ":test_binary.html",
+# ],
+# path = "/tf-plugin/test",
+# deps = [
+# ":test_lib",
+# "//tensorboard/components/tf_imports:web_component_tester",
+# ],
+# )
-tensorboard_html_binary(
- name = "test_binary",
- # Disable advanced optimization to prevent check for WebComponentTester
- # gobals.
- compilation_level = "SIMPLE",
- # Requires for compiling `import`s away.
- compile = True,
- input_path = "/tf-plugin/test/tests.html",
- output_path = "/tf-plugin/test/test_binary.html",
- deps = [
- ":test_lib",
- ],
-)
+# tensorboard_html_binary(
+# name = "test_binary",
+# # Disable advanced optimization to prevent check for WebComponentTester
+# # gobals.
+# compilation_level = "SIMPLE",
+# # Requires for compiling `import`s away.
+# compile = True,
+# input_path = "/tf-plugin/test/tests.html",
+# output_path = "/tf-plugin/test/test_binary.html",
+# deps = [
+# ":test_lib",
+# ],
+# )
tf_web_library(
- name = "test_lib",
+ name = "test_web_library",
srcs = [
"iframe.html",
- "iframe.ts",
"plugin-test.ts",
"tests.html",
],
- path = "/tf-plugin/test",
+ path = "/tf-plugin-lib/test",
deps = [
- "//tensorboard/components/plugin_util:plugin_host",
"//tensorboard/components/plugin_util:plugin_guest",
+ "//tensorboard/components/plugin_util:plugin_host",
"//tensorboard/components/tf_imports:web_component_tester",
],
)
diff --git a/tensorboard/components/plugin_util/test/iframe.html b/tensorboard/components/plugin_util/test/iframe.html
index 9aff72251d..a1f16dd479 100644
--- a/tensorboard/components/plugin_util/test/iframe.html
+++ b/tensorboard/components/plugin_util/test/iframe.html
@@ -15,6 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-
+
+
diff --git a/tensorboard/components/plugin_util/test/plugin-test.ts b/tensorboard/components/plugin_util/test/plugin-test.ts
index 4c1500ee2f..488e586205 100644
--- a/tensorboard/components/plugin_util/test/plugin-test.ts
+++ b/tensorboard/components/plugin_util/test/plugin-test.ts
@@ -12,9 +12,8 @@ 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 pluginHost from '../plugin-host.js';
-namespace tf_plugin.test {
+namespace tb.plugin.lib.host.test {
const {expect} = chai;
const template = document.getElementById(
'iframe-template'
@@ -57,24 +56,15 @@ namespace tf_plugin.test {
this.destListen = this.guestWindow.test.listen;
this.destUnlisten = this.guestWindow.test.unlisten;
this.srcSendMessage = (type, payload) => {
- return pluginHost.sendMessage(this.guestFrame, type, payload);
+ return new Promise(async (resolve) => {
+ const results = await broadcast(type, payload);
+ resolve(results[0]);
+ });
};
this.destPostMessageSpy = () =>
this.sandbox.spy(this.guestWindow.test._guestIPC, 'postMessage');
},
},
- {
- spec: 'guest (src) to host (dest)',
- beforeEachFunc: function() {
- this.destListen = pluginHost.listen;
- this.destUnlisten = pluginHost.unlisten;
- this.srcSendMessage = (type, payload) => {
- return this.guestWindow.test.sendMessage(type, payload);
- };
- this.destPostMessageSpy = () =>
- this.sandbox.spy(pluginHost._hostIPC, 'postMessage');
- },
- },
].forEach(({spec, beforeEachFunc}) => {
describe(spec, () => {
beforeEach(beforeEachFunc);
diff --git a/tensorboard/components/plugin_util/test/tests.html b/tensorboard/components/plugin_util/test/tests.html
index 76946a9b0e..20a4d13677 100644
--- a/tensorboard/components/plugin_util/test/tests.html
+++ b/tensorboard/components/plugin_util/test/tests.html
@@ -20,4 +20,4 @@
-
+