Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
without_page_refresh capybara helper

I recently had to write a small capybara helper:

def without_page_refresh
  page.execute_script("window._withoutPageRefresh = 'BAM'")
  yield
  page.evaluate_script("window._withoutPageRefresh").should == "BAM", "Page was navigated away"
end

Use case:

You are building a form that gracefully degrades when javascript is not enabled. It goes something like this:

# uses rack-test so no javascript
scenario "User can lose money in an accessible way" do
  visit "/your_account"
  page.should have_content "You have $100"
  click_button "Charge me"
  page.should have_content "You have $50"
end

Next step is to make that form do the ajax thingy. You copy test above and switch it to use javascript driver:

# uses selenium for javascript
scenario "User can lose money with style", :js => true do
  visit "/your_account"
  page.should have_content "You have $100"
  click_button "Charge me"
  page.should have_content "You have $50"
end

Newly written test is pretty good except that it passes without writing a single line of javascript. So here's when that helper comes into play. Our javascript test becomes:

# uses selenium for javascript
scenario "User can lose money with style", :js => true do
  visit "/your_account"

  without_page_refresh do
    page.should have_content "You have $100"
    click_button "Charge me"
    page.should have_content "You have $50"
  end
end

Now javascript test fails with "Page was navigated away" since nothing is preventing that form from submiting to another page.

PIVOTAL LABS
Standup 10/14/11: lvh.me

Ask for Help

"Pie-clearfix behaves differently on heroku vs. locally."

Compressing assets? Compressing locally? Try with a proxy? IE stylesheet limitations?

"Rails 3.1.1 asset pipeline not compiling images. Before the 3.1.1 upgrade, images were compiling correctly. After the upgrade, images do not compile"

"How can we test subdomain behavior in Selenium?"

Try lvh.me. lvh.me is a domain that points to your local virtual host. nslookup for lvh.me shows the address as 127.0.0.1.

Interesting Things

  • Dance party in design area sometime between 3-5pm

LABS
Standup 1/19/2011: How would you google this?

Ask for Help

"Anyone using Selenium 2 and Webdriver?"

One of our internal projects is using it.

"How to stop time in Jasmine?"

There were a couple suggestions:

  • use a global function, such as 'now'
  • send in your own clock object

"Whurl standalone, or more dynos?"

Apparently Whurl is running on a single dyno at Heroku, so a single bad request can tie up Whurl until the request times out. Where are you TildeWill?

"What's this called?"

Imagin these are records in a relational database, with the records on the left having a one to many relationship with the records on the right. How would you google this?

one to many diagram

PIVOTAL LABS
Standup 12/17/2010 Comparing indexed date columns, git subtrees, Headless Selenium for CI

Helps

Is there a way to get MySql indexing to speed up queries involving greater and less than operators on date columns?

Postgres handles these operators a little bit better than MySql, but may not actually solve this problem.

Using millis instead of dates would give the DB the best chance of handling this scenario.

We are using Git's subtree merge facility instead of submodules to stay synced to a different repository for part of our project. How do we push changes back to that repo?

See Tim Connor's blog post "Git sub-tree merging back to the subtree for pushing to an upstream". Early in that post is a pointer to an article describing the the subtree merge operation. Tim goes on to explain how to push your changes back through the chain.

Interesting

  • Some cloud environments leave the names of temp files visible even when their contents are not accessible. Be sure to use obfuscated names for your temporary files!

  • The "Headless" gem allows you to easily set up an alternate "display" that allows programs to execute in a headless environment. See this blog post about how to use Headless to run Selenium tests on a CI box: http://www.aentos.com/blog/easy-setup-your-cucumber-scenarios-using-headless-gem-run-selenium-your-ci-server

  • Ccrb will bog down to painfully slow levels if more than a couple of CC Tray clients are pinging it repeatedly during a build.

  • Cron will not honor your .rvmrc file unless you do some work to set up the environment. If you set up your cron job like this:

0 6 * * * /bin/bash -l -c 'echo /home/someuser/.rvm/bin/rvm rvmrc trust ... && cd ... 

the -l & -c parameters cause bash to load your environment as if your were logging in before running the specified commands. Someone also mentioned that rvm-shell can be used as a solution to this problem.

PIVOTAL LABS
Standup 3/12/2009

Interesting

  • Selenium removes the If-Modified-Since header. This gets in your way if you are testing ETags.

  • Speaking of ETags - they are awesome. See Ryan Daigle's article for code.

Help

Just how slow is Mongrel when serving static images?

The answer is - pretty slow. The reason for the question was that Google's crawler tends to keep a single connection open and fire lots and lots of http requests over a period of several hours. With a standard Nginx/Mongrel setup, this would tie up a mongrel for this entire period.

A proposed solution to this problem is to use HAProxy between Nginx and Mongrel.

LABS
Run JavaScript in Selenium tests. Easily.

Here's the gist of this post: gist.github.com/58876

Ever since I've started using Webrat, a lot of the pain of Selenium has gone away for me. There's still a little bit of pain though. Part of it is caused by the fact that it's harder than it should be to just execute arbitrary bits of JavaScript in in your current window under test. Well no more. Here's a helper:

