In this post we will take a look at a way to improve sample Rails 5.1.3 System Test using POROs, collaborators, delegation and modules.
STEP #0
Basic system test, before refactoring
it verifies three things:
If we can visit the index page and if it has the structure we expect
If we can create a new user and see it on the index user page
If we can update user information and see the changes on the index
user page
Step #1
In this step we’ll:
Introduce an abstract class that will help us describe page structure
and functionality
Add a page class to test show user page
Use new page class in a test
As a first step let’s introduce an abstract class with a single method that
will help us specify what elements we have on the page, actions from
this step can be found in the corresponding commit
Let’s take a closer look at initilaize method and instance variables
there:
@current_session - defaults to Capybara.current_session,
collaborator object that allows us use driver inside has_node method
@url - required parameter, URL of the page under test
@css_wrapper - defaults to an empty string, helpful when all elements
under test are within an element with particular CSS class
Now let’s introduce a new class that describes a show user page
You can see here three ways to identify an element on the page:
Let’s first compare Pages::User::Edit and Pages::User::New
they both have two same nodes first_name and last_name, which isn’t
strange - we render same partial form on both pages. Except for that
when testing these pages we fill out this form, let’s extract these two
pieces to a module.
Pages::Users::Partials::UserForm module
Pages after refactoring
Step #5
In This step we will:
Add ability to take screenshots to the page classes
Compare test we had before Step #1 and after Step #5
First item is quite straightforward, since we already have a test as a
collaborator in Pages::Base we only need to add take_screenshot to a
list of methods we delegate, you can find changes in the
corresponding commit
Now let’s compare what we had in the beginning
Before
and how the test looks now
After
after version has few advantages, they will be listed in a summary
section
Summary
Advantages of the OO approarch:
Tests are less brittle - if page structure/logic changes you will
need to change only corresponding page class
Tests are more readable - because of instance_eval blocks you
always know which page are you on
It’s much easier to define elements that exist on the page
Same functionality can be extracted
Other team members may use page classes in their tests
Pages are POROs, all the beauty/power of Ruby can be used there
I’m not happy with the fact that Pages::Base has include Rails.application.routes.url_helpers. This is done only to show that
if the page URL is static it can become a part of the page class, there
should be a better way to achieve it
has_node works only for a single element, would be cool to have has_nodes for collections. Once again page classes are POROs so
they may and should be changed to fit your needs
Folder with page classes may be a part of autoload paths, but not
everyone likes autoloading
Depending on a test framework delegated methods in Pages::Base will differ, but it can be used with other test frameworks (like RSpec) too
Instead of having multiple test there could be one test, you won’t
truncate database, you may have tests grouped by the user that is
logged in, additional data in the database may help you discover bugs
or make your hate your life :)