Commit ff7f164d authored by Andrejs Cunskis's avatar Andrejs Cunskis

E2E: Update github import spec with proper validation

Interact with specific item row

Validate specific project imported instead of global state

Validate got to projects button

E2E: Fix fabricate via UI method
parent 061963f3
...@@ -103,6 +103,7 @@ export default { ...@@ -103,6 +103,7 @@ export default {
<tr <tr
class="gl-h-11 gl-border-0 gl-border-solid gl-border-t-1 gl-border-gray-100 gl-h-11" class="gl-h-11 gl-border-0 gl-border-solid gl-border-t-1 gl-border-gray-100 gl-h-11"
data-qa-selector="project_import_row" data-qa-selector="project_import_row"
:data-qa-source-project="repo.importSource.fullName"
> >
<td class="gl-p-4"> <td class="gl-p-4">
<gl-link :href="repo.importSource.providerLink" target="_blank" data-testid="providerLink" <gl-link :href="repo.importSource.providerLink" target="_blank" data-testid="providerLink"
...@@ -155,7 +156,7 @@ export default { ...@@ -155,7 +156,7 @@ export default {
</template> </template>
<template v-else-if="repo.importedProject">{{ displayFullPath }}</template> <template v-else-if="repo.importedProject">{{ displayFullPath }}</template>
</td> </td>
<td class="gl-p-4"> <td class="gl-p-4" data-qa-selector="import_status_indicator">
<import-status :status="importStatus" /> <import-status :status="importStatus" />
</td> </td>
<td data-testid="actions"> <td data-testid="actions">
......
...@@ -21,7 +21,7 @@ module QA ...@@ -21,7 +21,7 @@ module QA
end end
def to_s def to_s
<<~MSG.strip % { page: @page_class } format(<<~MSG.strip, page: @page_class)
%{page} has no required elements. %{page} has no required elements.
See https://docs.gitlab.com/ee/development/testing_guide/end_to_end/dynamic_element_validation.html#required-elements See https://docs.gitlab.com/ee/development/testing_guide/end_to_end/dynamic_element_validation.html#required-elements
MSG MSG
...@@ -232,7 +232,7 @@ module QA ...@@ -232,7 +232,7 @@ module QA
visible = kwargs.delete(:visible) visible = kwargs.delete(:visible)
visible = visible.nil? && true visible = visible.nil? && true
try_find_element = ->(wait) do try_find_element = lambda do |wait|
if disabled.nil? if disabled.nil?
has_css?(element_selector_css(name, kwargs), text: text, wait: wait, class: klass, visible: visible) has_css?(element_selector_css(name, kwargs), text: text, wait: wait, class: klass, visible: visible)
else else
...@@ -322,13 +322,13 @@ module QA ...@@ -322,13 +322,13 @@ module QA
# It would be ideal if we could detect when the animation is complete # It would be ideal if we could detect when the animation is complete
# but in some cases there's nothing we can easily access via capybara # but in some cases there's nothing we can easily access via capybara
# so instead we wait for the element, and then we wait a little longer # so instead we wait for the element, and then we wait a little longer
raise ElementNotFound, %Q(Couldn't find element named "#{name}") unless has_element?(name) raise ElementNotFound, %(Couldn't find element named "#{name}") unless has_element?(name)
sleep 1 sleep 1
end end
def within_element(name, **kwargs) def within_element(name, **kwargs)
wait_for_requests wait_for_requests(skip_finished_loading_check: kwargs.delete(:skip_finished_loading_check))
text = kwargs.delete(:text) text = kwargs.delete(:text)
page.within(element_selector_css(name, kwargs), text: text) do page.within(element_selector_css(name, kwargs), text: text) do
...@@ -386,9 +386,7 @@ module QA ...@@ -386,9 +386,7 @@ module QA
end end
def self.errors def self.errors
if views.empty? return ["Page class does not have views / elements defined!"] if views.empty?
return ["Page class does not have views / elements defined!"]
end
views.flat_map(&:errors) views.flat_map(&:errors)
end end
......
...@@ -18,12 +18,17 @@ module QA ...@@ -18,12 +18,17 @@ module QA
element :import_button element :import_button
element :project_path_content element :project_path_content
element :go_to_project_button element :go_to_project_button
element :import_status_indicator
end end
view "app/assets/javascripts/import_entities/components/group_dropdown.vue" do view "app/assets/javascripts/import_entities/components/group_dropdown.vue" do
element :target_namespace_selector_dropdown element :target_namespace_selector_dropdown
end end
# Add personal access token
#
# @param [String] personal_access_token
# @return [void]
def add_personal_access_token(personal_access_token) def add_personal_access_token(personal_access_token)
# If for some reasons this process is retried, user cannot re-enter github token in the same group # If for some reasons this process is retried, user cannot re-enter github token in the same group
# In this case skip this step and proceed to import project row # In this case skip this step and proceed to import project row
...@@ -34,71 +39,50 @@ module QA ...@@ -34,71 +39,50 @@ module QA
finished_loading? finished_loading?
end end
def import!(full_path, name) # Import project
return if already_imported(full_path) #
# @param [String] source_project_name
choose_test_namespace(full_path) # @param [String] target_group_path
set_path(full_path, name) # @return [void]
import_project(full_path) def import!(gh_project_name, target_group_path, project_name)
within_element(:project_import_row, source_project: gh_project_name) do
wait_for_success click_element(:target_namespace_selector_dropdown)
end click_element(:target_group_dropdown_item, group_name: target_group_path)
fill_element(:project_path_field, project_name)
# TODO: refactor to use 'go to project' button instead of generic main menu
def go_to_project(name)
Page::Main::Menu.perform(&:go_to_projects)
Page::Dashboard::Projects.perform do |dashboard|
dashboard.go_to_project(name)
end
end
private
def within_repo_path(full_path, &block)
project_import_row = find_element(:project_import_row, text: full_path)
within(project_import_row, &block)
end
def choose_test_namespace(full_path)
within_repo_path(full_path) do
within_element(:target_namespace_selector_dropdown) { click_button(class: 'dropdown-toggle') }
click_element(:target_group_dropdown_item, group_name: Runtime::Namespace.path)
end
end
def set_path(full_path, name)
within_repo_path(full_path) do
fill_element(:project_path_field, name)
end
end
def import_project(full_path)
within_repo_path(full_path) do
click_element(:import_button) click_element(:import_button)
end end
end end
def wait_for_success # Check Go to project button present
# TODO: set reload:false and remove skip_finished_loading_check_on_refresh when #
# https://gitlab.com/gitlab-org/gitlab/-/issues/292861 is fixed # @param [String] gh_project_name
wait_until( # @return [Boolean]
max_duration: 90, def has_go_to_project_button?(gh_project_name)
sleep_interval: 5.0, within_element(:project_import_row, source_project: gh_project_name) do
reload: true, has_element?(:go_to_project_button)
skip_finished_loading_check_on_refresh: true
) do
# TODO: Refactor to explicitly wait for specific project import successful status
# This check can create false positive if main importing message appears with delay and check exits early
page.has_no_content?('Importing 1 repository', wait: 3)
end end
end end
def already_imported(full_path) # Check if import page has a successfully imported project
within_repo_path(full_path) do #
has_element?(:project_path_content) && has_element?(:go_to_project_button) # @param [String] source_project_name
# @param [Integer] wait
# @return [Boolean]
def has_imported_project?(gh_project_name, wait: QA::Support::WaitForRequests::DEFAULT_MAX_WAIT_TIME)
within_element(:project_import_row, source_project: gh_project_name, skip_finished_loading_check: true) do
# TODO: remove retrier with reload:true once https://gitlab.com/gitlab-org/gitlab/-/issues/292861 is fixed
wait_until(
max_duration: wait,
sleep_interval: 5,
reload: true,
skip_finished_loading_check_on_refresh: true
) do
has_element?(:import_status_indicator, text: "Complete")
end
end end
end end
alias_method :wait_for_success, :has_imported_project?
end end
end end
end end
......
...@@ -18,9 +18,12 @@ module QA ...@@ -18,9 +18,12 @@ module QA
Page::Project::Import::Github.perform do |import_page| Page::Project::Import::Github.perform do |import_page|
import_page.add_personal_access_token(github_personal_access_token) import_page.add_personal_access_token(github_personal_access_token)
import_page.import!(github_repository_path, name) import_page.import!(github_repository_path, group.full_path, name)
import_page.go_to_project(name) import_page.wait_for_success(github_repository_path)
end end
reload!
visit!
end end
def go_to_import_page def go_to_import_page
......
...@@ -3,9 +3,11 @@ ...@@ -3,9 +3,11 @@
module QA module QA
RSpec.describe 'Manage', :github, :requires_admin do RSpec.describe 'Manage', :github, :requires_admin do
describe 'Project import' do describe 'Project import' do
let!(:api_client) { Runtime::API::Client.as_admin } let(:github_repo) { 'gitlab-qa-github/test-project' }
let!(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } } let(:imported_project_name) { 'imported-project' }
let!(:user) do let(:api_client) { Runtime::API::Client.as_admin }
let(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } }
let(:user) do
Resource::User.fabricate_via_api! do |resource| Resource::User.fabricate_via_api! do |resource|
resource.api_client = api_client resource.api_client = api_client
resource.hard_delete_on_api_removal = true resource.hard_delete_on_api_removal = true
...@@ -13,16 +15,25 @@ module QA ...@@ -13,16 +15,25 @@ module QA
end end
let(:imported_project) do let(:imported_project) do
Resource::ProjectImportedFromGithub.fabricate_via_browser_ui! do |project| Resource::ProjectImportedFromGithub.init do |project|
project.name = 'imported-project' project.import = true
project.add_name_uuid = false
project.name = imported_project_name
project.group = group project.group = group
project.github_personal_access_token = Runtime::Env.github_access_token project.github_personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = 'gitlab-qa-github/test-project' project.github_repository_path = github_repo
end end
end end
before do before do
group.add_member(user, Resource::Members::AccessLevel::MAINTAINER) group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
Flow::Login.sign_in(as: user)
Page::Main::Menu.perform(&:go_to_create_project)
Page::Project::New.perform do |project_page|
project_page.click_import_project
project_page.click_github_link
end
end end
after do after do
...@@ -30,13 +41,24 @@ module QA ...@@ -30,13 +41,24 @@ module QA
end end
it 'imports a GitHub repo', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1762' do it 'imports a GitHub repo', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1762' do
Flow::Login.sign_in(as: user) Page::Project::Import::Github.perform do |import_page|
import_page.add_personal_access_token(Runtime::Env.github_access_token)
import_page.import!(github_repo, group.full_path, imported_project_name)
imported_project # import the project aggregate_failures do
expect(import_page).to have_imported_project(github_repo)
# validate button is present instead of navigating to avoid dealing with multiple tabs
# which makes the test more complicated
expect(import_page).to have_go_to_project_button(github_repo)
end
end
imported_project.reload!.visit!
Page::Project::Show.perform do |project| Page::Project::Show.perform do |project|
expect(project).to have_content(imported_project.name) aggregate_failures do
expect(project).to have_content('This test project is used for automated GitHub import by GitLab QA.') expect(project).to have_content(imported_project_name)
expect(project).to have_content('This test project is used for automated GitHub import by GitLab QA.')
end
end end
end end
end end
......
...@@ -51,7 +51,7 @@ module QA ...@@ -51,7 +51,7 @@ module QA
group.add_member(user, Resource::Members::AccessLevel::OWNER) group.add_member(user, Resource::Members::AccessLevel::OWNER)
Flow::Login.sign_in(as: user) Flow::Login.sign_in(as: user)
imported_project.reload! # import project and populate attributes imported_project # import project
end end
after do after do
......
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