I’m automating part of the the regression testing one of our sites using Selenium and had to use 3 different patterns within one small area of the system (login). Since I’ll likely have to explain to someone how to add to or maintain these scripts I figured I might as well write these patterns down for later reference. We’re a Ruby shop (though less than this time last year) so all examples are using the selenium-client gem.

  • Traditional Submit – This is the classic way of the web, since basically its inception. Stuff is passed to the server, the server does something, and the results are displayed via a page refresh.
      <pre lang="ruby">def test_both_blank
        @browser.open "/"
        @browser.click "//input[@name='commit' and @value='Login']", :wait_for => :page
        begin
          assert_equal "The email address or password was incorrect.", @browser.get_text("//div[@class='system_error']")
        rescue Test::Unit::AssertionFailedError
          @verification_errors 
      <p>
      The only magic required here is the <i>:wait_for => :page</i> which does exactly what it implies; it waits for the page to refresh.</p>
    
  • Internal Submit - This type is just manipulation of the DOM in the browser and nothing leaves that little sandbox. The classic example is when you have multiple forms on a page but you just change an attribute of it to show or hide it. This means you can’t wait for the page to load as it never unloads. Nor can you wait for an object to be present as it is, at least in the DOM. But you can check whether it is visible or not.
      <pre lang="ruby">def test_forgot_password_link
        @browser.open "/"
        @browser.click "link=exact:Forgot password?"
        @browser.wait_for_text('Enter your email address')
        begin
          assert_equal(false, @browser.visible?("//form[@id='login_frm']/fieldset/div[1]/input"))
          assert @browser.visible?("//form[@id='forgot_pwd_form']/fieldset/div[1]/input")
        rescue Test::Unit::AssertionFailedError
          @verification_errors 
      <p>
      Here is am checking that both the thing that should no longer visible is indeed hidden and the bit that should be in its place is.</p>
    
  • AJAX Submit - Of course, we are using AJAX (like everyone else) and I avoided it as long as I could, but ended up being nicely abstracted into the land of easiness. AJAX submits of course don’t refresh the page (like the Internal Submit) but contacts the server and displays the result (like the Traditional Submit).
      <pre lang="ruby">def test_forgot_password_no_email
        @browser.open "/"
        @browser.click "link=exact:Forgot password?"
        @browser.wait_for_text('Enter your email address')
        @browser.click "//input[@name='commit' and @value='Go']", :wait_for => :ajax
        begin
          assert_equal "That email address was not found.", @browser.get_text("//div[@class='system_error']")
        rescue Test::Unit::AssertionFailedError
          @verification_errors 
      <p>
      Sweet! Wait for the the ajax request that happens as a result of the click and then continue. Now there is some serious black magic going on here. You can tweak it a bit with <i>:javascript_framework => :jquery</i> (or :prototype, but that is the default so you don't really need to specify that) as an option on the click. Having to tag that on every AJAX action is a pain, so I'm getting my selenium connection like this now.<br></br>
      </p>
      <pre lang="ruby">@browser = Selenium::Client::Driver.new \
        :host => "localhost",
        :port => 4444,
        :browser => "*firefox",
        :url => "http://localhost:3000",
        :timeout => 10000,
        :javascript_framework => :jquery      
      @browser.start_new_browser_session
      <p>
      One of our <a href="http://calc.zerofootprint.net">other sites</a> uses both jquery and prototype so I would actually have to specify it on each line. Ah well.</p>
    

Can anyone think of any other types of form submits?