1---
2stage: none
3group: unassigned
4info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
5---
6
7# Style guide for writing end-to-end tests
8
9This document describes the conventions used at GitLab for writing End-to-end (E2E) tests using the GitLab QA project.
10
11## `click_` versus `go_to_`
12
13### When to use `click_`?
14
15When clicking in a single link to navigate, use `click_`.
16
17For example:
18
19```ruby
20def click_ci_cd_pipelines
21  within_sidebar do
22    click_element(:link_pipelines)
23  end
24end
25```
26
27From a testing perspective, if we want to check that clicking a link, or a button (a single interaction) is working as intended, we would want the test to read as:
28
29- Click a certain element
30- Verify the action took place
31
32### When to use `go_to_`?
33
34When interacting with multiple elements to go to a page, use `go_to_`.
35
36For example:
37
38```ruby
39def go_to_operations_environments
40  hover_operations do
41    within_submenu do
42      click_element(:operations_environments_link)
43    end
44  end
45end
46```
47
48`go_to_` fits the definition of interacting with multiple elements very well given it's more of a meta-navigation action that includes multiple interactions.
49
50Notice that in the above example, before clicking the `:operations_environments_link`, another element is hovered over.
51
52> We can create these methods as helpers to abstract multi-step navigation.
53
54## Element naming convention
55
56When adding new elements to a page, it's important that we have a uniform element naming convention.
57
58We follow a simple formula roughly based on Hungarian notation.
59
60*Formula*: `element :<descriptor>_<type>`
61
62- `descriptor`: The natural-language description of what the element is. On the login page, this could be `username`, or `password`.
63- `type`: A generic control on the page that can be seen by a user.
64  - `_button`
65  - `_checkbox`
66  - `_container`: an element that includes other elements, but doesn't present visible content itself. For example, an element that has a third-party editor inside it, but which isn't the editor itself and so doesn't include the editor's content.
67  - `_content`: any element that contains text, images, or any other content displayed to the user.
68  - `_dropdown`
69  - `_field`: a text input element.
70  - `_link`
71  - `_modal`: a popup modal dialog, for example, a confirmation prompt.
72  - `_placeholder`: a temporary element that appears while content is loading. For example, the elements that are displayed instead of discussions while the discussions are being fetched.
73  - `_radio`
74  - `_tab`
75  - `_menu_item`
76
77NOTE:
78If none of the listed types are suitable, please open a merge request to add an appropriate type to the list.
79
80### Examples
81
82**Good**
83
84```ruby
85view '...' do
86  element :edit_button
87  element :notes_tab
88  element :squash_checkbox
89  element :username_field
90  element :issue_title_content
91end
92```
93
94**Bad**
95
96```ruby
97view '...' do
98  # `_confirmation` should be `_field`. what sort of confirmation? a checkbox confirmation? no real way to disambiguate.
99  # an appropriate replacement would be `element :password_confirmation_field`
100  element :password_confirmation
101
102  # `clone_options` is too vague. If it's a dropdown menu, it should be `clone_dropdown`.
103  # If it's a checkbox, it should be `clone_checkbox`
104  element :clone_options
105
106  # how is this url being displayed? is it a textbox? a simple span?
107  # If it is content on the page, it should be `ssh_clone_url_content`
108  element :ssh_clone_url
109end
110```
111
112## Block argument naming
113
114To have a standard on what we call pages and resources when using the `.perform` method,
115we use the name of the page object in [snake_case](https://en.wikipedia.org/wiki/Snake_case)
116(all lowercase, with words separated by an underscore). See good and bad examples below.
117
118While we prefer to follow the standard in most cases, it is also acceptable to
119use common abbreviations (for example, `mr`) or other alternatives, as long as
120the name is not ambiguous. This can include appending `_page` if it helps to
121avoid confusion or make the code more readable. For example, if a page object is
122named `New`, it could be confusing to name the block argument `new` because that
123is used to instantiate objects, so `new_page` would be acceptable.
124
125We chose not to use `page` because that would shadow the
126Capybara DSL, potentially leading to confusion and bugs.
127
128### Examples
129
130**Good**
131
132```ruby
133Page::Project::Members.perform do |members|
134  members.do_something
135end
136```
137
138```ruby
139Resource::MergeRequest.fabricate! do |merge_request|
140  merge_request.do_something_else
141end
142```
143
144```ruby
145Resource::MergeRequest.fabricate! do |mr|
146  mr.do_something_else
147end
148```
149
150```ruby
151Page::Project::New.perform do |new_page|
152  new_page.do_something
153end
154```
155
156**Bad**
157
158```ruby
159Page::Project::Members.perform do |project_settings_members_page|
160  project_settings_members_page.do_something
161end
162```
163
164```ruby
165Page::Project::New.perform do |page|
166  page.do_something
167end
168```
169
170> Besides the advantage of having a standard in place, by following this standard we also write shorter lines of code.
171