Run mochitests against an arbitrary build, or against the distribution directory

I’ve had problems before where it would have been useful to easily run mochitests against other versions of the browser than those in my $OBJDIR. I’m pleased to say I just landed a small patch for the mochitests runner’s mach commands that lets you do:

./mach mochitest-browser --app-override /usr/bin/firefox path/to/test

and also has a special shortcut for the application as built for distribution (using omni.jar rather than a flat directory structure):

./mach mochitest-browser --app-override dist path/to/test

Happy testing!

Why doing visual refreshes of Firefox is hard

We’re getting closer and closer to releasing Australis with Firefox 29, and that gives me more time to write something that’s been on my mind the last couple of weeks/months. Extra impetus was provided by sentiment along the lines of “how did you possibly miss this / think fix X was a good idea?” from some people outside the core development team, responding to some of our changes.

In this post, I’d like to give you an idea of the number of combinations of options, configurations, themes, add-ons, fonts and styles. It is enormous. Firefox generally tries to fit in with your operating system as best it can, and that means we have to pay attention to lots of things. And yes, that means sometimes we miss things. Here’s a breakdown of some of the things I’ve seen fly by as we made Australis, all linked to bugs specific to particular scenarios (there are 54 individual bugs linked, the majority of which were fixed for 29).

Firefox is available on three main (tier-1) platforms: Windows, Linux, and OS X.

All three platforms support lightweight themes, of which we support light and dark text variants. On light text lightweight themes, we invert the text and icons to be bright (which usually means the theme itself has a dark background). Interactions between these themes and the OS are not always the same everywhere, which leads to bugs.

Different toolbars like the menubar and the bookmarks toolbar can be toggled on and off (which sometimes makes certain ideas more difficult), and the menubar has an autohide state, which is new on Linux and caused specific bugs there.

And although we normally always show the tabbar and the navbar, there are popup windows where we don’t (toolbar=no), which, you guessed it, causes bugs.

Then we have per-window private browsing, which has an indicator which makes things ‘fun’ (and soon private browsing will look even more different from normal browsing).

Of course, while we stick to English layout direction is more or less fixed, but we ship both LTR and RTL locales on all platforms, which changes the order of things, which frequently leads to bugs.

Then there’s the padding that we added for “customize mode”, which affects layout of the toolbars and the (‘fake’) titlebar, which had its own problems.

Some issues are specific to pinned or overflowing tabs (sometimes even particular tabs), as well as panorama/tab groups.

Beyond that, styling is somewhat platform-specific, each with their own quirks:

OS X

OS X is, in a certain sense, “easiest” because the OS doesn’t have a lot of options that mess with things (font size, for example, isn’t easily configurable). But there’s still some variation:

  • Lion vs. pre-lion: 10.6, which we still support, has no fullscreen button in the titlebar (unlike 10.7-10.9) and has no concept of “Lion fullscreen”.
  • Spaces: causes odd bugs with panels.
  • HiDPI (“retina”): this causes bugs / missed cases. Add external displays which might not be hidpi, and you get even odder bugs (this one’s 10.9-only, too, it seems!).
  • RTL. Coupled with retina –> more bugs.
  • 10.9 broke more stuff.
  • Titlebar can be turned on/off now: cue more bugs.

Linux

Linux really means “Unix that has GTK”, as far as theming is concerned. Unfortunately that ends up being a wide spectrum of cases:

Windows

Windows really means “Windows XP, Windows Vista, Windows 7, Windows 8(.1) and all the corresponding Windows Server versions”. Which then means:

This list doesn’t include bugs caused or revealed by add-ons, but of course those also add interesting behaviour to the mix.

All in all, it’s been an interesting first year as an employee at Mozilla (I started April 1st, 2013), and I can’t wait to see all our changes ship: Firefox 29 is scheduled for release on April 29th.

Debugging chrome JS and mochitests – redux

