summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Davison <ddavison@gitlab.com>2019-07-17 19:30:01 +0000
committerDan Davison <ddavison@gitlab.com>2019-07-17 19:30:01 +0000
commit78f461bbab6e0ee51472dba63f705bfed061f869 (patch)
tree19211a1cb62d80793d878e99c22407a213a6cb73
parentb921b2d1fb0c1cb3e6d4f3c88806855b48827855 (diff)
parenta7e16ee20893bbc7f31fb0eb3cdd3018ace9acda (diff)
downloadgitlab-ce-78f461bbab6e0ee51472dba63f705bfed061f869.tar.gz
Merge branch 'docs-quality-data-qa-selector' into 'master'
Add documentation surrounding [data-qa-selector] See merge request gitlab-org/gitlab-ce!30690
-rw-r--r--doc/development/testing_guide/end_to_end/page_objects.md38
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md33
2 files changed, 45 insertions, 26 deletions
diff --git a/doc/development/testing_guide/end_to_end/page_objects.md b/doc/development/testing_guide/end_to_end/page_objects.md
index 05cb03eb4bd..29ad49403fe 100644
--- a/doc/development/testing_guide/end_to_end/page_objects.md
+++ b/doc/development/testing_guide/end_to_end/page_objects.md
@@ -92,20 +92,25 @@ end
The `view` DSL method will correspond to the rails View, partial, or vue component that renders the elements.
The `element` DSL method in turn declares an element for which a corresponding
-`qa-element-name-dasherized` CSS class will need to be added to the view file.
+`data-qa-selector=element_name_snaked` data attribute will need to be added to the view file.
You can also define a value (String or Regexp) to match to the actual view
code but **this is deprecated** in favor of the above method for two reasons:
- Consistency: there is only one way to define an element
-- Separation of concerns: QA uses dedicated CSS classes instead of reusing code
+- Separation of concerns: QA uses dedicated `data-qa-*` attributes instead of reusing code
or classes used by other components (e.g. `js-*` classes etc.)
```ruby
view 'app/views/my/view.html.haml' do
- # Implicitly require `.qa-logout-button` CSS class to be present in the view
+
+ ### Good ###
+
+ # Implicitly require the CSS selector `[data-qa-selector="logout_button"]` to be present in the view
element :logout_button
+ ### Bad ###
+
## This is deprecated and forbidden by the `QA/ElementWithPattern` RuboCop cop.
# Require `f.submit "Sign in"` to be present in `my/view.html.haml
element :my_button, 'f.submit "Sign in"' # rubocop:disable QA/ElementWithPattern
@@ -129,24 +134,39 @@ view 'app/views/my/view.html.haml' do
end
```
-To add these elements to the view, you must change the rails View, partial, or vue component by adding a `qa-element-descriptor` class
+To add these elements to the view, you must change the rails View, partial, or vue component by adding a `data-qa-selector` attribute
for each element defined.
-In our case, `qa-login-field`, `qa-password-field` and `qa-sign-in-button`
+In our case, `data-qa-selector="login_field"`, `data-qa-selector="password_field"` and `data-qa-selector="sign_in_button"`
**app/views/my/view.html.haml**
```haml
-= f.text_field :login, class: "form-control top qa-login-field", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
-= f.password_field :password, class: "form-control bottom qa-password-field", required: true, title: "This field is required."
-= f.submit "Sign in", class: "btn btn-success qa-sign-in-button"
+= f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required.", data: { qa_selector: 'login_field' }
+= f.password_field :password, class: "form-control bottom", required: true, title: "This field is required.", data: { qa_selector: 'password_field' }
+= f.submit "Sign in", class: "btn btn-success", data: { qa_selector: 'sign_in_button' }
```
Things to note:
-- The CSS class must be `kebab-cased` (separated with hyphens "`-`")
+- The name of the element and the qa_selector must match and be snake_cased
- If the element appears on the page unconditionally, add `required: true` to the element. See
[Dynamic element validation](dynamic_element_validation.md)
+- You may see `.qa-selector` classes in existing Page Objects. We should prefer the [`data-qa-selector`](#data-qa-selector-vs-qa-selector)
+ method of definition over the `.qa-selector` CSS class
+
+
+### `data-qa-selector` vs `.qa-selector`
+
+> Introduced in GitLab 12.1
+
+There are two supported methods of defining elements within a view.
+
+1. `data-qa-selector` attribute
+1. `.qa-selector` class
+
+Any existing `.qa-selector` class should be considered deprecated
+and we should prefer the `data-qa-selector` method of definition.
## Running the test locally
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index efcfd44bc22..3bbf8feab39 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -101,7 +101,7 @@ it 'replaces an existing label if it has the same key' do
page.find('#content-body').click
page.refresh
- labels_block = page.find('.qa-labels-block')
+ labels_block = page.find(%q([data-qa-selector="labels_block"]))
expect(labels_block).to have_content('animal::dolphin')
expect(labels_block).not_to have_content('animal::fox')
@@ -130,7 +130,7 @@ it 'keeps both scoped labels when adding a label with a different key' do
page.find('#content-body').click
page.refresh
- labels_block = page.find('.qa-labels-block')
+ labels_block = page.find(%q([data-qa-selector="labels_block"]))
expect(labels_block).to have_content('animal::fox')
expect(labels_block).to have_content('plant::orchid')
@@ -139,7 +139,7 @@ it 'keeps both scoped labels when adding a label with a different key' do
end
```
-> Note that elements are always located using CSS selectors, and a good practice is to add test-specific selectors (this is called adding testability to the application and we will talk more about it later.) For example, the `labels_block` element uses the selector `.qa-labels-block`, which was added specifically for testing purposes.
+> Note that elements are always located using CSS selectors, and a good practice is to add test-specific selectors (this is called "testability"). For example, the `labels_block` element uses the CSS selector [`data-qa-selector="labels_block"`](page_objects.md#data-qa-selector-vs-qa-selector), which was added specifically for testing purposes.
Below are the steps that the test covers:
@@ -168,7 +168,7 @@ end
it 'replaces an existing label if it has the same key' do
select_label_and_refresh @new_label_same_scope
- labels_block = page.find('.qa-labels-block')
+ labels_block = page.find(%q([data-qa-selector="labels_block"]))
expect(labels_block).to have_content(@new_label_same_scope)
expect(labels_block).not_to have_content(@initial_label)
@@ -179,7 +179,7 @@ end
it 'keeps both scoped label when adding a label with a different key' do
select_label_and_refresh @new_label_different_scope
- labels_block = page.find('.qa-labels-block')
+ labels_block = page.find(%q([data-qa-selector="labels_block"]))
expect(labels_blocks).to have_content(@new_label_different_scope)
expect(labels_blocks).to have_content(@initial_label)
@@ -305,7 +305,7 @@ module QA
it 'correctly applies scoped labels depending on if they are from the same or a different scope' do
select_labels_and_refresh [@new_label_same_scope, @new_label_different_scope]
- labels_block = page.all('.qa-labels-block')
+ labels_block = page.all(%q([data-qa-selector="labels_block"]))
expect(labels_block).to have_content(@new_label_same_scope)
expect(labels_block).to have_content(@new_label_different_scope)
@@ -552,37 +552,36 @@ The `text_of_labels_block` method is a simple method that returns the `:labels_b
#### Updates in the view (*.html.haml) and `dropdowns_helper.rb` files
-Now let's change the view and the `dropdowns_helper` files to add the selectors that relate to the Page Object.
+Now let's change the view and the `dropdowns_helper` files to add the selectors that relate to the [Page Objects].
-In the [app/views/shared/issuable/_sidebar.html.haml](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/app/views/shared/issuable/_sidebar.html.haml) file, on [line 105 ](https://gitlab.com/gitlab-org/gitlab-ee/blob/84043fa72ca7f83ae9cde48ad670e6d5d16501a3/app/views/shared/issuable/_sidebar.html.haml#L105), add an extra class `qa-edit-link-labels`.
+In [`app/views/shared/issuable/_sidebar.html.haml:105`](https://gitlab.com/gitlab-org/gitlab-ee/blob/7ca12defc7a965987b162a6ebef302f95dc8867f/app/views/shared/issuable/_sidebar.html.haml#L105), add a `data: { qa_selector: 'edit_link_labels' }` data attribute.
The code should look like this:
```haml
-= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right qa-edit-link-labels'
+= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: 'edit_link_labels' }
```
-In the same file, on [line 121](https://gitlab.com/gitlab-org/gitlab-ee/blob/84043fa72ca7f83ae9cde48ad670e6d5d16501a3/app/views/shared/issuable/_sidebar.html.haml#L121), add an extra class `.qa-dropdown-menu-labels`.
+In the same file, on [line 121](https://gitlab.com/gitlab-org/gitlab-ee/blob/7ca12defc7a965987b162a6ebef302f95dc8867f/app/views/shared/issuable/_sidebar.html.haml#L121), add a `data: { qa_selector: 'dropdown_menu_labels' }` data attribute.
The code should look like this:
```haml
-.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable.qa-dropdown-menu-labels
+.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable.dropdown-extended-height{ data: { qa_selector: 'dropdown_menu_labels' } }
```
-In the [`dropdowns_helper.rb`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/app/helpers/dropdowns_helper.rb) file, on [line 94](https://gitlab.com/gitlab-org/gitlab-ee/blob/99e51a374f2c20bee0989cac802e4b5621f72714/app/helpers/dropdowns_helper.rb#L94), add an extra class `qa-dropdown-input-field`.
+In [`app/helpers/dropdowns_helper.rb:94`](https://gitlab.com/gitlab-org/gitlab-ee/blob/7ca12defc7a965987b162a6ebef302f95dc8867f/app/helpers/dropdowns_helper.rb#L94), add a `data: { qa_selector: 'dropdown_input_field' }` data attribute.
The code should look like this:
```ruby
-filter_output = search_field_tag search_id, nil, class: "dropdown-input-field qa-dropdown-input-field", placeholder: placeholder, autocomplete: 'off'
+filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder, autocomplete: 'off', data: { qa_selector: 'dropdown_input_field' }
```
-> Classes starting with `qa-` are used for testing purposes only, and by defining such classes in the elements we add **testability** in the application.
+> `data-qa-*` data attributes and CSS classes starting with `qa-` are used solely for the purpose of QA and testing.
+> By defining these, we add **testability** to the application.
-> When defining a class like `qa-labels-block`, it is transformed into `:labels_block` for usage in the Page Objects. So, `qa-edit-link-labels` is transformed into `:edit_link_labels`, `qa-dropdown-menu-labels` is transformed into `:dropdown_menu_labels`, and `qa-dropdown-input-field` is transformed into `:dropdown_input_field`. Also, we use a [sanity test](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/qa/qa/page#how-did-we-solve-fragile-tests-problem) to check that defined elements have their respective `qa-` selectors in the specified views.
-
-> We did not define the `qa-labels-block` class in the `app/views/shared/issuable/_sidebar.html.haml` file because it was already there to be used.
+> When defining a data attribute like: `qa_selector: 'labels_block'`, it should match the element definition: `element :labels_block`. We use a [sanity test](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/qa/qa/page#how-did-we-solve-fragile-tests-problem) to check that defined elements have their respective selectors in the specified views.
#### Updates in the `QA::Page::Base` class