/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { RootMessageHandler } = ChromeUtils.importESModule( "chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs" ); // Check that errors from WindowGlobal modules can be caught by the consumer // of the RootMessageHandler. add_task(async function test_module_error() { const browsingContextId = gBrowser.selectedBrowser.browsingContext.id; const rootMessageHandler = createRootMessageHandler("session-id-error"); info("Call a module method which will throw"); try { await rootMessageHandler.handleCommand({ moduleName: "commandwindowglobalonly", commandName: "testError", destination: { type: WindowGlobalMessageHandler.type, id: browsingContextId, }, }); ok(false, "Error from window global module was not caught"); } catch (e) { ok(true, "Error from window global module caught"); } rootMessageHandler.destroy(); }); // Check that sending commands to incorrect destinations creates an error which // can be caught by the consumer of the RootMessageHandler. add_task(async function test_destination_error() { const rootMessageHandler = createRootMessageHandler("session-id-error"); const fakeBrowsingContextId = -1; ok( !BrowsingContext.get(fakeBrowsingContextId), "No browsing context matches fakeBrowsingContextId" ); info("Call a valid module method, but on a non-existent browsing context id"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "commandwindowglobalonly", commandName: "testOnlyInWindowGlobal", destination: { type: WindowGlobalMessageHandler.type, id: fakeBrowsingContextId, }, }), err => err.message == `Unable to find a BrowsingContext for id -1` ); rootMessageHandler.destroy(); }); add_task(async function test_invalid_module_error() { const rootMessageHandler = createRootMessageHandler( "session-id-missing_module" ); info("Attempt to call a Root module which has a syntax error"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "invalid", commandName: "someMethod", destination: { type: RootMessageHandler.type, }, }), err => err.name === "SyntaxError" && err.message == "expected expression, got ';'" ); rootMessageHandler.destroy(); }); add_task(async function test_missing_root_module_error() { const rootMessageHandler = createRootMessageHandler( "session-id-missing_module" ); info("Attempt to call a Root module which doesn't exist"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "missingmodule", commandName: "someMethod", destination: { type: RootMessageHandler.type, }, }), err => err.name == "UnsupportedCommandError" && err.message == `missingmodule.someMethod not supported for destination ROOT` ); rootMessageHandler.destroy(); }); add_task(async function test_missing_windowglobal_module_error() { const browsingContextId = gBrowser.selectedBrowser.browsingContext.id; const rootMessageHandler = createRootMessageHandler( "session-id-missing_windowglobal_module" ); info("Attempt to call a WindowGlobal module which doesn't exist"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "missingmodule", commandName: "someMethod", destination: { type: WindowGlobalMessageHandler.type, id: browsingContextId, }, }), err => err.name == "UnsupportedCommandError" && err.message == `missingmodule.someMethod not supported for destination WINDOW_GLOBAL` ); rootMessageHandler.destroy(); }); add_task(async function test_missing_root_method_error() { const rootMessageHandler = createRootMessageHandler( "session-id-missing_root_method" ); info("Attempt to call an invalid method on a Root module"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "command", commandName: "wrongMethod", destination: { type: RootMessageHandler.type, }, }), err => err.name == "UnsupportedCommandError" && err.message == `command.wrongMethod not supported for destination ROOT` ); rootMessageHandler.destroy(); }); add_task(async function test_missing_windowglobal_method_error() { const browsingContextId = gBrowser.selectedBrowser.browsingContext.id; const rootMessageHandler = createRootMessageHandler( "session-id-missing_windowglobal_method" ); info("Attempt to call an invalid method on a WindowGlobal module"); Assert.throws( () => rootMessageHandler.handleCommand({ moduleName: "commandwindowglobalonly", commandName: "wrongMethod", destination: { type: WindowGlobalMessageHandler.type, id: browsingContextId, }, }), err => err.name == "UnsupportedCommandError" && err.message == `commandwindowglobalonly.wrongMethod not supported for destination WINDOW_GLOBAL` ); rootMessageHandler.destroy(); }); /** * This test checks that even if a command is rerouted to another command after * the RootMessageHandler, we still check the new command and log a useful * error message. * * This illustrates why it is important to perform the command check at each * layer of the MessageHandler network. */ add_task(async function test_missing_intermediary_method_error() { const browsingContextId = gBrowser.selectedBrowser.browsingContext.id; const rootMessageHandler = createRootMessageHandler( "session-id-missing_intermediary_method" ); info( "Call a (valid) command that relies on another (missing) command on a WindowGlobal module" ); await Assert.rejects( rootMessageHandler.handleCommand({ moduleName: "commandwindowglobalonly", commandName: "testMissingIntermediaryMethod", destination: { type: WindowGlobalMessageHandler.type, id: browsingContextId, }, }), err => err.name == "UnsupportedCommandError" && err.message == `commandwindowglobalonly.missingMethod not supported for destination WINDOW_GLOBAL` ); rootMessageHandler.destroy(); });