Testing web applications
I've recently been assigned to develop automated tests for our main web application. The idea is basically to speed up the process of accepting new releases and avoid allowing new features to break old ones.
Our first step was to build a minimum viable product, that is, a full working test that assumed the user would always take a straightforward path inputting only valid values.
We built it using Node.js and Puppeteer. It took us about a week and we learned quite a few lessons that we were able to use when building our testing tool.
Lessons from the MVP:
- The application used iframes in order to allow the user to use other applications and, as a matter of fact, most of the features were being used within an iframe.
- The main application uses angular as it's frontend and there is at least one bug that removes the main iframe from the interface, but that is known and is not going to be fixed soon.
- The application displayed in the iframe uses JSF framework and both JSF and Angular were generating ids dynamically.
The downside was that the company we hired to develop the tests wouldn't work with Puppeteer. The contract was in their side on this. If we wanted to share our test code with them, we would need to adopt their technology, that is Java and Selenium.
Recreating the MVP with Java
I actually enjoyed the fact that I now had to work with Java. It is a language I had never had much interest in ― not even when my brother and I decided to build Android apps (we chose Python with Kivy back than). Now that my main job was requiring me to work with Java I had the perfect opportunity and incentive to learn a new language.
Now I had a different situation. I had a deadline, a different language with a community that seems to be completely dependent on their IDEs of choice. I ended up installing several of them, enabling their Vim plugins. When I thought I was familiar enough I tried turning back to vim, but it turns out I wasn't familiar enough.
It took me a whole other week to rebuild the MVP with Java and I am pretty sure it is a much worse code.
Building the testing suite
Our first step to improve our test code was to create our own abstraction layer for Selenium.
We created simplified versions of the actions we commonly used and avoided invoking Selenium directly from the tests.
The idea was that we could use something like this in our code:
Browser b = new Browser(); Page p = new Page(); b.goTo(page.home); b.click(page.calendar.next()); b.click(page.calendar.day(3, 5));
Separating the script from the page description
It seemed reasonable from the start to separate the procedural section of the code from the page description section. The page description ought to be reused in several tests. At first we thought we would have some classes holding a bunch of CSS selectors that would be consumed by the tests. We called these page description classes Pages. The fact is that many selectors would be used a single time and moving them to the Page classes seemed to be a waste of time. So we tried to create these Pages a little smarter: they would be collection of components.
The components were basically collections of selectors and selector templates that could be reused within several tests in the same Page.
Let's consider a quick example: a calendar. A calendar would have a main selector, a selector for the next month and previous month, and a selector builder that would return the selector for a day.
The idea is that the test may invoke a method that would look like something like this:
Page p = new Page();