diff options
Diffstat (limited to 'qa/qa/page/README.md')
-rw-r--r-- | qa/qa/page/README.md | 134 |
1 files changed, 0 insertions, 134 deletions
diff --git a/qa/qa/page/README.md b/qa/qa/page/README.md deleted file mode 100644 index d0de33892c4..00000000000 --- a/qa/qa/page/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# Page objects in GitLab QA - -In GitLab QA we are using a known pattern, called _Page Objects_. - -This means that we have built an abstraction for all GitLab pages that we use -to drive GitLab QA scenarios. Whenever we do something on a page, like filling -in a form, or clicking a button, we do that only through a page object -associated with this area of GitLab. - -For example, when GitLab QA test harness signs in into GitLab, it needs to fill -in a user login and user password. In order to do that, we have a class, called -`Page::Main::Login` and `sign_in_using_credentials` methods, that is the only -piece of the code, that has knowledge about `user_login` and `user_password` -fields. - -## Why do we need that? - -We need page objects, because we need to reduce duplication and avoid problems -whenever someone changes some selectors in GitLab's source code. - -Imagine that we have a hundred specs in GitLab QA, and we need to sign into -GitLab each time, before we make assertions. Without a page object one would -need to rely on volatile helpers or invoke Capybara methods directly. Imagine -invoking `fill_in :user_login` in every `*_spec.rb` file / test example. - -When someone later changes `t.text_field :login` in the view associated with -this page to `t.text_field :username` it will generate a different field -identifier, what would effectively break all tests. - -Because we are using `Page::Main::Login.act { sign_in_using_credentials }` -everywhere, when we want to sign into GitLab, the page object is the single -source of truth, and we will need to update `fill_in :user_login` -to `fill_in :user_username` only in a one place. - -## What problems did we have in the past? - -We do not run QA tests for every commit, because of performance reasons, and -the time it would take to build packages and test everything. - -That is why when someone changes `t.text_field :login` to -`t.text_field :username` in the _new session_ view we won't know about this -change until our GitLab QA nightly pipeline fails, or until someone triggers -`package-and-qa` action in their merge request. - -Obviously such a change would break all tests. We call this problem a _fragile -tests problem_. - -In order to make GitLab QA more reliable and robust, we had to solve this -problem by introducing coupling between GitLab CE / EE views and GitLab QA. - -## How did we solve fragile tests problem? - -Currently, when you add a new `Page::Base` derived class, you will also need to -define all selectors that your page objects depends on. - -Whenever you push your code to CE / EE repository, `qa:selectors` sanity test -job is going to be run as a part of a CI pipeline. - -This test is going to validate all page objects that we have implemented in -`qa/page` directory. When it fails, you will be notified about missing -or invalid views / selectors definition. - -## How to properly implement a page object? - -We have built a DSL to define coupling between a page object and GitLab views -it is actually implemented by. See an example below. - -```ruby -module Page - module Main - class Login < Page::Base - view 'app/views/devise/passwords/edit.html.haml' do - element :password_field - element :password_confirmation - element :change_password_button - end - - view 'app/views/devise/sessions/_new_base.html.haml' do - element :login_field - element :password_field - element :sign_in_button - end - - # ... - end -end -``` - -The `view` DSL method declares the filename of the view where an -`element` is implemented. - -The `element` DSL method in turn declares an element for which a corresponding -`qa-element-name-dasherized` CSS class 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 - 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 - element :logout_button - - ## 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 - - ## This is deprecated and forbidden by the `QA/ElementWithPattern` RuboCop cop. - # Match every line in `my/view.html.haml` against - # `/link_to .* "My Profile"/` regexp. - element :profile_link, /link_to .* "My Profile"/ # rubocop:disable QA/ElementWithPattern -end -``` - -## Running the test locally - -During development, you can run the `qa:selectors` test by running - -```shell -bin/qa Test::Sanity::Selectors -``` - -from within the `qa` directory. - -## Where to ask for help? - -If you need more information, ask for help on `#quality` channel on Slack -(internal, GitLab Team only). - -If you are not a Team Member, and you still need help to contribute, please -open an issue in GitLab CE issue tracker with the `~QA` label. |