Case Study: Automated Testing ‘Login with Remember Me’ in Selenium WebDriver
a step by step guide to developing this slightly tricky automated End-to-End test for this common web app feature.
This article is included in the “How to in Selenium WebDriver” series.
“Login with Remember Me” functionality is common, nearly on all web apps, but it is not as easy as you would expect for automated testing this feature properly.
‘Remember Me’ ensures that you remain signed in (with the help of cookies) the next time you visit the site, even after the browser is completely closed. This tutorial will show you how to set Chrome’s options to use the same browser profile and successfully test ‘Remember Me’ in Selenium WebDriver.
1. Test Design
Log in with the Remember Me checkbox checked
Copied the URL of logged in page, e.g. Dashboard
Close the browser
Start a new browser
Paste the dashboard URL
Verify logged in
Perform the above test steps manually, and it will pass.
2. Automated Test failed; why?
Implement the above steps into a Selenium WebDriver test script, as below.
it "sign in with cookie failed because different chrome profile is used" do
@driver = $driver = Selenium::WebDriver.for(browser_type, browser_options)
driver.get(site_url + "/sign-in")
sign_in("pro", "test01", :remember_me => true) driver.quit
# start a new browser session
@driver = Selenium::WebDriver.for(browser_type, browser_options) visit("/dashboard")
expect(page_text).not_to include("Please log in")
end
The test failed on the last step, expect (page_text).not_to include(“Please log in”)
.
Why? The manual testing passed, so what is the difference here?
The reason: Selenium WebDriver, by default, starts a new Chrome browser with a new profile each time, which affects the cookies. Browser profiles (on Chrome) do not share cookies.
3. Verify Cookies saved after ‘Remember Me’
When a user chooses to ‘Login with Remember Me’, a cookie entry (often called remember_token
) is saved, which is later used for authentication.
The test script below will verify the cookie token has been created.
it "Cookie is created on sign in with remember me and cleared on sign out" do
sign_in("bob", "test01", :remember_me => true)
remember_cookie = driver.manage.cookie_named("remember_token")
expect(site_url).to include(remember_cookie[:domain])
expect(remember_token_cookie[:value].size()).to eq(22)
visit("/sign-out") # shall clear cookie
# normal sign in
visit("/sign-in")
sign_in("wendy", "test01")
# should not have a cookie
shall_not_allow {
remember_cookie = driver.manage.cookie_named("remember_token")
expect(remember_cookie).to be_nil
}
visit("/sign-out") # shall clear cookie
end
The above might partially serve automated testing the ‘Log in with Remember Me’. It merely checks whether the cookie entry has been created, not actually automatic-signed-in.
Still, how can we use an automated test to test this common feature end-to-end, from a user’s perspective?
4. Try to use the same chrome user data profile
The solution is to avoid creating a new profile each time.
It is possible to specify ChromeDriver to use a specific profile rather than a new profile for each Chrome browser. Choosing a profile can be done in the browser options’ add_arguments
and passing a path into user-data-dir
.
An example of how this works is like below:
the_chrome_options = Selenium::WebDriver::Chrome::Options.new;
the_chrome_options.add_argument("--user-data-dir=PATH_TO/Test User Data");
The above test script specifies the path to the browser profile (bolded), which will be used when a new Chrome browser is launched.
Note: everytime you run the test, you will need to remove the profile folder first, so a new profile is created and doesn’t rely on existing ones. This is the purpose of the
rm_rf
, followed bymkdir_p
.
$chrome_user_data_dir = "/Users/me/work/projects/testwisely/ui-tests/tmp/chrome-user-data-dir"# remove existing profile
FileUtils.rm_rf($chrome_user_data_dir) if Dir.exists? ($chrome_user_data_dir)
FileUtils.mkdir_p($chrome_user_data_dir)@driver = Selenium::WebDriver.for(browser_type,
browser_options(:user_data_dir => $chrome_user_data_dir))
driver.get(site_url)
browser_options
is a convenient function defined in the test_helper.rb
. The below adds a path to a profile to Chrome options to use the specified profile.
if opts[:user_data_dir] && Dir.exists?(opts[:user_data_dir])
the_chrome_options.add_argument("--user-data-dir=#{opts[:user_data_dir]}")
end
However, the first time the profile starts up, it will have two tabs.
Because Chrome starts a new empty profile, it assumes you are using it for the first time. But we don’t want that in automation. So, close the browser and start it again.
@driver = $driver = Selenium::WebDriver.for(browser_type,
browser_options(:user_data_dir => $chrome_user_data_dir))
sleep 1
@driver.quit
# then launch a new ChromeDriver instance again
4. Tidy up and complete script
Before we finish, we should tidy up the $chrome_user_data_dir
.
Previously, we used the absolute path to specify the location, but it is better to use a relative path to ensure the test runs OK on a different machine.
Here, I’ve kept it in the tmp
folder (same as the absolute path example above) but now uses a relative path.
File.expand_path File.join(File.dirname(__FILE__),
"../tmp/chrome-user-data-dir")
Also, within the profile directory, Chrome will create many subfolders. Remember to add tmp
to your.gitignore
to avoid accidentally committing it. If you can exclude it from your testing IDE (such as TestWise), I recommend doing so.
5. The Complete Script
(for the whole test project structure, including test_helper.rb, get it here).
load File.dirname(__FILE__) + "/../test_helper.rb"
describe "Sign in remember me" do
include TestHelper
before(:all) do
$chrome_user_data_dir = File.expand_path File.join(File.dirname(__FILE__), "../tmp/chrome-user-data-dir")
FileUtils.rm_rf($chrome_user_data_dir) if Dir.exists?($chrome_user_data_dir)
FileUtils.mkdir_p($chrome_user_data_dir)
@driver = $driver = Selenium::WebDriver.for(browser_type,
browser_options(:user_data_dir => $chrome_user_data_dir))
sleep 1
@driver.quit # this is to create chrome profile data, otherwise, will start a new tab "What's New"
@driver = $driver = Selenium::WebDriver.for(browser_type,
browser_options(:user_data_dir => $chrome_user_data_dir))
driver.get(site_url)
reset
end
before(:each) do
visit("/sign-in")
end
after(:all) do
FileUtils.rm_rf($chrome_user_data_dir) if Dir.exists?($chrome_user_data_dir)
driver.quit unless debugging?
end
# Selenium starts a new profile so cookie is no longer valid.
it "Sign in automativcally from the remember me cookie" do
sign_in("pro", "test01", :remember_me => true)
# verify the cookie
remember_token_cookie =
driver.manage.cookie_named("remember_token")
expect(remember_token_cookie[:value].size).to eq(22)
driver.quit
sleep 1
# if we don't specify user data dir,
# the cookie saved in previous browser session won't be valid
@driver = Selenium::WebDriver.for(browser_type,
browser_options(:user_data_dir => $chrome_user_data_dir))
visit("/dashboard")
expect(page_text).not_to include("Please log in")
expect(page_text).to include("Dashboard")
visit("/sign-out") # shall clear cookie
visit("/dashboard")
expect(page_text).to include("Please log in")
end
Related reading