If you've ever used Selenium, and if you're currently using Appium for web testing, you might have wondered if Appium supports interacting with cookies stored in the browser. It does! And to explore how and why we might want to work with cookies, we're going to travel back in time to around 2006, when I was working as a freelance web developer. I had a side project called Expenseus, a useful little app designed to help keep track of shared expenses among a group of friends. Here's what it still looks like today:
Don't laugh! It wasn't pretty then and it certainly hasn't aged well, but it is still running after 13 years without any updates (please do not try and hack it). Above is an image of the login page. To build this app, for some reason I decided to write a more or less complete clone of Ruby on Rails in PHP (don't ask me why--I loved PHP that much, I guess!) As part of this whole framework, I built a cookie-based login system. The way this worked was that, on a visit to the site, the app would generate a unique session id for a visitor, and set that id in the PHPSESSID cookie. From then on, requests to the app would contain this unique id in the header. The server could then associate various bits of state with the user across requests, for example, whether a user is logged in, or whether the user just took an action which should result in a message being shown on the next page.
This is a very common pattern for cookie use. Even though cookies can store arbitrary data, they're usually just used to store a session token or id, and that is associated with state kept on the server in something like Memcache, or a database.
Using Cookies for Testing
- Navigate to the app's URL
- If we don't have a login cookie stored in our test class:
- Navigate to the login page and log in by filling out fields and clicking buttons
- Retrieve the session id from the login cookie and save it on our test class
- Go to main step 4
- If we have a login cookie stored from a previous test:
- Delete the current cookie
- Set a new login cookie with the saved cookie information
- Proceed with the rest of the test, in a logged-in state.
The Cookie API
In the flow above, we need to interact with the cookies in three ways: getting cookie data, deleting a cookie, and adding a new cookie. The Appium / Selenium API has methods for all of these. Here's how we would get a cookie with the name PHPSESSID:
The Cookie class gives us methods that allow us to retrieve the name, value, expiry, domain, and other metadata of the cookie. Here's how we would delete a cookie with the same name:
And finally, here's how we set a new cookie, assuming we have a Cookie instance called loginCookie (maybe the same object we got back as the result of the call above?) all ready to go:
Putting it all together, we can define a test helper method that will log a user in, either by automating the fields and buttons, or by setting a cookie if one exists in the static loginCookie class field:
(In the code above, I've assumed some things about my app, for example the login url, the relevant locators, or the fact that the site takes me to the dashboard upon login.)
You can check out a full working example of the technique above, where a test is run first on Safari on iOS, and then on Chrome on Android, where the Chrome test just uses the cookie retrieved from the Safari test, rather than having to go through all the login steps itself. It feels pretty magical to see it in action, until you remember that HTTP is totally stateless, so there's really no difference between two requests from one browser or two requests from two different browsers!