From 2ad990bba0cce86bd2e44d2e91e73f874f0f0896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 18 Jun 2018 17:05:42 +0200 Subject: [PATCH] [QA] Add a new scenario to test GitHub import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/views/import/_githubish_status.html.haml | 4 +- app/views/layouts/header/_new_dropdown.haml | 2 +- qa/qa.rb | 9 +- qa/qa/factory/resource/group.rb | 2 +- qa/qa/factory/resource/project.rb | 18 +-- .../resource/project_imported_from_github.rb | 37 ++++++ qa/qa/factory/resource/sandbox.rb | 4 +- qa/qa/page/component/select2.rb | 11 ++ qa/qa/page/issuable/{show.rb => sidebar.rb} | 5 +- qa/qa/page/menu/side.rb | 8 ++ qa/qa/page/project/import/github.rb | 66 +++++++++++ qa/qa/page/project/new.rb | 20 +++- qa/qa/page/project/show.rb | 10 ++ qa/qa/runtime/env.rb | 11 ++ qa/qa/runtime/namespace.rb | 2 +- qa/qa/scenario/test/integration/github.rb | 18 +++ .../project/import_from_github_spec.rb | 106 ++++++++++++++++++ qa/spec/runtime/env_spec.rb | 23 ++++ 18 files changed, 337 insertions(+), 19 deletions(-) create mode 100644 qa/qa/factory/resource/project_imported_from_github.rb create mode 100644 qa/qa/page/component/select2.rb rename qa/qa/page/issuable/{show.rb => sidebar.rb} (73%) create mode 100644 qa/qa/page/project/import/github.rb create mode 100644 qa/qa/scenario/test/integration/github.rb create mode 100644 qa/qa/specs/features/project/import_from_github_spec.rb diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml index f7094375023..5e7be5cd37b 100644 --- a/app/views/import/_githubish_status.html.haml +++ b/app/views/import/_githubish_status.html.haml @@ -40,7 +40,7 @@ = project.human_import_status_name - @repos.each do |repo| - %tr{ id: "repo_#{repo.id}" } + %tr{ id: "repo_#{repo.id}", data: { qa: { repo_path: repo.full_name } } } %td = provider_project_link(provider, repo.full_name) %td.import-target @@ -50,7 +50,7 @@ - if current_user.can_select_namespace? - selected = params[:namespace_id] || :current_user - opts = current_user.can_create_group? ? { extra_group: Group.new(name: repo.owner.login, path: repo.owner.login) } : {} - = select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'input-group-text select2 js-select-namespace', tabindex: 1 } + = select_tag :namespace_id, namespaces_options(selected, opts.merge({ display_path: true })), { class: 'input-group-text select2 js-select-namespace qa-project-namespace-select', tabindex: 1 } - else = text_field_tag :path, current_user.namespace_path, class: "input-group-text input-large form-control", tabindex: 1, disabled: true %span.input-group-prepend diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml index d35df706036..792291bde75 100644 --- a/app/views/layouts/header/_new_dropdown.haml +++ b/app/views/layouts/header/_new_dropdown.haml @@ -37,7 +37,7 @@ %li.dropdown-bold-header GitLab - if current_user.can_create_project? %li - = link_to 'New project', new_project_path + = link_to 'New project', new_project_path, class: 'qa-global-new-project-link' - if current_user.can_create_group? %li = link_to 'New group', new_group_path diff --git a/qa/qa.rb b/qa/qa.rb index 41fca37c8f2..6d0521f8ed0 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -40,6 +40,7 @@ module QA autoload :Issue, 'qa/factory/resource/issue' autoload :Project, 'qa/factory/resource/project' autoload :MergeRequest, 'qa/factory/resource/merge_request' + autoload :ProjectImportedFromGithub, 'qa/factory/resource/project_imported_from_github' autoload :DeployKey, 'qa/factory/resource/deploy_key' autoload :Branch, 'qa/factory/resource/branch' autoload :SecretVariable, 'qa/factory/resource/secret_variable' @@ -79,6 +80,7 @@ module QA autoload :Instance, 'qa/scenario/test/instance' module Integration + autoload :Github, 'qa/scenario/test/integration/github' autoload :LDAP, 'qa/scenario/test/integration/ldap' autoload :Kubernetes, 'qa/scenario/test/integration/kubernetes' autoload :Mattermost, 'qa/scenario/test/integration/mattermost' @@ -132,6 +134,10 @@ module QA autoload :Show, 'qa/page/project/show' autoload :Activity, 'qa/page/project/activity' + module Import + autoload :Github, 'qa/page/project/import/github' + end + module Pipeline autoload :Index, 'qa/page/project/pipeline/index' autoload :Show, 'qa/page/project/pipeline/show' @@ -185,7 +191,7 @@ module QA end module Issuable - autoload :Show, 'qa/page/issuable/show' + autoload :Sidebar, 'qa/page/issuable/sidebar' end module MergeRequest @@ -210,6 +216,7 @@ module QA # module Component autoload :Dropzone, 'qa/page/component/dropzone' + autoload :Select2, 'qa/page/component/select2' end end diff --git a/qa/qa/factory/resource/group.rb b/qa/qa/factory/resource/group.rb index 9f13e26f35c..531fccd2ad8 100644 --- a/qa/qa/factory/resource/group.rb +++ b/qa/qa/factory/resource/group.rb @@ -23,7 +23,7 @@ module QA Page::Group::New.perform do |group| group.set_path(@path) group.set_description(@description) - group.set_visibility('Private') + group.set_visibility('Public') group.create end end diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb index cda1b35ba6a..7bc64c6ae5d 100644 --- a/qa/qa/factory/resource/project.rb +++ b/qa/qa/factory/resource/project.rb @@ -5,16 +5,12 @@ module QA module Resource class Project < Factory::Base attr_writer :description + attr_reader :name dependency Factory::Resource::Group, as: :group - def name=(name) - @name = "#{name}-#{SecureRandom.hex(8)}" - @description = 'My awesome project' - end - - product :name do - Page::Project::Show.act { project_name } + product :name do |factory| + factory.name end product :repository_ssh_location do @@ -24,6 +20,14 @@ module QA end end + def initialize + @description = 'My awesome project' + end + + def name=(raw_name) + @name = "#{raw_name}-#{SecureRandom.hex(8)}" + end + def fabricate! group.visit! diff --git a/qa/qa/factory/resource/project_imported_from_github.rb b/qa/qa/factory/resource/project_imported_from_github.rb new file mode 100644 index 00000000000..df2a3340d60 --- /dev/null +++ b/qa/qa/factory/resource/project_imported_from_github.rb @@ -0,0 +1,37 @@ +require 'securerandom' + +module QA + module Factory + module Resource + class ProjectImportedFromGithub < Resource::Project + attr_writer :personal_access_token, :github_repository_path + + dependency Factory::Resource::Group, as: :group + + product :name do |factory| + factory.name + end + + def fabricate! + group.visit! + + Page::Group::Show.act { go_to_new_project } + + Page::Project::New.perform do |page| + page.go_to_import_project + end + + Page::Project::New.perform do |page| + page.go_to_github_import + end + + Page::Project::Import::Github.perform do |page| + page.add_personal_access_token(@personal_access_token) + page.list_repos + page.import!(@github_repository_path, @name) + end + end + end + end + end +end diff --git a/qa/qa/factory/resource/sandbox.rb b/qa/qa/factory/resource/sandbox.rb index ad376988e82..4f6039f300f 100644 --- a/qa/qa/factory/resource/sandbox.rb +++ b/qa/qa/factory/resource/sandbox.rb @@ -21,8 +21,8 @@ module QA Page::Group::New.perform do |group| group.set_path(@name) - group.set_description('GitLab QA Sandbox') - group.set_visibility('Private') + group.set_description('GitLab QA Sandbox Group') + group.set_visibility('Public') group.create end end diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb new file mode 100644 index 00000000000..30829eb0221 --- /dev/null +++ b/qa/qa/page/component/select2.rb @@ -0,0 +1,11 @@ +module QA + module Page + module Component + module Select2 + def select_item(item_text) + find('ul.select2-result-sub > li', text: item_text).click + end + end + end + end +end diff --git a/qa/qa/page/issuable/show.rb b/qa/qa/page/issuable/sidebar.rb similarity index 73% rename from qa/qa/page/issuable/show.rb rename to qa/qa/page/issuable/sidebar.rb index c02edbd286b..dec2ce1eab3 100644 --- a/qa/qa/page/issuable/show.rb +++ b/qa/qa/page/issuable/sidebar.rb @@ -1,15 +1,14 @@ module QA module Page module Issuable - class Show < Page::Base + class Sidebar < Page::Base view 'app/views/shared/issuable/_sidebar.html.haml' do element :labels_block, ".issuable-show-labels" end def has_label?(label) page.within('.issuable-show-labels') do - element = find('span', text: label, wait: 1) - !element.nil? + !!find('span', text: label) end end end diff --git a/qa/qa/page/menu/side.rb b/qa/qa/page/menu/side.rb index 6bf4825cf00..333d871c51a 100644 --- a/qa/qa/page/menu/side.rb +++ b/qa/qa/page/menu/side.rb @@ -10,6 +10,8 @@ module QA element :operations_kubernetes_link, "title: _('Kubernetes')" element :issues_link, /link_to.*shortcuts-issues/ element :issues_link_text, "Issues" + element :merge_requests_link, /link_to.*shortcuts-merge_requests/ + element :merge_requests_link_text, "Merge Requests" element :top_level_items, '.sidebar-top-level-items' element :operations_section, "class: 'shortcuts-operations'" element :activity_link, "title: 'Activity'" @@ -62,6 +64,12 @@ module QA end end + def click_merge_requests + within_sidebar do + click_link('Merge Requests') + end + end + def click_wiki within_sidebar do click_link('Wiki') diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb new file mode 100644 index 00000000000..36567927194 --- /dev/null +++ b/qa/qa/page/project/import/github.rb @@ -0,0 +1,66 @@ +module QA + module Page + module Project + module Import + class Github < Page::Base + include Page::Component::Select2 + + view 'app/views/import/github/new.html.haml' do + element :personal_access_token_field, 'text_field_tag :personal_access_token' + element :list_repos_button, "submit_tag _('List your GitHub repositories')" + end + + view 'app/views/import/_githubish_status.html.haml' do + element :project_import_row, 'data: { qa: { repo_path: repo.full_name } }' + element :project_namespace_select + element :project_namespace_field, 'select_tag :namespace_id' + element :project_path_field, 'text_field_tag :path, repo.name' + element :import_button, "_('Import')" + end + + def add_personal_access_token(personal_access_token) + fill_in 'personal_access_token', with: personal_access_token + end + + def list_repos + click_button 'List your GitHub repositories' + end + + def import!(full_path, name) + choose_test_namespace(full_path) + set_path(full_path, name) + import_project(full_path) + end + + private + + def within_repo_path(full_path) + page.within(%Q(tr[data-qa-repo-path="#{full_path}"])) do + yield + end + end + + def choose_test_namespace(full_path) + within_repo_path(full_path) do + click_element :project_namespace_select + end + + select_item(Runtime::Namespace.path) + end + + def set_path(full_path, name) + within_repo_path(full_path) do + fill_in 'path', with: name + end + end + + def import_project(full_path) + within_repo_path(full_path) do + click_button 'Import' + end + end + end + end + end + end +end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index 186a4724326..7976e96d43b 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -2,6 +2,12 @@ module QA module Page module Project class New < Page::Base + include Page::Component::Select2 + + view 'app/views/projects/new.html.haml' do + element :import_project_tab, "Import project" + end + view 'app/views/projects/_new_project_fields.html.haml' do element :project_namespace_select element :project_namespace_field, /select :namespace_id.*class: 'select2/ @@ -10,10 +16,18 @@ module QA element :project_create_button, "submit 'Create project'" end + view 'app/views/projects/_import_project_pane.html.haml' do + element :import_github, "icon('github', text: 'GitHub')" + end + def choose_test_namespace click_element :project_namespace_select - find('ul.select2-result-sub > li', text: Runtime::Namespace.path).click + select_item(Runtime::Namespace.path) + end + + def go_to_import_project + click_on 'Import project' end def choose_name(name) @@ -27,6 +41,10 @@ module QA def create_new_project click_on 'Create project' end + + def go_to_github_import + click_link 'GitHub' + end end end end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 1406edece17..1dcdb59490a 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -22,6 +22,10 @@ module QA element :branches_dropdown end + view 'app/views/projects/_files.html.haml' do + element :tree_holder, '.tree-holder' + end + def project_name find('.qa-project-name').text end @@ -46,6 +50,12 @@ module QA click_element :create_merge_request end + def wait_for_import + wait(reload: true) do + has_css?('.tree-holder') + end + end + def go_to_new_issue click_element :new_menu_toggle diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index 7610c7f3f43..5dc194e0aef 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -66,6 +66,17 @@ module QA def has_gcloud_credentials? %w[GCLOUD_ACCOUNT_KEY GCLOUD_ACCOUNT_EMAIL].none? { |var| ENV[var].to_s.empty? } end + + # Specifies the token that can be used for the GitHub API + def github_access_token + ENV['GITHUB_ACCESS_TOKEN'].to_s.strip + end + + def require_github_access_token! + return unless github_access_token.empty? + + raise ArgumentError, "Please provide GITHUB_ACCESS_TOKEN" + end end end end diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb index 8d05b387416..ccfa8b44db3 100644 --- a/qa/qa/runtime/namespace.rb +++ b/qa/qa/runtime/namespace.rb @@ -16,7 +16,7 @@ module QA end def sandbox_name - Runtime::Env.sandbox_name || 'gitlab-qa-sandbox' + Runtime::Env.sandbox_name || 'gitlab-qa-sandbox-group' end end end diff --git a/qa/qa/scenario/test/integration/github.rb b/qa/qa/scenario/test/integration/github.rb new file mode 100644 index 00000000000..1d22b532aa5 --- /dev/null +++ b/qa/qa/scenario/test/integration/github.rb @@ -0,0 +1,18 @@ +module QA + module Scenario + module Test + module Integration + class Github < Test::Instance + tags :github + + def perform(address, *rspec_options) + # This test suite requires a GitHub personal access token + Runtime::Env.require_github_access_token! + + super + end + end + end + end + end +end diff --git a/qa/qa/specs/features/project/import_from_github_spec.rb b/qa/qa/specs/features/project/import_from_github_spec.rb new file mode 100644 index 00000000000..221b5c27fba --- /dev/null +++ b/qa/qa/specs/features/project/import_from_github_spec.rb @@ -0,0 +1,106 @@ +module QA + describe 'user imports a GitHub repo', :core, :github do + let(:imported_project) do + Factory::Resource::ProjectImportedFromGithub.fabricate! do |project| + project.name = 'imported-project' + project.personal_access_token = Runtime::Env.github_access_token + project.github_repository_path = 'gitlab-qa/test-project' + end + end + + after do + # We need to delete the imported project because it's impossible to import + # the same GitHub project twice for a given user. + api_client = Runtime::API::Client.new(:gitlab) + delete_project_request = Runtime::API::Request.new(api_client, "/projects/#{CGI.escape("#{Runtime::Namespace.path}/#{imported_project.name}")}") + delete delete_project_request.url + + expect_status(202) + end + + it 'user imports a GitHub repo' do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } + + imported_project # import the project + + Page::Menu::Main.act { go_to_projects } + Page::Dashboard::Projects.perform do |dashboard| + dashboard.go_to_project(imported_project.name) + end + + Page::Project::Show.act { wait_for_import } + + verify_repository_import + verify_issues_import + verify_merge_requests_import + verify_labels_import + verify_milestones_import + verify_wiki_import + end + + def verify_repository_import + expect(page).to have_content('This test project is used for automated GitHub import by GitLab QA.') + expect(page).to have_content(imported_project.name) + end + + def verify_issues_import + Page::Menu::Side.act { click_issues } + expect(page).to have_content('This is a sample issue') + + click_link 'This is a sample issue' + + expect(page).to have_content('We should populate this project with issues, pull requests and wiki pages.') + + # Comments + expect(page).to have_content('This is a comment from @rymai.') + + Page::Issuable::Sidebar.perform do |issuable| + expect(issuable).to have_label('enhancement') + expect(issuable).to have_label('help wanted') + expect(issuable).to have_label('good first issue') + end + end + + def verify_merge_requests_import + Page::Menu::Side.act { click_merge_requests } + expect(page).to have_content('Improve README.md') + + click_link 'Improve README.md' + + expect(page).to have_content('This improves the README file a bit.') + + # Review comment are not supported yet + expect(page).not_to have_content('Really nice change.') + + # Comments + expect(page).to have_content('Nice work! This is a comment from @rymai.') + + # Diff comments + expect(page).to have_content('[Review comment] I like that!') + expect(page).to have_content('[Review comment] Nice blank line.') + expect(page).to have_content('[Single diff comment] Much better without this line!') + + Page::Issuable::Sidebar.perform do |issuable| + expect(issuable).to have_label('bug') + expect(issuable).to have_label('enhancement') + end + end + + def verify_labels_import + # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19228 + # to build upon it. + end + + def verify_milestones_import + # TODO: Waiting on https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18727 + # to build upon it. + end + + def verify_wiki_import + Page::Menu::Side.act { click_wiki } + + expect(page).to have_content('Welcome to the test-project wiki!') + end + end +end diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb index 2b6365dbc41..851026c71f0 100644 --- a/qa/spec/runtime/env_spec.rb +++ b/qa/spec/runtime/env_spec.rb @@ -76,4 +76,27 @@ describe QA::Runtime::Env do expect { described_class.user_type }.to raise_error(ArgumentError) end end + + describe '.github_access_token' do + it 'returns "" if GITHUB_ACCESS_TOKEN is not defined' do + expect(described_class.github_access_token).to eq('') + end + + it 'returns stripped string if GITHUB_ACCESS_TOKEN is defined' do + stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ') + expect(described_class.github_access_token).to eq('abc123') + end + end + + describe '.require_github_access_token!' do + it 'raises ArgumentError if GITHUB_ACCESS_TOKEN is not defined' do + expect { described_class.require_github_access_token! }.to raise_error(ArgumentError) + end + + it 'does not raise if GITHUB_ACCESS_TOKEN is defined' do + stub_env('GITHUB_ACCESS_TOKEN', ' abc123 ') + + expect { described_class.require_github_access_token! }.not_to raise_error + end + end end