About a month ago I posted about debugging chrome JS and mochitests. Since then, we’ve done a fair bit to improve the situation, and so I figured an update was in order (I’ve posted some of this to fx-dev and m.d.platform already, so apologies if you’re reading this twice). In particular:

  • After updating your chrome/remote debugging settings, no restart or new window is required anymore to start debugging, and the notes that say so are gone, too. So all you  need to do is toggle the required settings, and open the debugger from the menu.
  • As of today’s nightly (still building) you’ll be able to use the --jsdebugger flag to start the browser debugger on browser startup. (with many thanks due to Panos for fixing an issue that stopped this, as well as –jsconsole, from working on Nightly builds, but not self-compiled builds)
  • As of just now, mach on mozilla-central supports using the aforementioned flag with mochitests as well, and you can debug your mochitests in one easy command:
    ./mach mochitest-browser --jsdebugger <my-test(s)>

    The test framework takes care of setting the required prefs in the freshly created profile, – you won’t even be prompted to allow the connection – and will wait with running the tests so you have time to set breakpoints etc.

Happy debugging!

Summit experiences

Somewhat surprisingly given that I’ve been “around” for “a while”, this year’s was the first summit I went to. I’d been to several FOSDEMs, a EuroOSCON/EuroFoo, and several other conferences as a Mozillian, but somehow the invitations for Summits/MozCamps/Add-on events had always come at a time when I had already planned other international travel for whenever they were happening (once more my apologies to Will, who I think has never had any other response to invites than apologetic “erm, I’d love to, but I can’t make it — maybe next time?” emails).

Anyhow, this was the first time announcements came so early (and my traveling had somewhat quietened down) that I was still free. And what an event it was! I met a whole bunch of folks that I’d never seen before, despite interacting with them online for years now (I would add a list but I’d be sure to forget someone…). It’s great to have faces (and some stories) to the names. Then there were some of my Firefox MoCo teammates that I met for the first time. I also had a chance to hang out with a wide range of people, volunteer and employee alike, active in totally (or only slightly) different areas of the project than me (MoCo “people team” folks, documentation writers, reps, devtools team members, add-ons developers, Paris office workplace resource people, and the list goes on…) both during sessions as well as in bars, when walking through random bits of Brussels, or in the hotel lobby / breakfast room.

Session-wise, I first went to the excellent session about Privacy, Security and Data. Thanks Garrett, Stacy, Curtis, Crystal, etc. for a fascinating session about what we can do and how our biases about privacy as technically adept folks are different from most other people, who worry about completely different things.

The next day I spent a bunch of my energy showing off Australis and answering questions about it at the Innovation Fair together with Jared, Matt, and many of the UX team people (who had a bunch of other stuff to show off, not just Australis). At the Brussels booth, we had a good selection of questions and worries from people about add-on compatibility, Linux (sadly, our booth table was big enough for two laptops, on which we showed OS X and Windows builds, which probably prompted many of the questions), customizability, and how to test the builds. Hopefully we did a good job answering those questions, and we’re getting ever closer to shipping Australis on Nightly!

We then had a hurried lunch and I went to the “Developing empathy for your users” session. I met some more amazing people there, and we had an interesting time thinking through the motivations and interests of the people that our UX team met doing field research, and trying to see how and why they made decisions the way they did. Thank you Larissa and Maureen for an excellent session!

Afterwards I had a quick conversation with Blake about an idea that I’d been mulling over for a while now, and spent the rest of the afternoon hacking. Not that idea, but related, is now slowly progressing on bugzilla: create source maps for preprocessed chrome files. Otherwise, if I find some extra hours in my week (unlikely) I may try and produce something else to ease hacking on the front-end of Mozilla products. :-)

Finally, on Sunday, there was a bunch more hacking, and I went to the excellent session on DRM, where we had a somewhat depressing discussion about what we as Mozilla can do about the EME proposal in the W3C HTML spec.

On Monday, we all went home again! I think what I took away from the summit most of all was an increased awareness of the size and diversity of our community and its goals, as well as how the mission unites us. Kudos to the organizers for coordinating a complex and large event as well as they did! :-)

Debugging chrome JS and mochitests

Update: if you’ve enabled the correct preferences, you can now use the --jsdebugger commandline flag to open the debugger immediately! You can also use this flag with mochitests. For more info, see my new post.

Earlier today, when I was still sound asleep, some of the students from the MSU capstone project that Jared and I are mentoring asked about debugging their add-on’s JS. Rather than just answering them, I figured I’d write a blogpost as perhaps the information is useful to others as well.

While there is ongoing work to make debugging add-ons built with the SDK a more natural experience, you can already debug browser and add-on JS alike using the Browser Debugger. In fact, while it’s not very intuitive (and again, there’s a bug for making that better) you can also use the Browser Debugger to debug mochitests. I have already been using this method to figure out what broke in recent test failures on the UX branch, and am pleased to have something more robust than dump statements to figure those out.

Generally, here is how you start using the Browser Debugger:

  1. Open the Firefox Developer Tools Toolbox (Tools > Web Developer > Toggle Tools in the menus)
  2. Click the little ‘gear’ icon in the toolbox to open the settings page.
  3. Toggle the “Enable chrome debugging” and “Enable remote debugging” checkboxes. (you may need to scroll down in the toolbox pane to see these)
  4. You can now close the toolbox, and either restart Firefox as the checkboxes suggest… or just open a new window.
  5. There will now be a “Browser Debugger” item in the Web Developer submenu under Tools (sadly, there is no keyboard shortcut). Use it to open the debugger.
  6. The Browser Debugger starts another Firefox process to remotely debug your existing Firefox process, and your existing one will therefore prompt you whether you want to allow access to the debugger (as doing so essentially gives full control of the debuggee to the debugger). Click “OK” in this dialog.

Now the browser debugger’s list of source files should start filling up. You can use the debugger much like you’d use the web debugger that is in the Toolbox: filter for sources, or even search through fulltext of sources to quickly find what you need, set (conditional) breakpoints, add watches, etc.

For mochitests, the situation is much the same except that, if you’re like me, you’ll quickly get annoyed because you get to go through the steps of enabling and starting the debugger manually every time. So I filed a bug and attached a patch to at least eliminate the opening of new windows, but got stuck trying to get it to pass all the tests.

In any case, you can start your test(s) with the --no-autorun option, and then go through the steps outlined above (opening a new window instead of restarting). Make sure you close the toolbox and the extra window, as these might otherwise interfere with running your tests. When you’re done setting your breakpoints and such, click the button in the mochitest window to start running your test(s). Happy debugging!

You don’t know what you’ve got ’till it’s gone – or, tab load detection gone wrong

TL;DR: if you own/wrote code that adds an event listener for the "load" event on a tab, doublecheck that you’re listening for that event on a tab’s <browser> element, and not on the <tab> (eg. the value returned by gBrowser‘s selectedTab property).

In the past two weeks some of us on the Firefox front-end team have been working to get the UX tinderbox builds green again. When we initially started work on Australis, we broke a couple of tests and in the interests of moving forward those were not immediately fixed – we were on a branch, out of the way of everyone else, and it wasn’t our number one priority. Over time this resulted in pretty orange trees, and so we recently moved to fix all the tests we’d broken and return the tree to a functioning, green state.

Although some tests did catch bugs on our side, in general we found subtle bugs in existing tests, which we have (helped) fix both on mozilla-central and the UX branch. One of those that I figured deserved a blogpost of its own was a pattern that tended to look roughly like this:

let tab = targetBrowser.selectedTab;
let win = tab.linkedBrowser.contentWindow;
let expectedReadyState = aURL == "about:blank" ? ["interactive", "complete"] : ["complete"];

if (aOnload) {
  let handler = function() {
    if (tab.linkedBrowser.currentURI.spec != aURL ||
        expectedReadyState.indexOf((win.document || {}).readyState) == -1) {
      return;
    }
    tab.removeEventListener("load", handler, false);
    executeSoon(aOnload);
  }
  tab.addEventListener("load", handler, false);
}

Unfortunately this code broke with the Australis changes, which include removing the empty favicon for pages which don’t have one. The bug in the code may not be immediately obvious, but what the code was doing was adding an event listener on a tabbed browser’s <tab> element (the leaf in the tabstrip at the top), rather than the corresponding <browser> (containing the actual page). Why did that work at all? Well, the tab element contains an image: the page’s favicon. When that loaded, a load event bubbled up. As we’re removing the favicon if the page doesn’t have one, rather than replacing it with an empty placeholder as we do on current versions of Firefox, no such event fires for pages without a favicon, and the relevant tests/code broke completely in Australis (for some of these tests, it is quite possible they caused occasional random orange before).

The manual checking of the page’s readyState is a clue that this isn’t the best way to detect when the page has loaded. Instead of using tab.addEventListener, use tab.linkedBrowser.addEventListener (and the same for removeEventListener, of course).

I’ve attempted to audit the mozilla-central tree for this kind of code, but I may not have been thorough enough by just grepping for things like tab.addEventListener. If you have written code depending on tab loads, be it in tests, or add-ons, or elsewhere, doublecheck how you detect these events!

15 years of Mozilla – and my first day

Today, Mozilla celebrates its 15th birthday. By a cunning plan sheer coincidence, today is also my first day as an employee, after being involved with the project for a little over 8 years. I’m extremely happy with everything Mozilla achieved in the years behind us, and after a period of being a little less active, I’m pleased to be able to help fulltime in the time to come.

I’m in the Firefox Desktop team, and I’m excited! I’ll (continue to) see all of you around, I’m sure (and will be in Mountain View between April 8th and 20th, if that helps).

Venkman 0.9.88.1 (or, why your scripts might seem to be gone)

A few days ago, the kind people at AMO approved version 0.9.88 of the JavaScript Debugger Venkman. The last release was… 2 years ago! Funnily enough, some users immediately found a show-stopping issue on Firefox 4, which is fixed in Venkman 0.9.88.1, which is currently waiting for review now also available on AMO (thanks to Nils Maier for reviewing!).

So what changed, you wonder? Well, obviously we fixed some bugs. I’d like to briefly discuss just one of them, because it has some repercussions for how you use Venkman:

We no longer start the debugger service when the browser starts (by default)

There were several bugs on file about how Venkman and Firebug made Firefox slower. On top of that, there were recent changes in how components were handled, which meant we could no longer start Venkman (and ask for the debugger service to start) as early as we used to. In fact, the native support from the debugger service to start “really early” was removed by some of the Firefox/Gecko developers as part of this effort. Venkman relied on this support (Firebug doesn’t, they do something similar from their own code).

Why was it important to start the debugger service early?

Because the debugger service only “knew” about functions, variables and script that was loaded when it was started. In other words, if you loaded a script, and then loaded the debugger service after doing so, you wouldn’t be able to debug those files.

So if you no longer start the debugger service early, how does this work?

Thanks to some great work by Wladimir Palant (of AdblockPlus fame), as of Firefox 3.5 we can also get the debug information about functions when they are called. So, when you start Venkman, we will start the debugger service, and for every JS function call, it will tell Venkman about the new code.

I don’t see my scripts or functions when I open Venkman. How do I debug my code?

You have two options:

  • You can load the file (if it’s not shown in the scripts view, try File > Open File (local files) or Open Web Location (urls)) and then set a “future” breakpoint. Venkman will stop there when the code is executed. Instead of loading the file manually, keep in mind any call into a function in the file will make it appear in the scripts list. It shouldn’t be hard to load the file.
  • You can reload the page, and Venkman will see all the scripts appear just like it used to.

Can I get the old behaviour back?

We would prefer it if you tried to work with Venkman the way it is now and let us know about things you think we should do differently or improve. If you’re unable to debug code now that you could debug fine before, please let us know!

If you really need to start the debugger service early, just enter “/startup-init true” (without quotes) at the Venkman console, and we will start the debugger service early (specifically, at the ‘profile-after-change’ notification – slightly later than before, but for most usecases this should not matter).

What about Firebug?

There’s a Firebug 1.6a20 alpha release that is compatible with Firefox 4. I don’t know if they still start the debugger service early if that pane is enabled.

ChatZilla and Firefox 3.5

