Instead of having a dedicated login page, some sites return a 403 Forbidden HTTP status code and include the login form in an HTML body of a custom 403 page. For example, Drupal admin pages work this way. While this may seem a little odd, it works; all modern browser will display the HTML and few, if any, will note the Forbidden status.

Mechanize on the other hand raise an exception when it receives a 403 status. Fortunately, it returns the page it received as part of that exception. Here’s how to handle it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mechanize = Mechanize.new

begin
  login_page = mechanize.get("http://localhost/admin")
rescue Mechanize::ResponseCodeError => exception
  if exception.response_code == '403'
    login_page = exception.page
  else
    raise # Some other error, re-raise
  end
end
login = login_page.form_with(:action => '/login') do |f|
  f.field_with(:name => 'user').value = user
  f.field_with(:name => 'password').value = password
end.submit
raise 'Login Failed' if login.body !~ /Logged in!/

This code also works in the case where you don’t get a forbidden status, so it can be used generically.

For bonus points you can use the same code in a Cucumber step by changing:

1
login_page = mechanize.get("http://localhost/admin")

to:

1
login_page = webrat.adapter.mechanize.get(path_to('the admin page'))

(assuming you’ve set up “the admin page” in paths.rb).

Comments