Manual:Coding conventions/Selenium-Ruby

Since I pair with people from different teams and I work on the mediawiki-selenium gem I tend to see a lot of Ruby, Selenium, Cucumber and page-object code. I have noticed some code that I like and some code that I do not like.

To move the code towards what I like, I have been working on this page. I plan to implement the changes myself, if nobody does it before I have the time to do it. I do not have a timeline for that.

I would really appreciate if you would read the page (it should take you 5 minutes or so) and let me know if you agree or disagree with my thoughts, if I missed something, if something needs to be explained, if the page should have more text and less code or vice versa...

You can let me know in the page discussion section, at QA mailing list, at #wikimedia-qa freenode IRC channel (I am zeljkof there). Also, feel free to update the page.

This page describes coding conventions used by Cucumber test files in MediaWiki codebase. For the list of repositories that contain the files see links section of mediawiki-selenium readme file. There are three types of files, Cucumber features files, Cucumber step definition files and page object files.

Whitespace
Selenium tests should use the same whitespace convention (tabs, spaces...) that the repository already uses. That makes it easy for developers to work on tests. This convention is currently used in most places.

tests/browser
If possible, Selenium tests should be located in  folder. This convention is currently used in most places.

Cucumber feature files
For example file see any file in  folder of qa-browsertests repository. Feature files usually contain features and scenarios.

Scenarios

 * The scenarios are supposed to be as human-readable as possible. Do not turn them into a programming language - they are supposed to be a communication tool between users, product managers, testers and developers.
 * Avoid mentioning implementation details in the scenarios.

Alphabetically sorted
If a feature or scenario has more than one tag, they should be sorted alphabetically.

Example:

Required tags
Every feature in a feature file should have a site and browser specific tag. Scenarios inherit tags from the features they belong to, so if (for example) the entire feature runs on a specific browser, just the feature needs to be tagged, not scenarios.
 * Site specific tag is for example  or  . The tag specifies where the feature or scenario should run. This convention is currently used in most places.
 * A special case of site specific tag is . If the feature or scenario runs fine on a clean wiki, it should be tagged  . This convention is currently not used. At the moment we tag features or scenarios that are known to fail on a clean wiki with.
 * Browser specific tag is for example  or  . The tag specifies which browser should be used to run the feature or scenario. This convention is currently not used. At the moment we tag features or scenarios if they are known to fail with specific browser, for example.

Optional tags
Some features or scenarios can have an optional tag.
 * If the feature or scenario requires the user to log in, it should have  tag. This convention is currently used in most places.
 * If the feature or scenario requires custom browser configuration, it should be tagged . This convention is currently not used. At the moment we tag features or scenarios that need custom browser configuration with   tag in UniversalLanguageSelector repository and with   tag in MobileFrontend repository.
 * We need to tag tests that are quick or slow to run. My suggestion is  and   tags.   tag could be used to create a Jenkins job that would run after every patch set submission to Gerrit, or every time a commit is merged into master branch.   tag could be used to create a Jenkins job that would run once a day. This convention is currently not used.

Ruby
Cucumber step definition files and page object files are Ruby code. In general we follow GitHub Ruby Styleguide. There are a few exceptions where we do not follow the styleguide.

Hashes
Use JSON style for Hash literals (introduced in Ruby 1.9) instead of the hashrocket syntax.

Example (good):

Example (bad):

Cucumber step definition files
For example file see any file in   folder of qa-browsertests repository. Step definition files usually contain,   and   steps.

Page object pattern
Direct calls to Selenium function are not supposed to be used. Use PageObject.

Simplicity
In general, code in step definition files should be as simple as possible. Ideally, just one or two lines per step. All complicated code should be moved to page objects. This convention is currently used in most places.

Example:

Grouped by type
Steps should be grouped by type. and  steps should be grouped in one group,   steps should be grouped separately.

Example:

This convention is currently not used. At the moment we do not combine  and   steps in one group.

Alphabetically sorted
Inside a group, steps should be sorted alphabetically by step name. That moves steps with similar name close to each other. Steps with similar name usually have similar functionality, making them good candidates for merging. This convention is currently used in most places.

Example:

rspec-expectations
We are using rspec-expectations assertions in step definition files. We should use it's  syntax.

Example ( syntax):

This convention is currently not used. At the moment we are using old  syntax.

Example ( syntax):

Page object files
For example file see any file in   folder of qa-browsertests repository. Step definition files usually contain page URL, page elements and methods. All complicated functionality should be moved to methods.

URL
Page URL is optional. It is used in step definitions when a  or   step needs to go directly to a page, or when a   step needs to check page URL.

Example:

Page elements
Simple page elements should be defined using page-object Ruby gem API.

Example:

Elements that are complicated to find should pass blocks finding the elements to the page-object API.

Example:

Methods
If a page has complicated functionality, a method in its page class is usually the best place for it.

Example: