Closed Bug 1203394 Opened 9 years ago Closed 8 years ago

alert() in background scripts should warn that it doesn't work

Categories

(WebExtensions :: Untriaged, defect)

defect
Not set
normal

Tracking

(firefox49 verified)

VERIFIED FIXED
mozilla49
Tracking Status
firefox49 --- verified

People

(Reporter: wbamberg, Assigned: tofumatt, Mentored)

References

Details

(Whiteboard: [good first bug]triaged)

Attachments

(4 files, 1 obsolete file)

Attached file test.xpi (obsolete) —
I've attached a WebExtension that loads 2 background scripts. The first just logs a string, the second displays an alert when the user clicks a button. It works as expected in Chrome. In Firefox (43.0a1 (2015-09-09)), I get this in the console:

NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMWindowUtils.isParentWindowMainWidgetVisible] nsPrompter.js:356:0

out of memory ExtensionUtils.jsm:24:0
Flags: needinfo?(wmccloskey)
Actually, it seems as if two scripts are not needed for this. You just need one background script, listening for a click on a browser action. I'll attach a new example.
Summary: "out of memory" with 2 background scripts → "out of memory" with background script listening to browser action click event
Attached file bug.xpi
Attachment #8659049 - Attachment is obsolete: true
Finally had a chance to take a look at this. I could see this being important for developers writing "My first WebExtension". The "out of memory" message is incorrect and unfortunate (probably some xpconnect bug). But the real problem is that we don't support alert() in background pages.
Flags: needinfo?(wmccloskey)
Summary: "out of memory" with background script listening to browser action click event → alert() does not work in background scripts
Based on the comments in bug 1214174, let's have just one bug.
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → DUPLICATE
Going to un-dupe this since we might want to implement alert().
Status: RESOLVED → REOPENED
Resolution: DUPLICATE → ---
Flags: blocking-webextensions-
As a side note, someone in the wild just ran into this, and asked about it at http://stackoverflow.com/questions/34199130/firefox-entension-alert
I've been thinking we should just alias this to console.log, and also print a warning that console.log should be used instead when it's called. And possibly open up the browser console if it's not open at the time.

That would be a good first bug, I think.
Mentor: kmaglione+bmo
Whiteboard: [good first bug]
Whiteboard: [good first bug] → [good first bug]triaged
The relevant code is here:

https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/ext-backgroundPage.js#64

I think the way to handle this is to add a DOMWindowCreated[1] listener to the content window, and then use exportFunction[2] to replace the window's `alert` function with one that calls the window's `console.log`, and then opens up the browser console (using `HUDService.openBrowserConsoleOrFocus()`)


[1]: https://developer.mozilla.org/en-US/docs/Web/Events/DOMWindowCreated
[2]: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components.utils.exportFunction
Assignee: nobody → tofumatt
https://reviewboard.mozilla.org/r/39775/#review37279

::: toolkit/components/extensions/ext-backgroundPage.js:83
(Diff revision 1)
> +          if (!consoleWindow) {
> +            let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
> +            require("devtools/client/framework/devtools-browser");
> +            let hudservice = require("devtools/client/webconsole/hudservice");
> +            let { console } = Cu.import("resource://gre/modules/Console.jsm", {});
> +            hudservice.toggleBrowserConsole().then(null, console.error);

I'd go with `hudservice.toggleBrowserConsole().catch(Cu.reportError)`

::: toolkit/components/extensions/ext-backgroundPage.js:95
(Diff revision 1)
> +
> +          alertDisplayedWarning = true;
> +        }
> +
> +        window.console.log(text);
> +      }

Semicolon.

::: toolkit/components/extensions/ext-backgroundPage.js:96
(Diff revision 1)
> +          alertDisplayedWarning = true;
> +        }
> +
> +        window.console.log(text);
> +      }
> +      Components.utils.exportFunction(alertOverwrite, this.contentWindow, {

Let's use `window` rather than `this.consoleWindow` just so we're consistent.

::: toolkit/components/extensions/test/mochitest/mochitest.ini:69
(Diff revision 1)
>  skip-if = buildapp == 'b2g' # unimplemented api.
>  [test_ext_alarms.html]
>  [test_ext_background_window_properties.html]
>  [test_ext_background_sub_windows.html]
>  [test_ext_background_api_injection.html]
> +[test_ext_background_page.html]

Looks like you forgot to add this test file?
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

Review request updated; see interdiff: https://reviewboard.mozilla.org/r/39775/diff/1-2/
Attachment #8730247 - Attachment description: MozReview Request: bug 1203394: alias alert() to console.log() in background scripts → MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag
Attachment #8730247 - Flags: review?(kmaglione+bmo)
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

https://reviewboard.mozilla.org/r/39775/#review44221

Very close. The tests just need to deal with the browser console window that we're opening.

It would be great if we could get this landed before the 48 merge on Monday

::: toolkit/components/extensions/test/mochitest/test_ext_background_page.html:16
(Diff revision 2)
> +<body>
> +
> +<script type="text/javascript">
> +"use strict";
> +
> +

Please remove extra blank line.

::: toolkit/components/extensions/test/mochitest/test_ext_background_page.html:20
(Diff revision 2)
> +
> +
> +const Services = SpecialPowers.Services;
> +
> +ok(!Services.wm.getEnumerator("alert:alert").hasMoreElements(),
> +   "Alerts should not be present at the start of the test.");

This needs to happen within a task. Tests are technically not allowed to log results during setup or teardown, so even if this works now, it's likely to break in the future.

::: toolkit/components/extensions/test/mochitest/test_ext_background_page.html:40
(Diff revision 2)
> +  info("startup complete loaded");
> +
> +  yield extension.awaitFinish("alertCalled");
> +
> +  var alertWindows = Services.wm.getEnumerator("alert:alert");
> +  ok(!alertWindows.hasMoreElements(), "Should not show alert");

We should check that the browser console is open here, and that it has a message. And we definitely need to close the browser console at the end of the test. Leaving it open is likely to cause other tests to fail.

Let me know if you need any help with this.

::: toolkit/components/extensions/test/mochitest/test_ext_background_page.html:44
(Diff revision 2)
> +  var alertWindows = Services.wm.getEnumerator("alert:alert");
> +  ok(!alertWindows.hasMoreElements(), "Should not show alert");
> +
> +  yield extension.unload();
> +});
> +

Please remove blank line.
Attachment #8730247 - Flags: review?(kmaglione+bmo)
https://reviewboard.mozilla.org/r/39775/#review44221

> This needs to happen within a task. Tests are technically not allowed to log results during setup or teardown, so even if this works now, it's likely to break in the future.

If I move the code inside a task I get errors about `ok` and `Services` being undefined. How do I run them inside a task?

> We should check that the browser console is open here, and that it has a message. And we definitely need to close the browser console at the end of the test. Leaving it open is likely to cause other tests to fail.
> 
> Let me know if you need any help with this.

Yeah, could you point me to a test I could copy or refer to? I did this for my last patch but it wasn't a mochitest, so I don't know how to do it here :-/
https://reviewboard.mozilla.org/r/39775/#review44221

> If I move the code inside a task I get errors about `ok` and `Services` being undefined. How do I run them inside a task?

That shouldn't happen. Can you show me the code?

> Yeah, could you point me to a test I could copy or refer to? I did this for my last patch but it wasn't a mochitest, so I don't know how to do it here :-/

I think we're going to have to make this a chrome test for this to work properly, since we need to check this from the parent process. So just move the line that registers the test from mochitest.ini to chrome.ini.

The code to check for and close the browser console should look something like this:

    let haveConsole = !!HUDService.getBrowserConsole();
    ok(haveConsole, "Expected browser console to be open");
    if (haveConsole)
      yield HUDService.toggleBrowserConsole();
    }

And to check for the message, do something like `Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage).getEvents()`, and then check that the last event is what you'd expect.
https://reviewboard.mozilla.org/r/39775/#review44221

> That shouldn't happen. Can you show me the code?

Sorry, I'm dumb; you're right. I was putting it in the extension code. I put it inside the task but not the extension and it was all good.
https://reviewboard.mozilla.org/r/39775/#review44221

> I think we're going to have to make this a chrome test for this to work properly, since we need to check this from the parent process. So just move the line that registers the test from mochitest.ini to chrome.ini.
> 
> The code to check for and close the browser console should look something like this:
> 
>     let haveConsole = !!HUDService.getBrowserConsole();
>     ok(haveConsole, "Expected browser console to be open");
>     if (haveConsole)
>       yield HUDService.toggleBrowserConsole();
>     }
> 
> And to check for the message, do something like `Cc["@mozilla.org/consoleAPI-storage;1"].getService(Ci.nsIConsoleAPIStorage).getEvents()`, and then check that the last event is what you'd expect.

My only issue here is that `HUDService` is undefined and trying to import it doesn't work. How do I get access to that API?
https://reviewboard.mozilla.org/r/39775/#review44221

> My only issue here is that `HUDService` is undefined and trying to import it doesn't work. How do I get access to that API?

