Commit 1119b3d6 authored by Sanad Liaquat's avatar Sanad Liaquat

Merge branch 'qa-shl-protected-tags-e2e-spec' into 'master'

Add end-to-end test for repository tags

Closes gitlab-org/quality/testcases#804

See merge request gitlab-org/gitlab!34284
parents f7a6e048 d6d2a09b
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
- if project_nav_tab? :files - if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do = nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do
= link_to project_tree_path(@project), class: 'shortcuts-tree qa-project-menu-repo' do = link_to project_tree_path(@project), class: 'shortcuts-tree', data: { qa_selector: "repository_link" } do
.nav-icon-container .nav-icon-container
= sprite_icon('doc-text') = sprite_icon('doc-text')
%span.nav-item-name#js-onboarding-repo-link %span.nav-item-name#js-onboarding-repo-link
...@@ -58,11 +58,11 @@ ...@@ -58,11 +58,11 @@
= _('Commits') = _('Commits')
= nav_link(html_options: {class: branches_tab_class}) do = nav_link(html_options: {class: branches_tab_class}) do
= link_to project_branches_path(@project), class: 'qa-branches-link', id: 'js-onboarding-branches-link' do = link_to project_branches_path(@project), data: { qa_selector: "branches_link" }, id: 'js-onboarding-branches-link' do
= _('Branches') = _('Branches')
= nav_link(controller: [:tags]) do = nav_link(controller: [:tags]) do
= link_to project_tags_path(@project) do = link_to project_tags_path(@project), data: { qa_selector: "tags_link" } do
= _('Tags') = _('Tags')
= nav_link(path: 'graphs#show') do = nav_link(path: 'graphs#show') do
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
= dropdown_tag('Select', = dropdown_tag('Select',
options: { toggle_class: 'js-allowed-to-create wide', options: { toggle_class: 'js-allowed-to-create wide',
dropdown_class: 'dropdown-menu-selectable capitalize-header', dropdown_class: 'dropdown-menu-selectable capitalize-header',
data: { field_name: 'protected_tag[create_access_levels_attributes][0][access_level]', input_id: 'create_access_levels_attributes' }}) data: { field_name: 'protected_tag[create_access_levels_attributes][0][access_level]', input_id: 'create_access_levels_attributes', qa_selector: 'access_levels_dropdown' }})
= render 'projects/protected_tags/shared/create_protected_tag' = render 'projects/protected_tags/shared/create_protected_tag'
...@@ -25,4 +25,4 @@ ...@@ -25,4 +25,4 @@
= yield :create_access_levels = yield :create_access_levels
.card-footer .card-footer
= f.submit 'Protect', class: 'btn-success btn', disabled: true = f.submit 'Protect', class: 'btn-success btn', disabled: true, data: { qa_selector: 'protect_tag_button' }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
footer_content: true, footer_content: true,
data: { show_no: true, show_any: true, show_upcoming: true, data: { show_no: true, show_any: true, show_upcoming: true,
selected: params[:protected_tag_name], selected: params[:protected_tag_name],
project_id: @project.try(:id) } }) do project_id: @project.try(:id), qa_selector: 'tags_dropdown' } }) do
%ul.dropdown-footer-list %ul.dropdown-footer-list
%li %li
......
- expanded = expanded_by_default? - expanded = expanded_by_default?
%section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded) } %section.settings.no-animate#js-protected-tags-settings{ class: ('expanded' if expanded), data: { qa_selector: 'protected_tag_settings_content' } }
.settings-header .settings-header
%h4 %h4
Protected Tags Protected Tags
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
%li %li
= link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value) = link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value)
- if can?(current_user, :admin_tag, @project) - if can?(current_user, :admin_tag, @project)
= link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn' do = link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn', data: { qa_selector: "new_tag_button" } do
= s_('TagsPage|New tag') = s_('TagsPage|New tag')
= link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn d-none d-sm-inline-block has-tooltip' do = link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn d-none d-sm-inline-block has-tooltip' do
= icon("rss") = icon("rss")
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
.form-group.row .form-group.row
= label_tag :tag_name, nil, class: 'col-form-label col-sm-2' = label_tag :tag_name, nil, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control' = text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control', data: { qa_selector: "tag_name_field" }
.form-group.row .form-group.row
= label_tag :ref, 'Create from', class: 'col-form-label col-sm-2' = label_tag :ref, 'Create from', class: 'col-form-label col-sm-2'
.col-sm-10.create-from .col-sm-10.create-from
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
.form-group.row .form-group.row
= label_tag :message, nil, class: 'col-form-label col-sm-2' = label_tag :message, nil, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= text_area_tag :message, @message, required: false, class: 'form-control', rows: 5 = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5, data: { qa_selector: "tag_message_field" }
.form-text.text-muted .form-text.text-muted
= tag_description_help_text = tag_description_help_text
%hr %hr
...@@ -47,10 +47,10 @@ ...@@ -47,10 +47,10 @@
= s_('TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}').html_safe % replacements = s_('TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}').html_safe % replacements
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description = render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field'
= render 'shared/notes/hints' = render 'shared/notes/hints'
.form-actions .form-actions
= button_tag s_('TagsPage|Create tag'), class: 'btn btn-success' = button_tag s_('TagsPage|Create tag'), class: 'btn btn-success', data: { qa_selector: "create_tag_button" }
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel' = link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel'
-# haml-lint:disable InlineJavaScript -# haml-lint:disable InlineJavaScript
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe %script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.top-area.multi-line.flex-wrap .top-area.multi-line.flex-wrap
.nav-text .nav-text
.title .title
%span.item-title.ref-name %span.item-title.ref-name{ data: { qa_selector: 'tag_name_content' } }
= icon('tag') = icon('tag')
= @tag.name = @tag.name
- if protected_tag?(@project, @tag) - if protected_tag?(@project, @tag)
...@@ -56,12 +56,12 @@ ...@@ -56,12 +56,12 @@
%i.fa.fa-trash-o %i.fa.fa-trash-o
- if @tag.message.present? - if @tag.message.present?
%pre.wrap %pre.wrap{ data: { qa_selector: 'tag_message_content' } }
= strip_signature(@tag.message) = strip_signature(@tag.message)
.append-bottom-default.prepend-top-default .append-bottom-default.prepend-top-default
- if @release.description.present? - if @release.description.present?
.description.md .description.md{ data: { qa_selector: 'tag_release_notes_content' } }
= markdown_field(@release, :description) = markdown_field(@release, :description)
- else - else
= s_('TagsPage|This tag has no release notes.') = s_('TagsPage|This tag has no release notes.')
...@@ -14,6 +14,6 @@ ...@@ -14,6 +14,6 @@
supports_autocomplete: supports_autocomplete, supports_autocomplete: supports_autocomplete,
qa_selector: qa_selector } qa_selector: qa_selector }
- else - else
= text_area_tag attr, current_text, class: classes, placeholder: placeholder = text_area_tag attr, current_text, data: { qa_selector: qa_selector }, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave.gl-text-gray-700{ href: "#" } %a.zen-control.zen-control-leave.js-zen-leave.gl-text-gray-700{ href: "#" }
= sprite_icon('compress', size: 16) = sprite_icon('compress', size: 16)
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= dropdown_tag('Select', = dropdown_tag('Select',
options: { toggle_class: 'js-allowed-to-create js-multiselect wide', options: { toggle_class: 'js-allowed-to-create js-multiselect wide',
dropdown_class: 'dropdown-menu-user dropdown-menu-selectable capitalize-header', filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable capitalize-header', filter: true,
data: { input_id: 'create_access_levels_attributes', default_label: 'Select' } }) data: { input_id: 'create_access_levels_attributes', default_label: 'Select', qa_selector: 'access_levels_dropdown' } })
.form-text.text-muted .form-text.text-muted
Only groups that Only groups that
= link_to 'have this project shared', help_page_path('user/project/members/share_project_with_groups') = link_to 'have this project shared', help_page_path('user/project/members/share_project_with_groups')
......
...@@ -254,6 +254,12 @@ module QA ...@@ -254,6 +254,12 @@ module QA
autoload :Show, 'qa/page/project/pipeline/show' autoload :Show, 'qa/page/project/pipeline/show'
end end
module Tag
autoload :Index, 'qa/page/project/tag/index'
autoload :New, 'qa/page/project/tag/new'
autoload :Show, 'qa/page/project/tag/show'
end
module Job module Job
autoload :Show, 'qa/page/project/job/show' autoload :Show, 'qa/page/project/job/show'
end end
...@@ -273,6 +279,7 @@ module QA ...@@ -273,6 +279,7 @@ module QA
autoload :Runners, 'qa/page/project/settings/runners' autoload :Runners, 'qa/page/project/settings/runners'
autoload :MergeRequest, 'qa/page/project/settings/merge_request' autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories' autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
autoload :ProtectedTags, 'qa/page/project/settings/protected_tags'
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions' autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
module Services module Services
......
...@@ -118,6 +118,7 @@ module QA ...@@ -118,6 +118,7 @@ module QA
autoload :ProtectedBranches, 'qa/ee/page/project/settings/protected_branches' autoload :ProtectedBranches, 'qa/ee/page/project/settings/protected_branches'
autoload :Main, 'qa/ee/page/project/settings/main' autoload :Main, 'qa/ee/page/project/settings/main'
autoload :MirroringRepositories, 'qa/ee/page/project/settings/mirroring_repositories' autoload :MirroringRepositories, 'qa/ee/page/project/settings/mirroring_repositories'
autoload :ProtectedTags, 'qa/ee/page/project/settings/protected_tags'
autoload :MergeRequest, 'qa/ee/page/project/settings/merge_request' autoload :MergeRequest, 'qa/ee/page/project/settings/merge_request'
autoload :MergeRequestApprovals, 'qa/ee/page/project/settings/merge_request_approvals' autoload :MergeRequestApprovals, 'qa/ee/page/project/settings/merge_request_approvals'
autoload :Integrations, 'qa/ee/page/project/settings/integrations' autoload :Integrations, 'qa/ee/page/project/settings/integrations'
......
# frozen_string_literal: true
module QA
module EE
module Page
module Project
module Settings
module ProtectedTags
extend QA::Page::PageConcern
def self.prepended(base)
super
base.class_eval do
view 'ee/app/views/projects/protected_tags/ee/_create_protected_tag.html.haml' do
element :access_levels_dropdown
end
end
end
end
end
end
end
end
end
...@@ -8,7 +8,7 @@ module QA ...@@ -8,7 +8,7 @@ module QA
page.has_css?('.dropdown-input-field', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME) page.has_css?('.dropdown-input-field', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
find('.dropdown-input-field').set(item) find('.dropdown-input-field').set(item)
click_link item click_on item
end end
end end
end end
......
# frozen_string_literal: true
module QA
module Page
module Project
module Settings
class ProtectedTags < Page::Base
include Page::Component::DropdownFilter
view 'app/views/projects/protected_tags/shared/_dropdown.html.haml' do
element :tags_dropdown
end
view 'app/views/projects/protected_tags/_create_protected_tag.html.haml' do
element :access_levels_dropdown
end
view 'app/views/projects/protected_tags/shared/_create_protected_tag.html.haml' do
element :protect_tag_button
end
def set_tag(tag_name)
click_element :tags_dropdown
filter_and_select(tag_name)
end
def choose_access_level_role(role)
click_element :access_levels_dropdown
click_on role
end
def click_protect_tag_button
click_element :protect_tag_button
end
end
end
end
end
end
QA::Page::Project::Settings::ProtectedTags.prepend_if_ee('QA::EE::Page::Project::Settings::ProtectedTags')
...@@ -23,6 +23,10 @@ module QA ...@@ -23,6 +23,10 @@ module QA
element :deploy_keys_settings element :deploy_keys_settings
end end
view 'app/views/projects/protected_tags/shared/_index.html.haml' do
element :protected_tag_settings_content
end
def expand_deploy_tokens(&block) def expand_deploy_tokens(&block)
expand_section(:deploy_tokens_settings) do expand_section(:deploy_tokens_settings) do
Settings::DeployTokens.perform(&block) Settings::DeployTokens.perform(&block)
...@@ -46,6 +50,12 @@ module QA ...@@ -46,6 +50,12 @@ module QA
MirroringRepositories.perform(&block) MirroringRepositories.perform(&block)
end end
end end
def expand_protected_tags(&block)
expand_section(:protected_tag_settings_content) do
ProtectedTags.perform(&block)
end
end
end end
end end
end end
......
...@@ -14,15 +14,16 @@ module QA ...@@ -14,15 +14,16 @@ module QA
include QA::Page::Project::SubMenus::Common include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :project_menu_repo element :repository_link
element :branches_link element :branches_link
element :tags_link
end end
end end
end end
def click_repository def click_repository
within_sidebar do within_sidebar do
click_element(:project_menu_repo) click_element(:repository_link)
end end
end end
...@@ -34,11 +35,19 @@ module QA ...@@ -34,11 +35,19 @@ module QA
end end
end end
def go_to_repository_tags
hover_repository do
within_submenu do
click_element(:tags_link)
end
end
end
private private
def hover_repository def hover_repository
within_sidebar do within_sidebar do
find_element(:project_menu_repo).hover find_element(:repository_link).hover
yield yield
end end
......
# frozen_string_literal: true
module QA
module Page
module Project
module Tag
class Index < Page::Base
view 'app/views/projects/tags/index.html.haml' do
element :new_tag_button
end
def click_new_tag_button
click_element :new_tag_button
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Page
module Project
module Tag
class New < Page::Base
view 'app/views/projects/tags/new.html.haml' do
element :tag_name_field
element :tag_message_field
element :release_notes_field
element :create_tag_button
end
view 'app/views/shared/_zen.html.haml' do
# This partial adds the `release_notes_field` selector passed from 'app/views/projects/tags/new.html.haml'
# The checks below ensure that required lines are not removed without updating this page object
element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
element :_, "text_area_tag attr, current_text, data: { qa_selector: qa_selector }" # rubocop:disable QA/ElementWithPattern
end
def fill_tag_name(text)
fill_element(:tag_name_field, text)
end
def fill_tag_message(text)
fill_element(:tag_message_field, text)
end
def fill_release_notes(text)
fill_element(:release_notes_field, text)
end
def click_create_tag_button
click_element :create_tag_button
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Page
module Project
module Tag
class Show < Page::Base
view 'app/views/projects/tags/show.html.haml' do
element :tag_name_content
element :tag_message_content
element :tag_release_notes_content
end
def has_tag_name?(text)
has_element?(:tag_name_content, text: text)
end
def has_tag_message?(text)
has_element?(:tag_message_content, text: text)
end
def has_tag_release_notes?(text)
has_element?(:tag_release_notes_content, text: text)
end
end
end
end
end
end
# frozen_string_literal: true
module QA
context 'Manage' do
describe 'Repository tags' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-for-tags'
project.initialize_with_readme = true
end
end
let(:developer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:maintainer_user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
let(:tag_name) { 'v0.0.1' }
let(:tag_message) { 'Version 0.0.1' }
let(:tag_release_notes) { 'Release It!' }
shared_examples 'successful tag creation' do |user|
it "can be created by #{user}" do
Flow::Login.sign_in(as: send(user))
create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
Page::Project::Tag::Show.perform do |show|
expect(show).to have_tag_name(tag_name)
expect(show).to have_tag_message(tag_message)
expect(show).to have_tag_release_notes(tag_release_notes)
expect(show).not_to have_element(:create_tag_button)
end
end
end
shared_examples 'unsuccessful tag creation' do |user|
it "cannot be created by an unauthorized #{user}" do
Flow::Login.sign_in(as: send(user))
create_tag_for_project(project, tag_name, tag_message, tag_release_notes)
Page::Project::Tag::New.perform do |new_tag|
expect(new_tag).to have_content('You are not allowed to create this tag as it is protected.')
expect(new_tag).to have_element(:create_tag_button)
end
end
end
context 'when not protected' do
before do
add_members_to_project(project)
end
it_behaves_like 'successful tag creation', :developer_user
it_behaves_like 'successful tag creation', :maintainer_user
end
context 'when protected' do
before do
add_members_to_project(project)
Flow::Login.sign_in
protect_tag_for_project(project, 'v*', 'Maintainers')
Page::Main::Menu.perform(&:sign_out)
end
it_behaves_like 'unsuccessful tag creation', :developer_user
it_behaves_like 'successful tag creation', :maintainer_user
end
def create_tag_for_project(project, name, message, release_notes)
project.visit!
Page::Project::Menu.perform(&:go_to_repository_tags)
Page::Project::Tag::Index.perform(&:click_new_tag_button)
Page::Project::Tag::New.perform do |new_tag|
new_tag.fill_tag_name(name)
new_tag.fill_tag_message(message)
new_tag.fill_release_notes(release_notes)
new_tag.click_create_tag_button
end
end
def protect_tag_for_project(project, tag, role)
project.visit!
Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_tags do |protected_tags|
protected_tags.set_tag(tag)
protected_tags.choose_access_level_role(role)
protected_tags.click_protect_tag_button
end
end
end
def add_members_to_project(project)
@developer_user = developer_user
@maintainer_user = maintainer_user
project.add_member(@developer_user, Resource::Members::AccessLevel::DEVELOPER)
project.add_member(@maintainer_user, Resource::Members::AccessLevel::MAINTAINER)
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment