Essays

Essays for February 2010

1 month ago

Wednesday, February 17, 2010

Considerations Involved in IP-based Geolocation and User Language Detection

I’m going to revisit the UPS homepage—one more time—that I already discussed in Improving the UPS Homepage by Remembering Fitt’s Law and It’s 2010—Use Clickable Labels on Checkboxes. Despite the the sparseness of this particular page, there is a third thing here that I think could improve the user experience significantly and reduce a barrier to entry to the site (and concomitantly, potential premature user abandonment).

I think it would be very useful to pre-populate the dropdown based on the user’s IP-based geolocation and browser language settings (the Accept-Language header). Why pre-populate instead of automatically redirecting? Zak Wilson and Ivan Stojic have argued that IP-based geolocation should not be used in web apps because it causes more problems than it solves. I don’t fully agree—those users are in the long tail and for the majority of users I would be willing to bet geolocation gets it right. The annoyance caused to the few users who travel extensively or are behind corporate firewalls isn’t really enough to outweigh the benefit conferred to the average non-English speaker who goes to google.com and yet sees the site in what’s probably their language.

All the same, Zak and Ivan are correct that the Accept-Language header is a better piece of information to use first. Given the potential for even that to be incorrectly set, and the fact that UPS has already decided to deploy an interstitial, I think it makes sense to at least pre-populate the dropdown with a best guess.

However, it’s quite possible that UPS has considered this feature and determined that visitor satisfaction counterintuitively goes down as a result. Why? Because given that the site can obviously figure out the correct setting for most users, they may be annoyed that they were presented with an interstitial page in the first place. The average user probably isn’t aware that their language settings can be automatically determined, and so presenting them with an uninitialized dropdown hides this fact.

Again, this possibility only underscores the necessity of A/B testing. Much like other complex dynamic systems with many inputs and outputs—weather, nonlinear electric circuits, molecular biology—it is difficult to predict the ultimate outcome of seemingly innocuous or superficially beneficial changes when users are involved. It would be great if someone from UPS could comment on this page and discuss the considerations involved while designing it.

1 Comment

1 month ago

Monday, February 8, 2010

Using CSS Selectors Instead of XPath As the Default Locator Strategy in Selenium

We use Selenium to run in-browser acceptance tests in all our Rails apps via the Selenium on Rails plugin. With early versions of Selenium you had to use verbose and clunky XPath locators to reference DOM elements in the tests, such as:

//div[@class='content']/div[@class='sidebar']/a

For a while now, though, the cssQuery library has been integrated into Selenium Core, allowing you to use CSS selectors instead. For example, the above XPath locator could be written with CSS selectors as:

css=.content .sidebar a

In addition to being shorter, the Selenium documentation itself points out that most experienced users recommend CSS locators because they’re faster for the Javascript engine to parse, which means faster tests.

Making CSS Locators the Default

While the CSS locators themselves are great, it’s a minor annoyance of mine that they’re not the default locating strategy. As a result, every locator has to be prepended with css=. If you want to change this, apply the following patch to selenium-core/scripts/selenium-browserbot.js:

@@ -1107,7 +1107,7 @@
         if (locator.startsWith('document.')) {
             return this.locateElementByDomTraversal(locator, inDocument, inWindow);
         }
-        return this.locateElementByIdentifier(locator, inDocument, inWindow);
+        return this.locateElementByCss(locator, inDocument);
     };
 }

Minor Annoyances With CSS Locators

The only thing that I don’t like with CSS locators is that indexing specific sibling elements is more verbose—it must be done with nth-child():

.content .sidebar:nth-child(1) a

With XPath you can use a simple pair of brackets:

//div[@class='content']/div[@class='sidebar'][1]/a

It would be really nice if CSS selectors had the same bracket-style indexing syntax as XPath. (Of course, this is a limitation of CSS itself, not Selenium.)

In addition, nth-child() is a little more brittle in that it isn’t constrained to the current selection scope. For example, assume you have markup like so:

<div class="content">
  <div class="something_else">…</div>
  <div class="sidebar">…</div>
</div>

There is now a non-sidebar sibling <div> appearing before the sidebar <div>. In this case, there will be no element that matches .sidebar:nth-child(1)—the sidebar is matched by .sidebar:nth-child(2). This means that adding additional unrelated markup to your page can break your tests if you’re using CSS locators. If you were using the XPath locators in this case, the indexing of the element in question would remain constant because the index doesn’t refer to children, but to elements matching that specific XPath. (If you added additional sidebar <div>’s the XPath would break as well, but all the same it’s still less brittle.)

One final point to note is that there’s also a bug in the cssQuery library that prevents nth-child() from working correctly—it’s Selenium bug #698. Unfortunately, the patch posted on the bug does not fix the problem for me. Instead, you have to resort to suffixing any nth-child() selector with a child or sibling combinator like so:

.content .sidebar:nth-child(1) > a

Despite these minor wrinkles, I find that the CSS locators used with Selenium are less verbose in general and lead to faster running tests.

Comments