module SeleniumHelpers
  # Execute JavaScript in the context of your Selenium window
  def run_javascript(javascript)
    driver.get_eval <<-JS
      (function() {
        with(this) {
          #{javascript}
        }
      }).call(selenium.browserbot.getCurrentWindow());
    JS
  end

  private

  # If running in regular Selenium context, get_eval is defined on self.
  def driver
    respond_to?(:selenium) ? send(:selenium) : self
  end
end

To use it with Cucumber, do like so:

World do |world|
  world.extend(SeleniumHelpers)
  world
end

To use it with POS, do like so:

class JavaScriptHelperTest < SeleniumTestCase
  include SeleniumHelpers

  # your tests go here...
end

Now what?

Now to run JavaScript in your Selenium window, just call run_javascript. Note that it's always going to return a String, so you may have to massage the output a tad:

checked_boxes_count = run_javascript <<-JS
  jQuery('input[type=checkbox]:checked').size();
JS

checked_boxes_count         # => "3"
checked_boxes_count.to_i   # => 3

Cooler stuff

While Webrat's DSL for traversing web apps is awesome, I've always found the alternatives (Polonium for example) to not jive well with how I think. They're way better than talking directly to Selenium, you're still locked in to a certain style. The run_javascript helper makes it easier to write your own helpers that fit your own style.

module ElementHelpers
  class Element
    def initialize(context, selector)
      @context, @selector = context, selector
    end

    def hide!
      call(:hide)
    end

    def show!
      call(:show)
    end

    def visible?
      call(:is, ':visible') == 'true'
    end

    private

    def call(fn, *args)
      @context.run_javascript <<-JS
        return jQuery(#{@selector.inspect})[#{fn.to_s.inspect}](#{args.map(&:inspect).join(', ')});
      JS
    end
  end

  def locate(selector)
    Element.new(self, selector)
  end
end

Now you can write your tests like so:

class JavaScriptHelperTest < ActiveSupport::TestCase
  include SeleniumHelpers
  include ElementHelpers

  def setup
    @element = locate('#all')
  end

  def test_visible_by_default
    assert @element.visible?
  end

  def test_hide_element
    @element.hide!
    assert ! @element.visible?
  end

  def test_show_element
    @element.hide! # setup
    @element.show!
    assert @element.visible?
  end
end

Credit should go to Brian Takita, since he did most of the hard work and I just wrote a method. Let me know if you have any issues or ideas with the helper, and may all your tests be green.

PIVOTAL LABS
Standup 01/12/2009: require & class reloading, acts_as_fu

Interesting Things

  • Using 'require' explicitly interferes with class reloading in Rails

Frederick Cheung discusses this in more detail here. This might be related to the Selenium + class reloading issues some pivots have experienced in recent weeks. The alternative is to rely on Rails automagic loading or 'require_dependency'.

  • acts_as_fu makes writing database independent tests for models is easier

Props to pivot Pat Nakajima for creating acts_as_fu.

PIVOTAL LABS
Standup 11/14/2008: XXL Mongrels and Non-Model Reports

Interesting Things

Ask for Help

"How big should a typical mongrel be? Ours is starting out at over 200 megs but is not leaking from that point."

Everyone agreed that 50MB to 70MB is standard and anything over 100MB is considered pretty big. People suggested RubyProf for inspecting object counts and possibly tracking down the memory hogging code.

"What pattern does everyone use for non-model Reports with ActiveRecord? We are trying to create a report that counts a single model and groups by two associated models"

There was consensus around modeling a distinct report object and calling the referenced models. For example, FooReport and FooReportController fit nicely in a RESTful Rails world.

LABS
Pattern for Functional Testing

Regular Selenium tests (in Java) might look like:

selenium.open("/login");
selenium.type("id=username", "bob");
selenium.type("id=password", "password");
selenium.click("Login");
selenium.waitForPageToLoad();
selenium.click("My Account");
selenium.waitForPageToLoad();
assertEquals("bob", selenium.getText("//table[2]/tr[3]/td[2]/");

After a few tests, this kind of thing becomes painful to manage. The typical solution is to create a bunch of constants for IDs and Xpaths, but that doesn't help too much.

Fellow Pivot Mike Grafton came up with a cool pattern for improving on this. The idea is to create a class representing each page of your web app. Each class contains two types of methods: a bunch of action methods (clickMyAccountLink(), typeUsername()), and a bunch of inspection commands (isLoginButtonEnabled(), getLoggedInUsername()).

When an action takes you to a new page, the corresponding action method returns a new class representing that page. When it stays on the same page, the method just returns "this". This allows methods to be chained to make the tests more readable.

Here's how that test would look using this new pattern:

MyAccountPage myAccountPage = new LoginPage(selenium)
  .typeUsername("bob")
  .typePassword("password")
  .clickLoginButton()
  .clickMyAccountLink();

assertEquals("bob", myAccountPage.getLoggedInUsername());

The constructor of each page class should validate that it's on the correct page (waiting if necessary, and perhaps asserting on the page title).

PIVOTAL LABS
Standup 08/04/2008

Ask for Help

"Does anyone know why a Selenium click event might not trigger the same activity as directly triggering the DOM id through javascript? We have a form submit button that works fine when directly activated but doesn't work in Selenium."

It was suggested that perhaps this is a timing issue. Maybe some required JS for the form hasn't loaded before Selenium is trying the event.

One workaround would be to test only the form submission called by on-click instead of the click itself.