Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-29 03:09:38 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-29 03:09:38 +0300
commitac6a319712d345ab54d4eb5be1a0a4116823dd1e (patch)
treeadb0a00d5876d35635e7ba87a9f63bfa16e2ba44 /doc
parentabe11a6a2c04112d0b7d6d4facfd0c8370f51831 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc')
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt2
-rw-r--r--doc/administration/auth/ldap-troubleshooting.md4
-rw-r--r--doc/administration/raketasks/check.md2
-rw-r--r--doc/administration/raketasks/github_import.md2
-rw-r--r--doc/administration/raketasks/ldap.md4
-rw-r--r--doc/administration/raketasks/maintenance.md2
-rw-r--r--doc/administration/raketasks/praefect.md2
-rw-r--r--doc/administration/raketasks/storage.md2
-rw-r--r--doc/administration/raketasks/uploads/migrate.md2
-rw-r--r--doc/administration/raketasks/uploads/sanitize.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql10
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json12
-rw-r--r--doc/api/group_milestones.md69
-rw-r--r--doc/api/settings.md9
-rw-r--r--doc/development/documentation/styleguide.md2
-rw-r--r--doc/development/testing_guide/end_to_end/beginners_guide.md340
-rw-r--r--doc/development/testing_guide/end_to_end/img/gl-devops-lifecycle-by-stage-numbers_V12_10.pngbin0 -> 28571 bytes
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md621
-rw-r--r--doc/raketasks/README.md46
-rw-r--r--doc/raketasks/backup_restore.md6
-rw-r--r--doc/raketasks/cleanup.md8
-rw-r--r--doc/raketasks/features.md2
-rw-r--r--doc/raketasks/generate_sample_prometheus_data.md2
-rw-r--r--doc/raketasks/import.md2
-rw-r--r--doc/raketasks/list_repos.md2
-rw-r--r--doc/raketasks/user_management.md2
-rw-r--r--doc/raketasks/x509_signatures.md2
28 files changed, 462 insertions, 699 deletions
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index ca38db989f3..0e088cb26b8 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -237,6 +237,7 @@ Qualys
Rackspace
Raketask
Raketasks
+reachability
rebase
rebased
rebases
@@ -372,6 +373,7 @@ unstage
unstaged
unstages
unstaging
+untarred
untracked
untrusted
unverified
diff --git a/doc/administration/auth/ldap-troubleshooting.md b/doc/administration/auth/ldap-troubleshooting.md
index 612f782e841..77c9c30d140 100644
--- a/doc/administration/auth/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap-troubleshooting.md
@@ -312,7 +312,7 @@ things to check to debug the situation.
interval](ldap-ee.md#adjusting-ldap-group-sync-schedule) for the group to
sync. To speed up the process, either go to the GitLab group **Settings ->
Members** and press **Sync now** (sync one group) or [run the group sync Rake
- task](../raketasks/ldap.md#run-a-group-sync) (sync all groups).
+ task](../raketasks/ldap.md#run-a-group-sync-starter-only) (sync all groups).
If all of the above looks good, jump in to a little more advanced debugging in
the rails console.
@@ -352,7 +352,7 @@ GitLab syncs the `admin_group`.
NOTE: **NOTE:**
To sync all groups manually when debugging is unnecessary, [use the Rake
-task](../raketasks/ldap.md#run-a-group-sync) instead.
+task](../raketasks/ldap.md#run-a-group-sync-starter-only) instead.
The output from a manual [group sync](ldap-ee.md#group-sync) can show you what happens
when GitLab syncs its LDAP group memberships against LDAP.
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index fd869548fb4..da5caf3966f 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -1,4 +1,4 @@
-# Integrity check Rake task
+# Integrity check Rake task **(CORE ONLY)**
GitLab provides Rake tasks to check the integrity of various components.
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index 2c2046de564..83a3d2c8884 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -1,4 +1,4 @@
-# GitHub import
+# GitHub import **(CORE ONLY)**
> [Introduced]( https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10308) in GitLab 9.1.
diff --git a/doc/administration/raketasks/ldap.md b/doc/administration/raketasks/ldap.md
index ba08a41d92b..2871a9235a3 100644
--- a/doc/administration/raketasks/ldap.md
+++ b/doc/administration/raketasks/ldap.md
@@ -1,4 +1,4 @@
-# LDAP Rake tasks
+# LDAP Rake tasks **(CORE ONLY)**
The following are LDAP-related Rake tasks.
@@ -28,7 +28,7 @@ limit by passing a number to the check task:
rake gitlab:ldap:check[50]
```
-## Run a group sync
+## Run a group sync **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14735) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.2.
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 56d5d239d15..696bc23c916 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -1,4 +1,4 @@
-# Maintenance Rake tasks
+# Maintenance Rake tasks **(CORE ONLY)**
GitLab provides Rake tasks for general maintenance.
diff --git a/doc/administration/raketasks/praefect.md b/doc/administration/raketasks/praefect.md
index 4f9cf0e10ba..c3dadb6bc30 100644
--- a/doc/administration/raketasks/praefect.md
+++ b/doc/administration/raketasks/praefect.md
@@ -1,4 +1,4 @@
-# Praefect Rake Tasks
+# Praefect Rake Tasks **(CORE ONLY)**
> [Introduced]( https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28369) in GitLab 12.10.
diff --git a/doc/administration/raketasks/storage.md b/doc/administration/raketasks/storage.md
index 5d55b6cb9fe..44592260882 100644
--- a/doc/administration/raketasks/storage.md
+++ b/doc/administration/raketasks/storage.md
@@ -1,4 +1,4 @@
-# Repository storage Rake tasks
+# Repository storage Rake tasks **(CORE ONLY)**
This is a collection of Rake tasks you can use to help you list and migrate
existing projects and attachments associated with it from Legacy storage to
diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md
index e8ca70ef856..864486aa6d3 100644
--- a/doc/administration/raketasks/uploads/migrate.md
+++ b/doc/administration/raketasks/uploads/migrate.md
@@ -1,4 +1,4 @@
-# Uploads migrate Rake tasks
+# Uploads migrate Rake tasks **(CORE ONLY)**
`gitlab:uploads:migrate` migrates uploads between different storage types.
diff --git a/doc/administration/raketasks/uploads/sanitize.md b/doc/administration/raketasks/uploads/sanitize.md
index e3a8c62a167..7c760b95c33 100644
--- a/doc/administration/raketasks/uploads/sanitize.md
+++ b/doc/administration/raketasks/uploads/sanitize.md
@@ -1,4 +1,4 @@
-# Uploads sanitize Rake tasks
+# Uploads sanitize Rake tasks **(CORE ONLY)**
Since GitLab 11.9, EXIF data is automatically stripped from JPG or TIFF image uploads.
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 45af5da95f0..bfa75aaf1c3 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -4594,6 +4594,16 @@ enum IssueSort {
DUE_DATE_DESC
"""
+ Label priority by ascending order
+ """
+ LABEL_PRIORITY_ASC
+
+ """
+ Label priority by descending order
+ """
+ LABEL_PRIORITY_DESC
+
+ """
Priority by ascending order
"""
PRIORITY_ASC
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 94b2548a6af..4f221c9459e 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -13028,6 +13028,18 @@
"deprecationReason": null
},
{
+ "name": "LABEL_PRIORITY_ASC",
+ "description": "Label priority by ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "LABEL_PRIORITY_DESC",
+ "description": "Label priority by descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "DUE_DATE_ASC",
"description": "Due date by ascending order",
"isDeprecated": false,
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 024819ad37f..10445acf881 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -21,10 +21,10 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ------ | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `iids[]` | integer array | optional | Return only the milestones having the given `iid` |
-| `state` | string | optional | Return only `active` or `closed` milestones |
-| `title` | string | optional | Return only the milestones having the given `title` |
-| `search` | string | optional | Return only milestones with a title or description matching the provided string |
+| `iids[]` | integer array | no | Return only the milestones having the given `iid` |
+| `state` | string | no | Return only `active` or `closed` milestones |
+| `title` | string | no | Return only the milestones having the given `title` |
+| `search` | string | no | Return only milestones with a title or description matching the provided string |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/milestones
@@ -44,7 +44,8 @@ Example Response:
"start_date": "2013-11-10",
"state": "active",
"updated_at": "2013-10-02T09:24:18Z",
- "created_at": "2013-10-02T09:24:18Z"
+ "created_at": "2013-10-02T09:24:18Z",
+ "web_url": "https://gitlab.com/groups/gitlab-org/-/milestones/42"
}
]
```
@@ -59,8 +60,10 @@ GET /groups/:id/milestones/:milestone_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of the group milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of the group milestone |
## Create new milestone
@@ -72,11 +75,13 @@ POST /groups/:id/milestones
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `title` (required) - The title of a milestone
-- `description` (optional) - The description of the milestone
-- `due_date` (optional) - The due date of the milestone
-- `start_date` (optional) - The start date of the milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `title` | string | yes | The title of a milestone |
+| `description` | string | no | The description of the milestone |
+| `due_date` | date | no | The due date of the milestone, in YYYY-MM-DD format (ISO 8601) |
+| `start_date` | date | no | The start date of the milestone, in YYYY-MM-DD format (ISO 8601) |
## Edit milestone
@@ -88,13 +93,15 @@ PUT /groups/:id/milestones/:milestone_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of a group milestone
-- `title` (optional) - The title of a milestone
-- `description` (optional) - The description of a milestone
-- `due_date` (optional) - The due date of the milestone
-- `start_date` (optional) - The start date of the milestone
-- `state_event` (optional) - The state event of the milestone (close|activate)
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of a group milestone |
+| `title` | string | no | The title of a milestone |
+| `description` | string | no | The description of a milestone |
+| `due_date` | date | no | The due date of the milestone, in YYYY-MM-DD format (ISO 8601) |
+| `start_date` | date | no | The start date of the milestone, in YYYY-MM-DD format (ISO 8601) |
+| `state_event` | string | no | The state event of the milestone _(`close` or `activate`)_ |
## Delete group milestone
@@ -106,8 +113,10 @@ DELETE /groups/:id/milestones/:milestone_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of the group's milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of the group's milestone |
## Get all issues assigned to a single milestone
@@ -119,8 +128,10 @@ GET /groups/:id/milestones/:milestone_id/issues
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of a group milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of a group milestone |
## Get all merge requests assigned to a single milestone
@@ -132,8 +143,10 @@ GET /groups/:id/milestones/:milestone_id/merge_requests
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of a group milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of a group milestone |
## Get all burndown chart events for a single milestone **(STARTER)**
@@ -147,5 +160,7 @@ GET /groups/:id/milestones/:milestone_id/burndown_events
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
-- `milestone_id` (required) - The ID of a group milestone
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `milestone_id` | integer | yes | The ID of a group milestone |
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 2f184d72667..5e432c11b3d 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -70,7 +70,8 @@ Example response:
"asset_proxy_url": "https://assets.example.com",
"asset_proxy_whitelist": ["example.com", "*.example.com", "your-instance.com"],
"npm_package_requests_forwarding": true,
- "issues_create_limit": 300
+ "issues_create_limit": 300,
+ "raw_blob_request_limit": 300
}
```
@@ -158,7 +159,8 @@ Example response:
"allow_local_requests_from_web_hooks_and_services": true,
"allow_local_requests_from_system_hooks": false,
"npm_package_requests_forwarding": true,
- "issues_create_limit": 300
+ "issues_create_limit": 300,
+ "raw_blob_request_limit": 300
}
```
@@ -364,4 +366,5 @@ are listed in the descriptions of the relevant settings.
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
| `web_ide_clientside_preview_enabled` | boolean | no | Client side evaluation (allow live previews of JavaScript projects in the Web IDE using CodeSandbox client side evaluation). |
| `snippet_size_limit` | integer | no | Max snippet content size in **bytes**. Default: 52428800 Bytes (50MB).|
-| `issues_create_limit` | integer | no | Max number of issue creation requests allowed per minute per user.|
+| `issues_create_limit` | integer | no | Max number of issue creation requests per minute per user. Default: 300. To disable throttling set to 0.|
+| `raw_blob_request_limit` | integer | no | Max number of requests per minute for each raw path. Default: 300. To disable throttling set to 0.|
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 0c6028971d9..452da7cc85e 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -1221,7 +1221,7 @@ a helpful link back to how the feature was developed.
to the following should be added immediately below the heading as a blockquote:
- `> Introduced in GitLab 11.3.`.
-- Whenever possible, version text should have a link to the issue, merge request, or epic that introduced the feature.
+- Whenever possible, version text should have a link to the _completed_ issue, merge request, or epic that introduced the feature.
An issue is preferred over a merge request, and a merge request is preferred over an epic. For example:
- `> [Introduced](<link-to-issue>) in GitLab 11.3.`.
diff --git a/doc/development/testing_guide/end_to_end/beginners_guide.md b/doc/development/testing_guide/end_to_end/beginners_guide.md
new file mode 100644
index 00000000000..73960a2f74d
--- /dev/null
+++ b/doc/development/testing_guide/end_to_end/beginners_guide.md
@@ -0,0 +1,340 @@
+# Beginner's guide to writing end-to-end tests
+
+In this tutorial, you will learn about the creation of end-to-end (_e2e_) tests
+for [GitLab Community Edition](https://about.gitlab.com/install/?version=ce) and
+[GitLab Enterprise Edition](https://about.gitlab.com/install/).
+
+By the end of this tutorial, you will be able to:
+
+- Determine whether an end-to-end test is needed.
+- Understand the directory structure within `qa/`.
+- Write a basic end-to-end test that will validate login features.
+- Develop any missing [page object](page_objects.md) libraries.
+
+## Before you write a test
+
+Before you write tests, your
+[GitLab Development Kit (GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit)
+must be configured to run the specs. The end-to-end tests:
+
+- Are contained within the `qa/` directory.
+- Should be independent and
+ [idempotent](https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning).
+- Create [resources](resources.md) (such as project, issue, user) on an ad-hoc basis.
+- Test the UI and API interfaces, and use the API to efficiently set up the UI tests.
+
+TIP: **Tip:**
+For more information, see [End-to-end testing Best Practices](best_practices.md).
+
+## Determine if end-to-end tests are needed
+
+Check the code coverage of a specific feature before writing end-to-end tests,
+for both [GitLab Community Edition](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles)
+and [GitLab Enterprise Edition](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles) projects.
+Does sufficient test coverage exist at the unit, feature, or integration levels?
+If you answered *yes*, then you *don't* need an end-to-end test.
+
+For information about the distribution of tests per level in GitLab, see
+[Testing Levels](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md).
+
+- See the
+ [How to test at the correct level?](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md#how-to-test-at-the-correct-level)
+ section of the [Testing levels](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md) document.
+- Review how often the feature changes. Stable features that don't change very often
+ might not be worth covering with end-to-end tests if they are already covered
+ in lower level tests.
+- Finally, discuss the proposed test with the developer(s) involved in implementing
+ the feature and the lower-level tests.
+
+CAUTION: **Caution:**
+Check both [GitLab Community Edition](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles) and
+[GitLab Enterprise Edition](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles) coverage projects
+for previously-written tests for this feature. For analyzing the code coverage,
+you must understand which application files implement specific features.
+
+NOTE: **Note:**
+In this tutorial we're writing a login end-to-end test, even though it has been
+sufficiently covered by lower-level testing, because it's the first step for most
+end-to-end flows, and is easiest to understand.
+
+## Identify the DevOps stage
+
+The GitLab QA end-to-end tests are organized by the different
+[stages in the DevOps lifecycle](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/qa/qa/specs/features/browser_ui).
+Determine where the test should be placed by
+[stage](https://about.gitlab.com/handbook/product/categories/#devops-stages),
+determine which feature the test will belong to, and then place it in a subdirectory
+under the stage.
+
+![DevOps lifecycle by stages](img/gl-devops-lifecycle-by-stage-numbers_V12_10.png)
+
+NOTE: **Note:**
+If the test is Enterprise Edition only, the test will be created in the `features/ee`
+directory, but follow the same DevOps lifecycle format.
+
+## Create a skeleton test
+
+In the first part of this tutorial we will be testing login, which is owned by the
+Manage stage. Inside `qa/specs/features/browser_ui/1_manage/login`, create a
+file `basic_login_spec.rb`.
+
+### The outer `context` block
+
+Specs have an outer `context` indicating the DevOps stage.
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+
+ end
+end
+```
+
+### The `describe` block
+
+Inside of our outer `context`, describe the feature to test. In this case, `Login`.
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Login' do
+
+ end
+ end
+end
+```
+
+### The `it` blocks (examples)
+
+Every test suite contains at least one `it` block (example). A good way to start
+writing end-to-end tests is to write test case descriptions as `it` blocks:
+
+```ruby
+module QA
+ context 'Manage' do
+ describe 'Login' do
+ it 'can login' do
+
+ end
+
+ it 'can logout' do
+
+ end
+ end
+ end
+end
+```
+
+## Write the test
+
+An important question is "What do we test?" and even more importantly, "How do we test?"
+
+Begin by logging in.
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Login' do
+ it 'can login' do
+ Flow::Login.sign_in
+
+ end
+
+ it 'can logout' do
+ Flow::Login.sign_in
+
+ end
+ end
+ end
+end
+```
+
+After [running the spec](#run-the-spec), our test should login and end; then we
+should answer the question "What do we test?"
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Login' do
+ it 'can login' do
+ Flow::Login.sign_in
+
+ Page::Main::Menu.perform do |menu|
+ expect(menu).to be_signed_in
+ end
+ end
+
+ it 'can logout' do
+ Flow::Login.sign_in
+
+ Page::Main::Menu.perform do |menu|
+ menu.sign_out
+
+ expect(menu).not_to be_signed_in
+ end
+ end
+ end
+ end
+end
+```
+
+**What do we test?**
+
+1. Can we log in?
+1. Can we log out?
+
+**How do we test?**
+
+1. Check if the user avatar appears in the top navigation.
+1. Check if the user avatar *does not* appear in the top navigation.
+
+NOTE: **Note:**
+Behind the scenes, `be_signed_in` is a
+[predicate matcher](https://relishapp.com/rspec/rspec-expectations/v/3-8/docs/built-in-matchers/predicate-matchers)
+that [implements checking the user avatar](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/page/main/menu.rb#L74).
+
+## De-duplicate your code
+
+Refactor your test to use a `before` block for test setup, since it's duplicating
+a call to `sign_in`.
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Login' do
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'can login' do
+ Page::Main::Menu.perform do |menu|
+ expect(menu).to be_signed_in
+ end
+ end
+
+ it 'can logout' do
+ Page::Main::Menu.perform do |menu|
+ menu.sign_out
+
+ expect(menu).not_to be_signed_in
+ end
+ end
+ end
+ end
+end
+```
+
+The `before` block is essentially a `before(:each)` and is run before each example,
+ensuring we now log in at the beginning of each test.
+
+## Test setup using resources and page objects
+
+Next, let's test something other than Login. Let's test Issues, which are owned by the Plan
+stage, so [create a file](#identify-the-devops-stage) in
+`qa/specs/features/browser_ui/3_create/issues` called `issues_spec.rb`.
+
+```ruby
+# frozen_string_literal: true
+
+module QA
+ context 'Plan' do
+ describe 'Issues' do
+ let(:issue) do
+ Resource::Issue.fabricate_via_api! do |issue|
+ issue.title = 'My issue'
+ issue.description = 'This is an issue specific to this test'
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ issue.visit!
+ end
+
+ it 'can close an issue' do
+ Page::Project::Issue::Show.perform do |show|
+ show.click_close_issue_button
+
+ expect(show).to be_closed
+ end
+ end
+ end
+ end
+end
+```
+
+Note the following important points:
+
+- At the start of our example, we will be at the `page/issue/show.rb` [page](page_objects.md).
+- Our test fabricates only what it needs, when it needs it.
+- The issue is fabricated through the API to save time.
+- GitLab prefers `let()` over instance variables. See
+ [best practices](../best_practices.md#let-variables).
+- `be_closed` is not implemented in `page/project/issue/show.rb` yet, but will be
+ implemented in the next step.
+
+The issue is fabricated as a [Resource](resources.md), which is a GitLab entity
+you can create through the UI or API. Other examples include:
+
+- A [Merge Request](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/merge_request.rb).
+- A [User](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/user.rb).
+- A [Project](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/project.rb).
+- A [Group](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/resource/group.rb).
+
+## Write the page object
+
+A [Page Object](page_objects.md) is a class in our suite that represents a page
+within GitLab. The **Login** page would be one example. Since our page object for
+the **Issue Show** page already exists, add the `closed?` method.
+
+```ruby
+module Page::Project::Issue
+ class Show
+ view 'app/views/projects/issues/show.html.haml' do
+ element :closed_status_box
+ end
+
+ def closed?
+ has_element?(:closed_status_box)
+ end
+ end
+end
+```
+
+Next, define the element `closed_status_box` within your view, so your Page Object
+can see it.
+
+```haml
+-#=> app/views/projects/issues/show.html.haml
+.issuable-status-box.status-box.status-box-issue-closed{ ..., data: { qa_selector: 'closed_status_box' } }
+```
+
+## Run the spec
+
+Before running the spec, confirm:
+
+- The GDK is installed.
+- The GDK is running on port 3000 locally.
+- No additional [RSpec metadata tags](rspec_metadata_tests.md) have been applied.
+- Your working directory is `qa/` within your GDK GitLab installation.
+
+To run the spec, run the following command:
+
+```ruby
+bundle exec bin/qa Test::Instance::All http://localhost:3000 -- <test_file>
+```
+
+Where `<test_file>` is:
+
+- `qa/specs/features/browser_ui/1_manage/login/login_spec.rb` when running the Login example.
+- `qa/specs/features/browser_ui/2_plan/issues/issue_spec.rb` when running the Issue example.
diff --git a/doc/development/testing_guide/end_to_end/img/gl-devops-lifecycle-by-stage-numbers_V12_10.png b/doc/development/testing_guide/end_to_end/img/gl-devops-lifecycle-by-stage-numbers_V12_10.png
new file mode 100644
index 00000000000..d11305c3686
--- /dev/null
+++ b/doc/development/testing_guide/end_to_end/img/gl-devops-lifecycle-by-stage-numbers_V12_10.png
Binary files differ
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 443b7b06a24..e6a683e9148 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -180,7 +180,7 @@ instance-level scenarios](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/
Continued reading:
-- [Quick Start Guide](quick_start_guide.md)
+- [Beginner's Guide](beginners_guide.md)
- [Style Guide](style_guide.md)
- [Best Practices](best_practices.md)
- [Testing with feature flags](feature_flags.md)
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
deleted file mode 100644
index 0ae3f375284..00000000000
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ /dev/null
@@ -1,621 +0,0 @@
-# Writing end-to-end tests step-by-step
-
-In this tutorial, you will find different examples, and the steps involved, in the creation of end-to-end (_e2e_) tests for GitLab CE and GitLab EE, using GitLab QA.
-
-When referring to end-to-end tests in this document, this means testing a specific feature end-to-end such as:
-
-- A user logging in.
-- The creation of a project.
-- The management of labels.
-- Breaking down epics into sub-epics and issues.
-
-## Important information before we start writing tests
-
-It's important to understand that end-to-end tests of isolated features, such as the ones described in the above note, doesn't mean that everything needs to happen through the GUI.
-
-If you don't exactly understand what we mean by **not everything needs to happen through the GUI,** please make sure you've read the [best practices](best_practices.md) before moving on.
-
-## This document covers the following items
-
-- [0.](#0-are-end-to-end-tests-needed) Identifying if end-to-end tests are really needed
-- [1.](#1-identifying-the-devops-stage) Identifying the [DevOps stage](https://about.gitlab.com/stages-devops-lifecycle/) of the feature that you are going to cover with end-to-end tests
-- [2.](#2-test-skeleton) Creating the skeleton of the test file (`*_spec.rb`)
-- [3.](#3-test-cases-mvc) The [MVC](https://about.gitlab.com/handbook/values/#minimum-viable-change-mvc) of the test cases' logic
-- [4.](#4-extracting-duplicated-code) Extracting duplicated code into methods
-- [5.](#5-tests-pre-conditions-using-resources-and-page-objects) Tests' pre-conditions (`before :context` and `before`) using resources and [Page Objects](page_objects.md)
-- [6.](#6-optimization) Optimizing the test suite
-- [7.](#7-resources) Using and implementing resources
-- [8.](#8-page-objects) Moving element definitions and methods to [Page Objects](page_objects.md)
-
-### 0. Are end-to-end tests needed?
-
-At GitLab we respect the [test pyramid](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md), and so, we recommend you check the code coverage of a specific feature before writing end-to-end tests, for both [CE](https://gitlab-org.gitlab.io/gitlab-foss/coverage-ruby/#_AllFiles) and [EE](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/#_AllFiles) projects.
-
-Sometimes you may notice that there is already good coverage in lower test levels, and we can stay confident that if we break a feature, we will still have quick feedback about it, even without having end-to-end tests.
-
-> For analyzing the code coverage, you will also need to understand which application files implement specific functionalities.
-
-#### Some other guidelines are as follows
-
-- Take a look at the [How to test at the correct level?](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md#how-to-test-at-the-correct-level) section of the [Testing levels](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/testing_guide/testing_levels.md) document
-
-- Look into the frequency in which such a feature is changed (_Stable features that don't change very often might not be worth covering with end-to-end tests if they're already covered in lower levels_)
-
-- Finally, discuss with the developer(s) involved in developing the feature and the tests themselves, to get their feeling
-
-If after this analysis you still think that end-to-end tests are needed, keep reading.
-
-### 1. Identifying the DevOps stage
-
-The GitLab QA end-to-end tests are organized by the different [stages in the DevOps lifecycle](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/qa/qa/specs/features/browser_ui), and so, if you are creating tests for issue creation, for instance, you would locate the spec files under the `qa/qa/specs/features/browser_ui/2_plan/` directory since issue creation is part of the Plan stage.
-
- In another case of a test for listing merged merge requests (MRs), the test should go under the `qa/qa/specs/features/browser_ui/3_create/` directory since merge requests are a feature from the Create stage.
-
-> There may be sub-directories inside the stages directories, for different features. For example: `.../browser_ui/2_plan/ee_epics/` and `.../browser_ui/2_plan/issues/`.
-
-Now, let's say we want to create tests for the [scoped labels](https://about.gitlab.com/releases/2019/04/22/gitlab-11-10-released/#scoped-labels) feature, available on GitLab EE Premium (this feature is part of the Plan stage.)
-
-> Because these tests are for a feature available only on GitLab EE, we need to create them in the [EE repository](https://gitlab.com/gitlab-org/gitlab).
-
-Since [there is no specific directory for this feature](https://gitlab.com/gitlab-org/gitlab/tree/master/qa/qa/specs/features/browser_ui/2_plan), we should create a sub-directory for it.
-
-Under `.../browser_ui/2_plan/`, let's create a sub-directory called `ee_scoped_labels/`.
-
-> Notice that since this feature is only available for GitLab EE we prefix the sub-directory with `ee_`.
-
-### 2. Test skeleton
-
-Inside the newly created sub-directory, let's create a file describing the test suite (e.g. `editing_scoped_labels_spec.rb`.)
-
-#### The `context` and `describe` blocks
-
-Specs have an outer `context` that indicates the DevOps stage. The next level is the `describe` block, that briefly states the subject of the test suite. See the following example:
-
-```ruby
-module QA
- context 'Plan' do
- describe 'Editing scoped labels on issues' do
- end
- end
-end
-```
-
-#### The `it` blocks
-
-Every test suite is composed of at least one `it` block, and a good way to start writing end-to-end tests is by writing test cases descriptions as `it` blocks. These might help you to think of different test scenarios. Take a look at the following example:
-
-```ruby
-module QA
- context 'Plan' do
- describe 'Editing scoped labels on issues' do
- it 'replaces an existing label if it has the same key' do
- end
-
- it 'keeps both scoped labels when adding a label with a different key' do
- end
- end
- end
-end
-```
-
-### 3. Test cases MVC
-
-For the [MVC](https://about.gitlab.com/handbook/values/#minimum-viable-change-mvc) of our test cases, let's say that we already have the application in the state needed for the tests, and then let's focus on the logic of the test cases only.
-
-To evolve the test cases drafted on step 2, let's imagine that the user is already logged into a GitLab EE instance, they already have at least a Premium license in use, there is already a project created, there is already an issue opened in the project, the issue already has a scoped label (e.g. `animal::fox`), there are other scoped labels (for the same scope and for a different scope (e.g. `animal::dolphin` and `plant::orchid`), and finally, the user is already on the issue's page. Let's also suppose that for every test case the application is in a clean state, meaning that one test case won't affect another.
-
-> Note: there are different approaches to creating an application state for end-to-end tests. Some of them are very time consuming and subject to failures, such as when using the GUI for all the pre-conditions of the tests. On the other hand, other approaches are more efficient, such as using the public APIs. The latter is more efficient since it doesn't depend on the GUI. We won't focus on this part yet, but it's good to keep it in mind.
-
-Let's now focus on the first test case.
-
-```ruby
-it 'replaces an existing label if it has the same key' do
- # This implementation is only for tutorial purposes. We normally encapsulate elements in Page Objects (which we cover on section 8).
- page.find('.block.labels .edit-link').click
- page.find('.dropdown-menu-labels .dropdown-input-field').send_keys ['animal::dolphin', :enter]
- page.find('#content-body').click
- page.refresh
-
- 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')
- expect(page).to have_content('added animal::dolphin label and removed animal::fox')
-end
-```
-
-> Notice that the test itself is simple. The most challenging part is the creation of the application state, which will be covered later.
->
-> The exemplified test case's MVC is not enough for the change to be merged, but it helps to build up the test logic. The reason is that we do not want to use locators directly in the tests, and tests **must** use [Page Objects](page_objects.md) before they can be merged. This way we better separate the responsibilities, where the Page Objects encapsulate elements and methods that allow us to interact with pages, while the spec files describe the test cases in more business-related language.
-
-Below are the steps that the test covers:
-
-1. The test finds the 'Edit' link for the labels and clicks on it.
-1. Then it fills in the 'Assign labels' input field with the value 'animal::dolphin' and press enters.
-1. Then it clicks in the content body to apply the label and refreshes the page.
-1. Finally, the expectations check that the previous scoped label was removed and that the new one was added.
-
-Let's now see how the second test case would look.
-
-```ruby
-it 'keeps both scoped labels when adding a label with a different key' do
- # This implementation is only for tutorial purposes. We normally encapsulate elements in Page Objects (which we cover on section 8).
- page.find('.block.labels .edit-link').click
- page.find('.dropdown-menu-labels .dropdown-input-field').send_keys ['plant::orchid', :enter]
- page.find('#content-body').click
- page.refresh
-
- 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')
- expect(page).to have_content('added animal::fox')
- expect(page).to have_content('added plant::orchid')
-end
-```
-
-> 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:
-
-1. The test finds the 'Edit' link for the labels and clicks on it.
-1. Then it fills in the 'Assign labels' input field with the value 'plant::orchid' and press enters.
-1. Then it clicks in the content body to apply the label and refreshes the page.
-1. Finally, the expectations check that both scoped labels are present.
-
-> Similar to the previous test, this one is also very straightforward, but there is some code duplication. Let's address it.
-
-### 4. Extracting duplicated code
-
-If we refactor the tests created on step 3 we could come up with something like this:
-
-```ruby
-before do
- ...
-
- @initial_label = 'animal::fox'
- @new_label_same_scope = 'animal::dolphin'
- @new_label_different_scope = 'plant::orchid'
-
- ...
-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(%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)
- expect(page).to have_content("added #{@new_label_same_scope}")
- expect(page).to have_content("and removed #{@initial_label}")
-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(%q([data-qa-selector="labels_block"]))
-
- expect(labels_blocks).to have_content(@new_label_different_scope)
- expect(labels_blocks).to have_content(@initial_label)
- expect(page).to have_content("added #{@new_label_different_scope}")
- expect(page).to have_content("added #{@initial_label}")
-end
-
-def select_label_and_refresh(label)
- page.find('.block.labels .edit-link').click
- page.find('.dropdown-menu-labels .dropdown-input-field').send_keys [label, :enter]
- page.find('#content-body').click
- page.refresh
-end
-```
-
-First, we remove the duplication of strings by defining the global variables `@initial_label`, `@new_label_same_scope` and `@new_label_different_scope` in the `before` block, and by using them in the expectations.
-
-Then, by creating a reusable `select_label_and_refresh` method, we remove the code duplication of this action, and later we can move this method to a Page Object class that will be created for easier maintenance purposes.
-
-Notice that the reusable method is created at the bottom of the file. This helps readability,
-where reading the code should be similar to reading a newspaper:
-
-- High-level information is at the top, like the title and summary of the news.
-- Low level, or more specific information, is at the bottom.
-
-### 5. Tests' pre-conditions using resources and Page Objects
-
-In this section, we will address the previously mentioned subject of creating the application state for the tests, using the `before :context` and `before` blocks, together with resources and Page Objects.
-
-#### `before :context`
-
-A pre-condition for the entire test suite is defined in the `before :context` block.
-
-> For our test suite, due to the need of the tests being completely independent of each other, we won't use the `before :context` block. The `before :context` block would make the tests dependent on each other because the first test changes the label of the issue, and the second one depends on the `'animal::fox'` label being set.
-
-TIP: **Tip:** In case of a test suite with only one `it` block it's ok to use only the `before` block (see below) with all the test's pre-conditions.
-
-#### `before`
-
-As the pre-conditions for our test suite, the things that needs to happen before each test starts are:
-
-- The user logging in;
-- A premium license already being set;
-- A project being created with an issue and labels already set;
-- The issue page being opened with only one scoped label applied to it.
-
-> When running end-to-end tests as part of the GitLab's continuous integration process [a license is already set as an environment variable](https://gitlab.com/gitlab-org/gitlab/blob/1a60d926740db10e3b5724713285780a4f470531/qa/qa/ee/strategy.rb#L20). For running tests locally you can set up such license by following the document [what tests can be run?](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md), based on the [supported GitLab environment variables](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables).
-
-#### Implementation
-
-In the following code we will focus only on the test suite's pre-conditions:
-
-```ruby
-module QA
- context 'Plan' do
- describe 'Editing scoped labels on issues' do
- before do
- Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.perform(&:sign_in_using_credentials)
-
- @initial_label = 'animal::fox'
- @new_label_same_scope = 'animal::dolphin'
- @new_label_different_scope = 'plant::orchid'
-
- issue = Resource::Issue.fabricate_via_api! do |issue|
- issue.title = 'Issue to test the scoped labels'
- issue.labels = [@initial_label]
- end
-
- [@new_label_same_scope, @new_label_different_scope].each do |label|
- Resource::Label.fabricate_via_api! do |l|
- l.project = issue.project
- l.title = label
- end
- end
-
- issue.visit!
- end
-
- it 'replaces an existing label if it has the same key' do
- ...
- end
-
- it 'keeps both scoped labels when adding a label with a different key' do
- ...
- end
-
- def select_label_and_refresh(label)
- ...
- end
- end
- end
-end
-```
-
-In the `before` block we create all the application state needed for the tests to run. We do that by using the `Runtime::Browser.visit` method to go to the login page, by performing a `sign_in_using_credentials` from the `Login` Page Object, by fabricating resources via APIs (`issue`, and `Resource::Label`), and by using the `issue.visit!` to visit the issue page.
-
-> A project is created in the background by creating the `issue` resource.
->
-> When creating the [Resources](resources.md), notice that when calling the `fabricate_via_api` method, we pass some attribute:values, like `title`, and `labels` for the `issue` resource; and `project` and `title` for the `label` resource.
->
-> What's important to understand here is that by creating the application state mostly using the public APIs we save a lot of time in the test suite setup stage.
->
-> Soon we will cover the use of the already existing resources' methods and the creation of your own `fabricate_via_api` methods for resources where this is still not available, but first, let's optimize our implementation.
-
-### 6. Optimization
-
-As already mentioned in the [best practices](best_practices.md) document, end-to-end tests are very costly in terms of execution time, and it's our responsibility as software engineers to ensure that we optimize them as much as possible.
-
-> Note that end-to-end tests are slow to run and so they can have several actions and assertions in a single test, which helps us get feedback from the tests sooner. In comparison, unit tests are much faster to run and can exercise every little piece of the application in isolation, and so they usually have only one assertion per test.
-
-Some improvements that we could make in our test suite to optimize its time to run are:
-
-1. Having a single test case (an `it` block) that exercises both scenarios to avoid "wasting" time in the tests' pre-conditions, instead of having two different test cases.
-1. Making the selection of labels more performant by allowing for the selection of more than one label in the same reusable method.
-
-Let's look at a suggestion that addresses the above points, one by one:
-
-```ruby
-module QA
- context 'Plan' do
- describe 'Editing scoped labels on issues' do
- before do
- ...
- end
-
- 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(%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)
- expect(labels_block).not_to have_content(@initial_label)
- expect(page).to have_content("added #{@initial_label}")
- expect(page).to have_content("added #{@new_label_same_scope} #{@new_label_different_scope} labels and removed #{@initial_label}")
- end
-
- def select_labels_and_refresh(labels)
- find('.block.labels .edit-link').click
- labels.each do |label|
- find('.dropdown-menu-labels .dropdown-input-field').send_keys [label, :enter]
- end
- find('#content-body').click
- refresh
- end
- end
- end
- end
-```
-
-To address point 1, we changed the test implementation from two `it` blocks into a single one that exercises both scenarios. Now the new test description is: `'correctly applies the scoped labels depending if they are from the same or a different scope'`. It's a long description, but it describes well what the test does.
-
-> Notice that the implementation of the new and unique `it` block had to change a little bit. Below we describe in details what it does.
-
-1. It selects two scoped labels simultaneously, one from the same scope of the one already applied in the issue during the setup phase (in the `before` block), and another one from a different scope.
-1. It asserts that the correct labels are visible in the `labels_block`, and that the labels were correctly added and removed;
-1. Finally, the `select_label_and_refresh` method is changed to `select_labels_and_refresh`, which accepts an array of labels instead of a single label, and it iterates on them for faster label selection (this is what is used in step 1 explained above.)
-
-### 7. Resources
-
-**Note:** When writing this document, some code that is now merged to master was not implemented yet, but we left them here for the readers to understand the whole process of end-to-end test creation.
-
-You can think of [Resources](resources.md) as anything that can be created on GitLab CE or EE, either through the GUI, the API, or the CLI.
-
-With that in mind, resources can be a project, an epic, an issue, a label, a commit, etc.
-
-As you saw in the tests' pre-conditions and the optimization sections, we're already creating some of these resources. We are doing that by calling the `fabricate_via_api!` method.
-
-> We could be using the `fabricate!` method instead, which would use the `fabricate_via_api!` method if it exists, and fallback to GUI fabrication otherwise, but we recommend being explicit to make it clear what the test does. Also, we always recommend fabricating resources via API since this makes tests faster and more reliable.
-
-For our test suite example, the resources that we need to create don't have the necessary code for the `fabricate_via_api!` method to correctly work (e.g., the issue and label resources), so we will have to create them.
-
-#### Implementation
-
-In the following we describe the changes needed in each of the resource files mentioned above.
-
-**Issue resource**
-
-Now, let's make it possible to create an issue resource through the API.
-
-First, in the [issue resource](https://gitlab.com/gitlab-org/gitlab/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/issue.rb), let's expose its id and labels attributes.
-
-Add the following `attribute :id` and `attribute :labels` right above the [`attribute :title`](https://gitlab.com/gitlab-org/gitlab/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/issue.rb#L15).
-
-> This line is needed to allow for the issue fabrication, and for labels to be automatically added to the issue when fabricating it via API.
->
-> We add the attributes above the existing attribute to keep them alphabetically organized.
-
-Then, let's initialize an instance variable for labels to allow an empty array as default value when such information is not passed during the resource fabrication, since this optional. [Between the attributes and the `fabricate!` method](https://gitlab.com/gitlab-org/gitlab/blob/1a1f1408728f19b2aa15887cd20bddab7e70c8bd/qa/qa/resource/issue.rb#L18), add the following:
-
-```ruby
-def initialize
- @labels = []
-end
-```
-
-Next, add the following code right below the [`fabricate!`](https://gitlab.com/gitlab-org/gitlab/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/issue.rb#L27) method.
-
-```ruby
-def api_get_path
- "/projects/#{project.id}/issues/#{id}"
-end
-
-def api_post_path
- "/projects/#{project.id}/issues"
-end
-
-def api_post_body
- {
- labels: labels,
- title: title
- }
-end
-```
-
-By defining the `api_get_path` method, we allow the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to get a single issue.
-
-> This `GET` path can be found in the [public API documentation](../../../api/issues.md#single-issue).
-
-By defining the `api_post_path` method, we allow the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to create a new issue in a specific project.
-
-> This `POST` path can be found in the [public API documentation](../../../api/issues.md#new-issue).
-
-By defining the `api_post_body` method, we allow the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
-
-> Notice that we pass both `labels` and `title` attributes in the `api_post_body`, where `labels` receives an array of labels, and [`title` is required](../../../api/issues.md#new-issue). Also, notice that we keep them alphabetically organized.
-
-**Label resource**
-
-Finally, let's make it possible to create label resources through the API.
-
-Add the following code right below the [`fabricate!`](https://gitlab.com/gitlab-org/gitlab/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/label.rb#L36) method.
-
-```ruby
-def resource_web_url(resource)
- super
-rescue ResourceURLMissingError
- # this particular resource does not expose a web_url property
-end
-
-def api_get_path
- raise NotImplementedError, "The Labels API doesn't expose a single-resource endpoint so this method cannot be properly implemented."
-end
-
-def api_post_path
- "/projects/#{project.id}/labels"
-end
-
-def api_post_body
- {
- color: @color,
- name: @title
- }
-end
-```
-
-By defining the `resource_web_url(resource)` method, we override the one from the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb#L44) module. We do that to avoid failing the test due to this particular resource not exposing a `web_url` property.
-
-By defining the `api_get_path` method, we **would** allow for the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to get a single label, but since there's no path available for that in the public API, we raise a `NotImplementedError` instead.
-
-By defining the `api_post_path` method, we allow for the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to create a new label in a specific project.
-
-By defining the `api_post_body` method, we allow for the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
-
-> Notice that we pass both `color` and `name` attributes in the `api_post_body` since [those are required](../../../api/labels.md#create-a-new-label). Also, notice that we keep them alphabetically organized.
-
-### 8. Page Objects
-
-Page Objects are used in end-to-end tests for maintenance reasons, where a page's elements and methods are defined to be reused in any test.
-
-> Page Objects are auto-loaded in the [`qa/qa.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa.rb) file and available in all the test files (`*_spec.rb`).
-
-Take a look at the [Page Objects](page_objects.md) documentation.
-
-Now, let's go back to our example.
-
-As you may have noticed, we are defining elements with CSS selectors and the `select_labels_and_refresh` method directly in the test file, and this is an anti-pattern since we need to better separate the responsibilities.
-
-To address this issue, we will move the implementation to Page Objects, and the test suite will only focus on the business rules that we are testing.
-
-#### Updates in the test file
-
-As in a test-driven development approach, let's start changing the test file even before the Page Object implementation is in place.
-
-Replace the code of the `it` block in the test file by the following:
-
-```ruby
-module QA
- context 'Plan' do
- describe 'Editing scoped labels on issues' do
- before do
- ...
- end
-
- it 'correctly applies scoped labels depending on if they are from the same or a different scope' do
- Page::Project::Issue::Show.perform do |issue_page|
- issue_page.select_labels_and_refresh [@new_label_same_scope, @new_label_different_scope]
-
- expect(page).to have_content("added #{@initial_label}")
- expect(page).to have_content("added #{@new_label_same_scope} #{@new_label_different_scope} labels and removed #{@initial_label}")
- expect(issue_page.text_of_labels_block).to have_content(@new_label_same_scope)
- expect(issue_page.text_of_labels_block).to have_content(@new_label_different_scope)
- expect(issue_page.text_of_labels_block).not_to have_content(@initial_label)
- end
- end
- end
- end
-end
-```
-
-Notice that `select_labels_and_refresh` is now a method from the issue Page Object (which is not yet implemented), and that we verify the labels' text by using `text_of_labels_block`, instead of via the `labels_block` element. The `text_of_labels_block` method will also be implemented in the issue Page Object.
-
-Let's now update the Issue Page Object.
-
-#### Updates in the Issue Page Object
-
-> Page Objects are located in the `qa/qa/page/` directory, and its sub-directories.
-
-The file we will have to change is the [Issue Page Object](https://gitlab.com/gitlab-org/gitlab/blob/master/qa/qa/page/project/issue/show.rb).
-
-First, add the following code right below the definition of an already implemented view (keep in mind that view's definitions and their elements should be alphabetically ordered):
-
-```ruby
-view 'app/helpers/dropdowns_helper.rb' do
- element :dropdown_input_field
-end
-
-view 'app/views/shared/issuable/_sidebar.html.haml' do
- element :dropdown_menu_labels
- element :edit_link_labels
- element :labels_block
-end
-```
-
-Similarly to what we did before, let's first change the Page Object even without the elements being defined in the view (`_sidebar.html.haml`) and the `dropdowns_helper.rb` files, and later we will update them by adding the appropriate CSS selectors.
-
-Now, let's implement the methods `select_labels_and_refresh` and `text_of_labels_block`.
-
-Somewhere between the definition of the views and the private methods, add the following snippet of code (these should also be alphabetically ordered for organization reasons):
-
-```ruby
-def select_labels_and_refresh(labels)
- click_element(:edit_link_labels)
- labels.each do |label|
- within_element(:dropdown_menu_labels, text: label) do
- send_keys_to_element(:dropdown_input_field, [label, :enter])
- end
- end
- click_body
- labels.each do |label|
- has_element?(:labels_block, text: label)
- end
- refresh
-end
-
-def text_of_labels_block
- find_element(:labels_block)
-end
-```
-
-##### Details of `select_labels_and_refresh`
-
-Notice that we have not only moved the `select_labels_and_refresh` method, but we have also changed its implementation to:
-
-1. Click the `:edit_link_labels` element previously defined, instead of using `find('.block.labels .edit-link').click`
-1. Use `within_element(:dropdown_menu_labels, text: label)`, and inside of it, we call `send_keys_to_element(:dropdown_input_field, [label, :enter])`, which is a method that we will implement in the `QA::Page::Base` class to replace `find('.dropdown-menu-labels .dropdown-input-field').send_keys [label, :enter]`
-1. Use `click_body` after iterating on each label, instead of using `find('#content-body').click`
-1. Iterate on every label again, and then we use `has_element?(:labels_block, text: label)` after clicking the page body (which applies the labels), and before refreshing the page, to avoid test flakiness due to refreshing too fast.
-
-##### Details of `text_of_labels_block`
-
-The `text_of_labels_block` method is a simple method that returns the `:labels_block` element (`find_element(:labels_block)`).
-
-#### 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 Objects](page_objects.md).
-
-In [`app/views/shared/issuable/_sidebar.html.haml:105`](https://gitlab.com/gitlab-org/gitlab/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', data: { qa_selector: 'edit_link_labels' }
-```
-
-In the same file, on [line 121](https://gitlab.com/gitlab-org/gitlab/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.dropdown-extended-height{ data: { qa_selector: 'dropdown_menu_labels' } }
-```
-
-In [`app/helpers/dropdowns_helper.rb:94`](https://gitlab.com/gitlab-org/gitlab/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", placeholder: placeholder, autocomplete: 'off', data: { qa_selector: 'dropdown_input_field' }
-```
-
-> `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 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-foss/tree/master/doc/development/testing_guide/end_to_end/page_objects.md#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
-
-The last thing that we have to do is to update `QA::Page::Base` class to add the `send_keys_to_element` method on it.
-
-Add the following snippet of code somewhere where class methods are defined (remember to organize methods alphabetically, and if you see a place where this standard is not being followed, it would be helpful if you could rearrange it):
-
-```ruby
-def send_keys_to_element(name, keys)
- find_element(name).send_keys(keys)
-end
-```
-
-This method receives an element (`name`) and the `keys` that it will send to that element, and the keys are an array that can receive strings, or "special" keys, like `:enter`.
-
-As you might remember, in the Issue Page Object we call this method like this: `send_keys_to_element(:dropdown_input_field, [label, :enter])`.
-
-With that, you should be able to start writing end-to-end tests yourself. *Congratulations!*
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index c5723369470..3e048b399f9 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -15,26 +15,26 @@ GitLab Rake tasks are performed using:
The following are available Rake tasks:
-| Tasks | Description |
-|:-------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|
-| [Back up and restore](backup_restore.md) | Back up, restore, and migrate GitLab instances between servers. |
-| [Clean up](cleanup.md) | Clean up unneeded items from GitLab instances. |
-| [Development](../development/rake_tasks.md) | Tasks for GitLab contributors. |
-| [Elasticsearch](../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) | Maintain Elasticsearch in a GitLab instance. |
-| [Enable namespaces](features.md) | Enable usernames and namespaces for user projects. |
-| [General maintenance](../administration/raketasks/maintenance.md) | General maintenance and self-check tasks. |
-| [Geo maintenance](../administration/raketasks/geo.md) **(PREMIUM ONLY)** | [Geo](../administration/geo/replication/index.md)-related maintenance. |
-| [GitHub import](../administration/raketasks/github_import.md) | Retrieve and import repositories from GitHub. |
-| [Import repositories](import.md) | Import bare repositories into your GitLab instance. |
-| [Import large project exports](../development/import_project.md#importing-via-a-rake-task) | Import large GitLab [project exports](../user/project/settings/import_export.md). |
-| [Integrity checks](../administration/raketasks/check.md) | Check the integrity of repositories, files, and LDAP. |
-| [LDAP maintenance](../administration/raketasks/ldap.md) | [LDAP](../administration/auth/ldap.md)-related tasks. |
-| [List repositories](list_repos.md) | List of all GitLab-managed Git repositories on disk. |
-| [Project import/export](../administration/raketasks/project_import_export.md) | Prepare for [project exports and imports](../user/project/settings/import_export.md). |
-| [Sample Prometheus data](generate_sample_prometheus_data.md) | Generate sample Prometheus data. |
-| [Repository storage](../administration/raketasks/storage.md) | List and migrate existing projects and attachments from legacy storage to hashed storage. |
-| [Uploads migrate](../administration/raketasks/uploads/migrate.md) | Migrate uploads between storage local and object storage. |
-| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
-| [User management](user_management.md) | Perform user management tasks. |
-| [Webhooks administration](web_hooks.md) | Maintain project Webhooks. |
-| [X509 signatures](x509_signatures.md) | Update x509 commit signatures, useful if certificate store has changed. |
+| Tasks | Description |
+|:----------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------|
+| [Back up and restore](backup_restore.md) | Back up, restore, and migrate GitLab instances between servers. |
+| [Clean up](cleanup.md) | Clean up unneeded items from GitLab instances. |
+| [Development](../development/rake_tasks.md) | Tasks for GitLab contributors. |
+| [Elasticsearch](../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) **(STARTER ONLY)** | Maintain Elasticsearch in a GitLab instance. |
+| [Enable namespaces](features.md) | Enable usernames and namespaces for user projects. |
+| [General maintenance](../administration/raketasks/maintenance.md) | General maintenance and self-check tasks. |
+| [Geo maintenance](../administration/raketasks/geo.md) **(PREMIUM ONLY)** | [Geo](../administration/geo/replication/index.md)-related maintenance. |
+| [GitHub import](../administration/raketasks/github_import.md) | Retrieve and import repositories from GitHub. |
+| [Import repositories](import.md) | Import bare repositories into your GitLab instance. |
+| [Import large project exports](../development/import_project.md#importing-via-a-rake-task) | Import large GitLab [project exports](../user/project/settings/import_export.md). |
+| [Integrity checks](../administration/raketasks/check.md) | Check the integrity of repositories, files, and LDAP. |
+| [LDAP maintenance](../administration/raketasks/ldap.md) | [LDAP](../administration/auth/ldap.md)-related tasks. |
+| [List repositories](list_repos.md) | List of all GitLab-managed Git repositories on disk. |
+| [Project import/export](../administration/raketasks/project_import_export.md) | Prepare for [project exports and imports](../user/project/settings/import_export.md). |
+| [Sample Prometheus data](generate_sample_prometheus_data.md) | Generate sample Prometheus data. |
+| [Repository storage](../administration/raketasks/storage.md) | List and migrate existing projects and attachments from legacy storage to hashed storage. |
+| [Uploads migrate](../administration/raketasks/uploads/migrate.md) | Migrate uploads between storage local and object storage. |
+| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
+| [User management](user_management.md) | Perform user management tasks. |
+| [Webhooks administration](web_hooks.md) | Maintain project Webhooks. |
+| [X509 signatures](x509_signatures.md) | Update x509 commit signatures, useful if certificate store has changed. |
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 78a0933ea15..0d5f7e6fa49 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -1,4 +1,4 @@
-# Backing up and restoring GitLab
+# Backing up and restoring GitLab **(CORE ONLY)**
GitLab provides Rake tasks for backing up and restoring GitLab instances.
@@ -687,7 +687,7 @@ before restoring the backup.
You need to have a working GitLab installation before you can perform
a restore. This is mainly because the system user performing the
restore actions (`git`) is usually not allowed to create or delete
-the SQL database it needs to import data into ('gitlabhq_production').
+the SQL database it needs to import data into (`gitlabhq_production`).
All existing data will be either erased (SQL) or moved to a separate
directory (repositories, uploads).
@@ -713,7 +713,7 @@ more of the following options:
Read what the [backup timestamp is about](#backup-timestamp).
- `force=yes` - Does not ask if the authorized_keys file should get regenerated and assumes 'yes' for warning that database tables will be removed, enabling the "Write to authorized_keys file" setting, and updating LDAP providers.
-If you are restoring into directories that are mountpoints you will need to make
+If you are restoring into directories that are mount points, you will need to make
sure these directories are empty before attempting a restore. Otherwise GitLab
will attempt to move these directories before restoring the new data and this
would cause an error.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index ef69b1cce15..e40fa1a9ef1 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -1,4 +1,4 @@
-# Clean up
+# Clean up **(CORE ONLY)**
GitLab provides Rake tasks for cleaning up GitLab instances.
@@ -7,9 +7,11 @@ GitLab provides Rake tasks for cleaning up GitLab instances.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36628) in GitLab 12.10.
DANGER: **Danger:**
-Do not run this within 12 hours of a GitLab upgrade. This is to ensure that all background migrations have finished, which otherwise may lead to data loss.
+Do not run this within 12 hours of a GitLab upgrade. This is to ensure that all background migrations
+have finished, which otherwise may lead to data loss.
-When you remove LFS files from a repository's history, they become orphaned and continue to consume disk space. With this Rake task, you can remove invalid references from the database, which
+When you remove LFS files from a repository's history, they become orphaned and continue to consume
+disk space. With this Rake task, you can remove invalid references from the database, which
will allow garbage collection of LFS files.
For example:
diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md
index 6ee958049a7..1d68671a545 100644
--- a/doc/raketasks/features.md
+++ b/doc/raketasks/features.md
@@ -1,4 +1,4 @@
-# Namespaces
+# Namespaces **(CORE ONLY)**
This Rake task enables [namespaces](../user/group/index.md#namespaces) for projects.
diff --git a/doc/raketasks/generate_sample_prometheus_data.md b/doc/raketasks/generate_sample_prometheus_data.md
index 7c321c3ac75..902be6862c8 100644
--- a/doc/raketasks/generate_sample_prometheus_data.md
+++ b/doc/raketasks/generate_sample_prometheus_data.md
@@ -1,4 +1,4 @@
-# Generate sample Prometheus data
+# Generate sample Prometheus data **(CORE ONLY)**
This command will run Prometheus queries for each of the metrics of a specific environment
for a series of time intervals to now:
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index b6847dfbdb1..5229ce2ab08 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -1,4 +1,4 @@
-# Import bare repositories
+# Import bare repositories **(CORE ONLY)**
Rake tasks are available to import bare repositories into a GitLab instance.
diff --git a/doc/raketasks/list_repos.md b/doc/raketasks/list_repos.md
index 6437ff583ce..411de52e379 100644
--- a/doc/raketasks/list_repos.md
+++ b/doc/raketasks/list_repos.md
@@ -1,4 +1,4 @@
-# Listing repository directories
+# Listing repository directories **(CORE ONLY)**
You can print a list of all Git repositories on disk managed by GitLab.
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index 117240c20c4..61e30f9ddb1 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -1,4 +1,4 @@
-# User management
+# User management **(CORE ONLY)**
GitLab provides Rake tasks for user management.
diff --git a/doc/raketasks/x509_signatures.md b/doc/raketasks/x509_signatures.md
index 438e28361fa..ffc8f4f2a8f 100644
--- a/doc/raketasks/x509_signatures.md
+++ b/doc/raketasks/x509_signatures.md
@@ -1,4 +1,4 @@
-# X509 signatures
+# X509 signatures **(CORE ONLY)**
When [signing commits with x509](../user/project/repository/x509_signed_commits/index.md),
the trust anchor might change and the signatures stored within the database must be updated.