Is it possible to get background_page target for Firefox Add-on in puppeteer?
For testing chrome extensions, I can easily access the background_page when extension is loaded by doing the following:
// Bring up chrome browser with extension loaded
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
ignoreHTTPSErrors: true,
timeout: 0,
args: [
`--disable-extensions-except=${CRX_PATH}`,
`--load-extension=${CRX_PATH}`,
'--ignore-certificate-errors',
'--no-sandbox',
'--disable-setuid-sandbox',
'--window-size=1920,1080',
],
});
// Fetch browser targets
const targets = await browser.targets();
// Filter out background_page for extension from the targets
const backgroundPageTarget = targets.find((target) => {
return target.type() === 'background_page';
});
I was able to load my firefox add-on by following these guides:
https://github.com/puppeteer/puppeteer/issues/4162
https://github.com/puppeteer/puppeteer/blob/f26bb7f4c44d9b7db5cc73c4af32db6fa5bcd3a2/experimental/puppeteer-firefox/README.md#add-ons
However, I've been unable to access the background_page of the add-on. I need that to intercept and validate requests and responses made by the add-on.
I managed to make it work with Selenium by following these steps:
Open up the same Firefox browser application that you're making Puppeteer connect to.
Load the extension the same way that you make Puppeteer load it (there's different ways, I did it by loading an unsigned version with Firefox dev edition).
Activate the popup window for the extension, then right click and select View page source.
In the URL, you should see this pattern view-source:moz-extension://<extension-id>/<extension-page-name>.html
Using this extension ID, you can make your script go to the background page by having the browser navigate to moz-extension://<extension-id>/<background-page-name>.html
Related
I need to control Firefox browser via webdriver. Note, I'm not trying to control page elements (i.e. find element, click, get text, etc); rather I need access to Firefox's profiler and force gc (i.e. I need firefox's Chrome Authority and sdk). For context, I'm creating a micro benchmark framework, not running a normal webdriver test.
Obviously raw webdriver won't work, so what I've been trying to do is
1) Create a firefox extension/add-on that does what I need: i.e.
var customActions = function() {
console.log('calling customActions.')
// I need to access chrome authority:
var {Cc,Ci,Cu} = require("chrome");
Cc["#mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
Cu.forceGC();
var file = require('sdk/io/file');
// And do some writes:
var textWriter = file.open('a/local/path.txt', 'w');
textWriter.write('sample data');
textWriter.close();
console.log('called customActions.')
};
2) Expose my customActions function to a page:
var mod = require("sdk/page-mod");
var data = require("sdk/self").data;
mod.PageMod({
include: ['*'],
contentScriptFile: data.url("myscript.js"),
onAttach: function(worker) {
worker.port.on('callCustomActions', function() {
customActions();
});
}
});
and in myscript.js:
exportFunction(function() {
self.port.emit('callCustomActions');
}, unsafeWindow, {defineAs: "callCustomActions"});
3) Load the xpi during my webdriver test, and call out to global function callCustomActions
So two questions about this process.
1) This entire process is very roundabout. Is there a better practice for talking to a firefox extension via webdriver?
2) My current solution isn't working well. If I run my extension via cfx run directly (without webdriver) it works as expected. However, neither the sdk nor chrome authority do anything when running via webdriver.
By the way, I know my function is being called because the log line "calling customActions." and "called customActions." both do print.
Maybe there are some firefox preferences that I need to set but haven't?
It may be that you do not need the add-on at all. Mozilla uses Marionette for test automation of Firefox OS amongst other things:
Marionette is an automation driver for Mozilla's Gecko engine. It can
remotely control either the UI or the internal JavaScript of a Gecko
platform, such as Firefox or Firefox OS. It can control both the
chrome (i.e. menus and functions) or the content (the webpage loaded
inside the browsing context), giving a high level of control and
ability to replicate user actions. In addition to performing actions
on the browser, Marionette can also read the properties and attributes
of the DOM.
If this sounds similar to Selenium/WebDriver then you're correct!
Marionette shares much of the same ethos and API as
Selenium/WebDriver, with additional commands to interact with Gecko's
chrome interface. Its goal is to replicate what Selenium does for web
content: to enable the tester to have the ability to send commands to
remotely control a user agent.
I'm creating my first Firefox extension using the Addon SDK, but I can't get messages I pass with console.log() to appear in my debugger.
I created a new profile in Firefox 33 and installed the latest version of Firebug. When I launch my addon using cfx run -p <My_Profile_Directory> I can see both Firebug and my addon, and the addon does what it's supposed to do. However, I don't see anywhere messages I wrote to log using the console.log() command
Here's my main.js so far:
function loginToSite(user, password) {
var Request = require("sdk/request").Request;
var doLogin = Request(
{
url: "https://website.com/login/index.php",
contentType: "application/x-www-form-urlencoded",
content: "username=xxxx&password=xxxx&remember=1",
onComplete: function(response) {
console.log(response.text);
}
}
);
doLogin.post();
}
function checkLoginStatus(tab) {
//TODO Actually check if the tab is logged in, currently assume it's not
loginToSite(0,0);
}
// Listens for tabs and checks each loaded tab if it's the website
tabs.on("ready", function(tab) {
var tabUrl = tab.url.toLowerCase();
if(tabUrl.contains("website.com")) {
console.log("Not connected to website.com, running login procedure");
checkLoginStatus(tab);
}
});
Like I said, I'm actually being logged in automatically, but no log messages appear in either Firebug's or the Firefox Developer Tools' console.
What am I doing wrong here? Where are the log messages?
You have to change the default logging level (error) to something more verbose, like info.
The global level is controlled by the preference extensions.sdk.console.logLevel. But you can adjust the logging level of your extension only, with the preference extensions.myExtensionID.sdk.console.logLevel
When you run cfx without passing a profile directory, it takes care of setting up the temporary profile to be developer friendly.
I have developed an add-on using the Firefox Add-on SDK 1.14.
This add-on listens to tabs.ready events to perform an action.
Starting on Firefox 24, the tabs.ready event is no longer fired when a page is loaded by means of a window.open call.
Sample add-on code:
var tabs = require("sdk/tabs");
tabs.on('ready', function(tab){console.log(tab.url)});
Sample page code:
window.open(
'http://stackoverflow.com',
'',
'width=800,height=600,scrollbars=yes,resizable=no,status=yes,location=yes'
);
Am I missing something or the Add-on SDK is not behaving correctly?
I'm developing a Chrome (packaged) app which maintains a set of bookmarks. This opens in its own small window. Clicking on a bookmark opens it in a browser using a link with target set to '_blank'.
On Mac OS X, these open in Safari. Is there anyway of having them open in Chrome?
When you click on a link with target="_blank" in a packaged app, Chrome respects your choice of the default browser and opens the link externally in whatever it is, not necessarily Chrome. In your case, the default system browser must be Safari.
The easy way to open such links in Chrome would be to make it the default browser instead.
If you don't want to do that, but still for some reason insist that your links open in new tabs specifically in Chrome, here is one (perhaps the only) way to achieve that:
Write a companion extension to your app and have your users install it.
In the app, attach an onclick handler to every link, and use chrome.runtime.sendMessage() to send a request to the extension to open the link's URL (in order to do that, you will have to find out your extension's ID and bake it into its manifest, as described here: http://developer.chrome.com/apps/manifest/key.html):
var link = ...;
link.addEventListener('click', function(e) {
e.stopPropagation();
e.preventDefault();
chrome.runtime.sendMessage(
yourExtensionId, { url: link.href }, function(response) {}
);
};
In the extension, define a chrome.runtime.onMessageExternal(data) handler (it will intercept sendMessage() requests from the app), and use chrome.tabs.create() in there to open a new tab:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
// Don't forget to make sure that |sender| is you app here.
chrome.tabs.create({ url: request.url }, function() {
// If you need to notify the app when the tab opens:
sendResponse(true);
});
// 'true' means that your response is sent asynchronously.
return true;
}
);
I created a Firefox extension and chrome extension. In Chrome I am using background.cs, so it will get loaded only once for all Chrome instances, so if I will write simple alert in background it will show alert box only for once.
The same thing is not working with Firefox, it will show that alert message all the times when I will open new Firefox windows.
Is there anything like background in Firefox?
Either write a javascript module or switch to the Add-on SDK
A javascript module would be something like this
this.EXPORTED_SYMBOLS = ["Helper"];
this Helper = {
initialized: false,
init: function() {
if(this.initialized){
return;
}
// code here is executed only the first time init() is called
this.initialized = true;
}
};