Same with "Cc"; I don't know what that's supposed to mean. Is there a good doc page for finding this stuff? My Googling has turned up a lot of API docs but they don't seem to work in the tests.
(In reply to tofumatt [:tofumatt] from comment #16)
> My only issue here is that `HUDService` is undefined and trying to import it
> doesn't work. How do I get access to that API?
>
> Same with "Cc"; I don't know what that's supposed to mean. Is there a good
> doc page for finding this stuff? My Googling has turned up a lot of API docs
> but they don't seem to work in the tests.

Hm. Well, usually Cc and Ci are defined for all of our tests in the head.js
file, but we don't currently have a separate head.js file for chrome
mochitests, so in this case they're not. You just need to add something like
this to the beginning of the script:

    var {classes: Ci, interfaces: Ci, utils: Cu, results: Cr} = Components;

As for HUDService, you need to import it the same way you do in
ext-backgroundPage.js:

    let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
    require("devtools/client/framework/devtools-browser");
    let HUDService = require("devtools/client/webconsole/hudservice");
https://reviewboard.mozilla.org/r/39775/#review44537

::: toolkit/components/extensions/ext-backgroundPage.js:79
(Diff revision 2)
> +      let alertDisplayedWarning = false;
> +      let alertOverwrite = text => {
> +        if (!alertDisplayedWarning) {
> +          let consoleWindow = Services.wm.getMostRecentWindow("devtools:webconsole");
> +          if (!consoleWindow) {
> +            let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});

Sorry, I should have noticed this before. ESLint will reject this for the whitespace inside the braces. Same for the one below.
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

Review request updated; see interdiff: https://reviewboard.mozilla.org/r/39775/diff/2-3/
Attachment #8730247 - Flags: review?(kmaglione+bmo)
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

https://reviewboard.mozilla.org/r/39775/#review45245

::: toolkit/components/extensions/test/mochitest/test_chrome_ext_background_page.html:50
(Diff revision 3)
> +
> +  // Make sure the message we output to the console is seen.
> +  // This message is in ext-backgroundPage.js
> +  let events = Cc["@mozilla.org/consoleAPI-storage;1"]
> +    .getService(Ci.nsIConsoleAPIStorage).getEvents();
> +  ok(events[events.length - 1], "alert() is not supported in background windows; please use console.log instead.")

This will only check that there was an event, not that it was correct. I think you need to check `event.arguments[0]` (using `eq` rather than `ok`)

::: toolkit/components/extensions/test/mochitest/test_chrome_ext_background_page.html:57
(Diff revision 3)
> +  let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
> +  require("devtools/client/framework/devtools-browser");
> +  let hudservice = require("devtools/client/webconsole/hudservice");
> +
> +  let consoleWindow = Services.wm.getMostRecentWindow("devtools:webconsole");
> +  if (!consoleWindow) {

This makes the next test invalid. We're supposed to be testing that the console window was opened by the extension, but this will open it if it's not already open.

::: toolkit/components/extensions/test/mochitest/test_chrome_ext_background_page.html:58
(Diff revision 3)
> +  require("devtools/client/framework/devtools-browser");
> +  let hudservice = require("devtools/client/webconsole/hudservice");
> +
> +  let consoleWindow = Services.wm.getMostRecentWindow("devtools:webconsole");
> +  if (!consoleWindow) {
> +    yield hudservice.toggleBrowserConsole().catch(Cu.reportError);

The `.catch(...)` isn't necessary. The `yield` will cause it to throw, and the test to fail, if the promise is rejected. Which is what we want.
Attachment #8730247 - Flags: review?(kmaglione+bmo)
https://reviewboard.mozilla.org/r/39775/#review45245

> This makes the next test invalid. We're supposed to be testing that the console window was opened by the extension, but this will open it if it's not already open.

Hmm, any idea why the test would fail without it then? It totally works when I launch Nightly and run an extension using alert() in the background, but the test fails without this :-(
https://reviewboard.mozilla.org/r/39775/#review45245

> This will only check that there was an event, not that it was correct. I think you need to check `event.arguments[0]` (using `eq` rather than `ok`)

eq doesn't seem to be available, but I see "is" being used elsewhere and it looks like it's comparing things like an eq() helper. Is that okay?
https://reviewboard.mozilla.org/r/39775/#review45245

> eq doesn't seem to be available, but I see "is" being used elsewhere and it looks like it's comparing things like an eq() helper. Is that okay?

Also, `events.arguments[0]` is undefined, and `event` doesn't exist. I'm confused.
https://reviewboard.mozilla.org/r/39775/#review45245

> Hmm, any idea why the test would fail without it then? It totally works when I launch Nightly and run an extension using alert() in the background, but the test fails without this :-(

It may be timing-related. `toggleBrowserConsole` is asynchronous, so the window may not be open by the time you check. When you `yield` on the result of `toggleBrowserConsole`, it actually waits. I don't see an obvious way to handle this, but the code is here: https://dxr.mozilla.org/mozilla-central/source/devtools/client/webconsole/hudservice.js#172
https://reviewboard.mozilla.org/r/39775/#review45245

> Also, `events.arguments[0]` is undefined, and `event` doesn't exist. I'm confused.

Sorry, yeah, `is`. We have different names for test functions in each suite...

`event` as in `event = events[events.length - 1]`
https://reviewboard.mozilla.org/r/39775/#review45253

::: toolkit/components/extensions/ext-backgroundPage.js:83
(Diff revision 3)
> +          if (!consoleWindow) {
> +            let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
> +            require("devtools/client/framework/devtools-browser");
> +            let hudservice = require("devtools/client/webconsole/hudservice");
> +            let {console} = Cu.import("resource://gre/modules/Console.jsm", {});
> +            hudservice.toggleBrowserConsole().catch(Cu.reportError);

Ugh. This should be `openBrowserConsoleOrFocus`. I can't believe I missed that.
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

Review request updated; see interdiff: https://reviewboard.mozilla.org/r/39775/diff/3-4/
Attachment #8730247 - Flags: review?(kmaglione+bmo)
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

https://reviewboard.mozilla.org/r/39775/#review45285

::: toolkit/components/extensions/test/mochitest/test_chrome_ext_background_page.html:62
(Diff revision 4)
> +
> +  let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
> +  require("devtools/client/framework/devtools-browser");
> +  let hudservice = require("devtools/client/webconsole/hudservice");
> +
> +  hudservice.getBrowserConsole();

Let's make this something like `while (!hudservice.getBrowserConsole()) { yield new Promise(resolve => setTimeout(resolve, 0)) }`
Attachment #8730247 - Flags: review?(kmaglione+bmo) → review+
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

Review request updated; see interdiff: https://reviewboard.mozilla.org/r/39775/diff/4-5/
Comment on attachment 8730247 [details]
MozReview Request: bug 1203394: alias alert() to console.log() in background scripts r?kmag

Review request updated; see interdiff: https://reviewboard.mozilla.org/r/39775/diff/5-6/
Patch to fix eslint errors in previous, landed patch.
Flags: needinfo?(aryx.bugmail)
Attachment #8744913 - Flags: review?(aryx.bugmail)
Skip Android test for alert()
Attachment #8744957 - Flags: review?(aryx.bugmail)
Comment on attachment 8744957 [details] [diff] [review]
alert-test-fixes.patch

Review of attachment 8744957 [details] [diff] [review]:
-----------------------------------------------------------------

Thanks, pushed https://hg.mozilla.org/integration/mozilla-inbound/rev/b1412d274f62
Attachment #8744957 - Flags: review?(aryx.bugmail) → review+
Depends on: 1267328
could someone please clarify ... is this the permanent "fix" or just a stopgap until alert() can be properly implemented? should I open a new bug for proper implementation of alert()?

i'm trying to move a "legacy" extension to webextensions that alerts info about an element via the context menu; it's very upsetting if this functionality will not be supported.
This is meant to make things easier for people who try to use alert() for debugging. We don't intend to support alert() in background pages.

If you want to alert data based on a context menu item, you can do so from a content script.
do I understand correctly that you're telling me that functionality cannot be accessible via native Firefox context menus?

can't this alias to nsIPromptService's alert? (https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIPromptService#alert())

all i want to do is alert an input's maxlength, where applicable, so as to inform allowable length for password generation, etc.
Flags: needinfo?(kmaglione+bmo)
I'm telling you that it won't be accessible from background pages. Alerts are modal dialogs, and they're meant to be tied to a specific, user-visible window. If you want to trigger an alert from a context menu operation, it needs to be triggered from the appropriate content window.
Flags: needinfo?(kmaglione+bmo)
I'm presuming content scripts cannot create native Firefox context menus. is that correct? is there no way for a native Firefox context menu to produce a native firefox interface for displaying information to the user (other than via browser console, for obvious reasons)?
Flags: needinfo?(kmaglione+bmo)
nsIPromptService's alert() is different from the web API window.alert(). it isn't tied to a particular tab. it's tied to the firefox browser window.
the web API version also can't be relied upon because it can be overridden by the web content to do other things, e.g.

function alert(message) { 
 console.info(message);
}
(In reply to zheaddaggue from comment #44)
> I'm presuming content scripts cannot create native Firefox context menus. is
> that correct? is there no way for a native Firefox context menu to produce a
> native firefox interface for displaying information to the user (other than
> via browser console, for obvious reasons)?

You can create a context menu item from a background script and then use a
content script to display the alert.

(In reply to zheaddaggue from comment #45)
> nsIPromptService's alert() is different from the web API window.alert(). it
> isn't tied to a particular tab. it's tied to the firefox browser window.

It's not. window.alert is implemented using nsIPromptService. The alerts are
modal to whatever window the caller chooses for them to be modal to.

(In reply to zheaddaggue from comment #46)
> the web API version also can't be relied upon because it can be overridden
> by the web content to do other things, e.g.

No, it can't be overridden by web content. Content scripts executed in a
different scope from page scripts, and are guaranteed access to a clean set of
web APIs.
Flags: needinfo?(kmaglione+bmo)
I was able to reproduce the initial issue on Firefox 48.0.2 (20160823121617) under Windows 10 64-bit.

Manually verified as fixed on Firefox 49 (20160912134115), Firefox 50.0a2 (2016-09-15) and Firefox 51.0a1 (2016-09-15) under Windows 10 64-bit. “You clicked” log successfully appeared and the error is no longer thrown in Browser Console.
Status: RESOLVED → VERIFIED
This issue is still reproduced on Firefox 52.0a2 (2017-01-22) / Windows 7 SP1.

There is no alert shown, and the console shows "alert() is not supported in background windows; please use console.log instead."
(In reply to Danny Lin from comment #49)
> This issue is still reproduced on Firefox 52.0a2 (2017-01-22) / Windows 7
> SP1.
> 
> There is no alert shown, and the console shows "alert() is not supported in
> background windows; please use console.log instead."

Hi Danny, that's actually the correct behaviour; I guess the title of the bug is a bit misleading. Because it's a background script alert() will never work. That message is the correct outcome; it's letting you know that there aren't alert()s available in the script and to use console.log instead. :-)
(In reply to tofumatt [:tofumatt] from comment #50)

Is there currently a way to show alert(), confirm(), or prompt() for chrome.browserAction.onClicked? If yes, how?
Just faced this issue...

I'm actually migrating from Chrome Extension to Firefox WebExtension - it all works properly in Chrome - displays the alert (the URL in alert dialog is just empty). 

Implemented "console.log" solution looks more like a temporary patch then a solution. Dear mozilla developers - simple things should remain simple... Using Background -> Content-Script communication just to show alert is reinventing the wheel in my opinion. Why don't you just show it on currently focused window - just like Chrome is doing? 

I'm on Firefox 52.0 - "alert" was patched - but "confirm" and "prompt" - are still throwing:

NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMWindowUtils.isParentWindowMainWidgetVisible]

------------------------

In addition - passing Background -> Content-Script (or picking currently focused Window - or whatever it takes to do it), can be done:
1. Once - by a mozilla developer
2. Thousands of time - by extensions developer in each extension
ref:

The purpose of this bug (bug 1353637) was to state why it is needed to have alert/confirm/prompt from background script, like other browsers such as Chrome. In other words, why it is necessary to change the status que.

The other referenced bug (this topic) does not answer this question. Instead it states that it is how Firefox is dong it at the moment.

The status of "bug has been fixed and VERIFIED for Firefox 49" does not reflect accurately.

Alert() bug was not fixed. It was decided to output a log instead of alert() which is not what alert() is for.
If the desired effect was to output to the console, developers would have used the console.log and not alert()

This 2 year old topic seems to deal mainly with errors resulting from using alert from background script rather than the merit of having alert/confirm/prompt from the background script (as was requested in bug 1353637).
This has already been discussed ad nauseum.

We aren't going to implement the ability to open modal dialogs from background pages. There are important technical reasons that they're problematic, and important UX ones as well.

This bug is fixed to the extent that it is ever going to be fixed.

If you want to continue this discussion, please do it elsewhere. The dev-platform and dev-firefox groups might be appropriate.
Should be either resolved wontfix or description changed to something less misleading. Calling issue with alert() not working from background script "fixed" is obvious overvaluation.
I don't think that is any more appropriate place for discussion about bug status meaning and it's clarity than bug itself.
Flags: needinfo?(kmaglione+bmo)
Please don't go around needinfo-ing people on old bugs, it accomplishes nothing.
Flags: needinfo?(kmaglione+bmo)
Summary: alert() does not work in background scripts → alert() in background scripts should warn that it doesn't work
Product: Toolkit → WebExtensions
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: