Run script in WE background page from parent process


(Ryan Hendrickson) #1

Goal: write some white-box tests for a WebExtension via WebDriver, without hacking it up.
Sub-goal: run some code in the context of a WebExtension’s background page from the parent process.

When I set the extensions.webextensions.remote pref to false, this code works for me:

Cu.import('resource://gre/modules/ExtensionParent.jsm');
const ext = ExtensionParent.GlobalManager.getExtension(extensionId);
const bg = Array.from(ext.views).find(v => v.viewType === 'background');
const w = bg.xulBrowser.contentWindow.wrappedJSObject;
w.someGlobal.callSomeFunction(); // or whatever...

But I’d like to run with e10s, for a more realistic test. When I do that, bg.xulBrowser.contentWindow is null. This isn’t that shocking, given that the content should be running in another process, but is there another way to ship my someGlobal.callSomeFunction() code over to the background page, without writing some extra hooks into the WebExtension itself?


(jscher2000) #2

If you relax the requirement of not having to add hooks to your target extension…


(Ryan Hendrickson) #3

I figured it out. bg.xulBrowser has a messageManager, and message managers have a loadFrameScript function that does what I need:

Cu.import('resource://gre/modules/ExtensionParent.jsm');
const ext = ExtensionParent.GlobalManager.getExtension(extensionId);
const bg = Array.from(ext.views).find(v => v.viewType === 'background');
const mm = bg.xulBrowser.messageManager;
mm.loadFrameScript(`data:text/plain;charset=UTF-8,${encodeURIComponent(`
const w = content.wrappedJSObject;
w.someGlobal.callSomeFunction(); // or whatever...
`)}`);

Using addMessageListener (on the message manager) and sendAsyncMessage (in the frame script), I can also wait for the code to complete, or get data back.