Just a short note, quite some time ago some trunk changes broke ChatZilla. Accessibility also required some changes. All of these fixes have happened (thanks to dbaron for helping out with the layout fix) – but there has not yet been a release. Seeing as we’re getting close to 3.5, I thought I should note that those affected by these issues (say, people on 3.5b4) can download a nightly ChatZilla build here. New builds appear there after every (set of) change(s) in CVS. This should fix any compatibility issues. If it does not, please file a bug.

Edit: ChatZilla 0.9.85 (released some weeks ago…) has all these fixes, and will work fine with 3.5. Oops! :-)

Moving from CVS to Mercurial

Yesterday, Venkman moved from CVS to Hg. For the benefit of others who may want to move other extensions, here is a rough attempt to outline the steps I took.

First, some notes of caution:

  • HG uses a character encoding specific to your machine. For my mac, that turned out to be mac-roman. You usually don’t want that, and need to tell it you want it to use utf8 instead. I could actually not convince it to do this for the author map – it stored the authors in mac-roman anyway. Check your imports carefully.
  • HG’s default ConvertExtension is your friend, as long as you tell it what to do the right way.
  • You probably want to create a test repo (I ended up using several, in trial and error!) at hg.mozilla.org/users. Instructions for doing that may be found here. Keep in mind that once you stick something in a Mercurial repo, it will be there forever. This means anyone pulling from your repo will have to keep downloading all those files. Be careful about what you push to the repo, because once you’ve pushed something there’s no going back (short of asking IT to delete the repo and trying again).

Alright. Down to the actual import. Here is the actual steps I ended up following. When I say “ended up” I mean “after trying N different things which didn’t work”, where N was large enough to keep me busy for a fair number of hours.

  1. Check out the relevant code from CVS. In my case, this meant:
    cvs -d :pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot co mozilla/extensions/venkman
  2. Enable the convert and mq extensions. Edit your ~/.hgrc file and include:
    [extensions]
    hgext.convert=
    mq =
  3. Decide whether you want all the branches in CVS. If, like me, you’re importing an extension, you probably don’t care about the Firefox/Mozilla release branches. You just want trunk history. In order to do this, we ask the convert extension to split up branches. Edit your ~/.hgrc file and include:
    [convert]
    hg.usebranchnames=0
    hg.clonebranches=1
  4. Now you can run convert, more or less like this:
    hg --encoding utf8 convert vnkCVS/mozilla/extensions/venkman venkman-initial
  5. Inspect your handiwork: you will now end up with several directories, one for each branch. You presumably want “default”, which should correspond to trunk. We will convert from hg to hg in a bit, to obtain just that.  Go back to your ~/.hgrc file and remove the [convert] section you added in step 3. This way, the new repo we’ll convert to won’t still have the “default” directory.
  6. Additionally, we still need to map authors. CVS used something like: “foo%somecompany.com”, and in Mercurial, we expect something of the form “John Doe <johndoe@mozilla.com>”. So we need to define an author map file, in which each line simply maps one set of authors to the next. For example:
    johndoe%mozilla.com = John Doe <johndoe@mozilla.com> . I uploaded the Author map for Venkman CVS to hg import that I used. It probably does not cover everyone who committed to your repo. If there are aliases that you’re not familiar with (Mozilla CVS is pretty old!) then Google and asking on IRC are easy ways of figuring out who’s who. To create a complete author map, I used some ad-hoc sed magic on:
    hg log | grep "user:" > foo.txt
    
  7. You may want to unify the entries of committers who have committed using different committer IDs. Ohloh can help there.
  8. Run hg convert again:
    hg --encoding utf8 convert --authors myAuthorMap.txt venkman-initial/default/ venkman-final/
  9. Check hg log. If there are loads of tags in which you’re not interested, you can use the hg strip command to strip the last hg revision, which added all the tags.
  10. Verify everything worked. Then add the correct “default-push” line to the .hg/hgrc file for the new repo you created, and push to your user repo. Check that everything is correct by reviewing the hgweb overview of things. If so, change the default-push line to point to the “real” repo, and push all the changesets there. You’re done!

This may not be the easiest or best way to do things, but that’s the way I managed – suggestions/improvements appreciated!