Use ModHeader Extension to Pass Single-Sign-On Page in Selenium Tests
Use Selenium WebDriver to modify HTTP headers using ModHeader to pass SSO, or a better and simpler way …
I was doing a showcase for a potential customer a few weeks ago. When possible, I usually try to write one or two tests live against the customer’s website.
This customer’s test site uses Sigle-Sign-On (SSO).
Click the ‘Sign in with Google’ button will lead to the Google Account Sign-in page.
However, Chrome disables logging in to Google Account by automation.
Solution: Use Chrome Extension to pass SSO
The customer showed me how they got around the problem manually: using the ModHeader Chrome extension to set a cookie to pass SSO.
I asked them to send me the cookie string and quickly implemented a user login automation test (in raw Selenium WebDriver + RSpec). Here was the execution:
And test script:
Start ChromeDriver with the extension: ModHeader
chrome_extension_file = File.join(File.dirname(__FILE__), "extension", "ModHeader_v3.1.25.crx")
the_chrome_options.add_extension(chrome_extension_file)
For detail on how to use a Chrome extension in Selenium scripts, please check out this article: “Drive Chrome with Extensions using Selenium WebDriver”.
2. Drive the ModHeader extension window to set the cookie
Find the extension window URL and drive it just like another web page.
extension_id = "idgpnmonknjnojddfkpgkljpfnnfcklj"
driver.get("chrome-extension://#{extension_id}/popup.html")
elem = driver.find_element(:xpath, "//input[@placeholder='Name']")
elem.send_keys("Cookie")
elem.send_keys(:tab)
driver.find_elements(:xpath, "//button[@aria-label='Expand']").last.click
sleep 0.25
elem_value = driver.find_elements(:xpath, "//div[@id='dialog-content']//textarea")[2]
elem_value.clear
driver.execute_script("arguments[0].value = arguments[1];", elem_value, sso_proxy_value)
sleep 0.6
elem_value.send_keys(" ")
elem_value.send_keys(:tab)
driver.find_element(:xpath, "//button[@data-mdc-dialog-action='close']").click
As you can see (from the animated GIF and the above test steps), we may drive ModHeader for other purposes.
By the way, the value of an SSO cookie is like below:
_sso_proxy=...VERYLONG...; intercom-session-XXXXXX=...LONG...
3. Extract the ‘SSO’ test steps into a reusable helper function.
The tests need to ‘SSO’-in a lot. So I performed two Functional Test Refactorings:
A test script looked like the below:
describe "New" do
include TestHelper
before(:all) do
@driver = Selenium::WebDriver.for(browser_type, browser_options)
driver.manage().window().resize_to(1280, 720)
sso_pass # defined function in the test_helper.rb
driver.get(site_url)
end
after(:all) do
driver.quit unless debugging?
end
it "New Case Name" do
# then login using personas such as "mary" or "manager01"
# ...
end
end
The customer was quite impressed with the test scripts. However, I would not be happy with the approach (not test scripts) if this was my app.
The time to pass SSO (driving the extension): 6 seconds
Six seconds is hardly a long time. But it would be a significant time that we might want to save for a large regression suite, e.g. 100 tests => 6 minutes. If the suite is as big as my WhenWise app’s, the total SSO execution time would be 50+ minutes (if running on a single build agent).Test scripts only work in Chrome browser, not Firefox and Safari.
i.e., unable to use automated tests for Cross-Browser Testing.
There is a simple way to address internal SSO testing.
A better way: Disable SSO on Dev/Test servers
A better way is to not use SSO on Dev/Test servers for easier development and testing. One common mistake in software testing is that software teams treat the internal server instances as the production server, which is unnecessary. For example, for testing emails, do you really need to send the emails out (via the Internet) and check their arrival in a test email account? No, you don’t, the effort of verifying SMTP protocol is redundant. You only need to verify the emails sent to an SMTP server and the actual email content. Check out this article: Testing Emails in Automated Test Scripts with Fake SMTP server: MailCatcher.
By the same token, during internal testing, I would recommend turning off non-essential checks, such as Captcha or SSO for Dev and Test servers (only enable them in Staging and Production, with manual testing to verify them) to simplify and speed up the testing process.
How?
By adding a switch based on the server environment. A server environment flag ( Rails.env
) is made popular by the Ruby on Rails framework. But I have implemented the same concept in Java before that. In other words, this pattern applies to most applications regardless of their implementation language.
Default server environments in Rails are: development
, test
, and production
. As you can imagine, many configuration settings are determined by Rails.env
. We may make use of it for better testing support too.
<% if Rails.env == "development" || Rails.env == "test" %>
<%= render :partial => "auth/form" %>
<% else %>
<%= render :partial => "auth/sso" %>
<% end %>
We can use the ModHeader extension to customize request headers to assist more than just passing SSO, the usage is the same:
Start Chrome with the ModHeader extension (.crx file)
Drive the ModHeader window …