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