Commit c7c8019a authored by Mark Lapierre's avatar Mark Lapierre

Merge branch 'ml-qa-add-npm-registry-test' into 'master'

Add E2E test of NPM registry

Closes gitlab-org/quality/testcases#220

See merge request gitlab-org/gitlab!18361
parents f0d315a8 804608a5
...@@ -184,11 +184,12 @@ export default { ...@@ -184,11 +184,12 @@ export default {
v-gl-modal="'delete-modal'" v-gl-modal="'delete-modal'"
class="js-delete-button" class="js-delete-button"
variant="danger" variant="danger"
data-qa-selector="delete_button"
>{{ __('Delete') }}</gl-button >{{ __('Delete') }}</gl-button
> >
</div> </div>
<div class="row prepend-top-default"> <div class="row prepend-top-default" data-qa-selector="package_information_content">
<package-information :type="packageEntity.package_type" :information="packageInformation" /> <package-information :type="packageEntity.package_type" :information="packageInformation" />
<package-information <package-information
v-if="packageMetadata" v-if="packageMetadata"
...@@ -223,9 +224,13 @@ export default { ...@@ -223,9 +224,13 @@ export default {
<div slot="modal-footer" class="w-100"> <div slot="modal-footer" class="w-100">
<div class="float-right"> <div class="float-right">
<gl-button @click="cancelDelete()">{{ __('Cancel') }}</gl-button> <gl-button @click="cancelDelete()">{{ __('Cancel') }}</gl-button>
<gl-button data-method="delete" :to="destroyPath" variant="danger">{{ <gl-button
__('Delete') data-method="delete"
}}</gl-button> :to="destroyPath"
variant="danger"
data-qa-selector="delete_modal_button"
>{{ __('Delete') }}</gl-button
>
</div> </div>
</div> </div>
</gl-modal> </gl-modal>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- if (project_nav_tab?(:packages) || project_nav_tab?(:container_registry)) - if (project_nav_tab?(:packages) || project_nav_tab?(:container_registry))
= nav_link controller: [:packages, :repositories] do = nav_link controller: [:packages, :repositories] do
= link_to packages_link do = link_to packages_link, data: { qa_selector: 'packages_link' } do
.nav-icon-container .nav-icon-container
= sprite_icon('package') = sprite_icon('package')
%span.nav-item-name %span.nav-item-name
......
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
= _('Created') = _('Created')
.table-section.section-10{ role: 'rowheader' } .table-section.section-10{ role: 'rowheader' }
- @packages.each do |package| - @packages.each do |package|
.gl-responsive-table-row.package-row.px-2 .gl-responsive-table-row.package-row.px-2{ data: { qa_selector: "package_row" } }
.table-section.section-30 .table-section.section-30
.table-mobile-header{ role: "rowheader" }= _("Name") .table-mobile-header{ role: "rowheader" }= _("Name")
.table-mobile-content.flex-truncate-parent .table-mobile-content.flex-truncate-parent
= link_to package.name, project_package_path(@project, package), class: 'flex-truncate-child' = link_to package.name, project_package_path(@project, package), class: 'flex-truncate-child', data: { qa_selector: "package_link" }
.table-section.section-20 .table-section.section-20
.table-mobile-header{ role: "rowheader" }= _("Version") .table-mobile-header{ role: "rowheader" }= _("Version")
.table-mobile-content .table-mobile-content
......
...@@ -407,6 +407,7 @@ module QA ...@@ -407,6 +407,7 @@ module QA
module DockerRun module DockerRun
autoload :Base, 'qa/service/docker_run/base' autoload :Base, 'qa/service/docker_run/base'
autoload :LDAP, 'qa/service/docker_run/ldap' autoload :LDAP, 'qa/service/docker_run/ldap'
autoload :NodeJs, 'qa/service/docker_run/node_js'
autoload :GitlabRunner, 'qa/service/docker_run/gitlab_runner' autoload :GitlabRunner, 'qa/service/docker_run/gitlab_runner'
end end
end end
......
...@@ -85,6 +85,7 @@ module QA ...@@ -85,6 +85,7 @@ module QA
autoload :Menu, 'qa/ee/page/project/menu' autoload :Menu, 'qa/ee/page/project/menu'
module SubMenus module SubMenus
autoload :Packages, 'qa/ee/page/project/sub_menus/packages'
autoload :SecurityCompliance, 'qa/ee/page/project/sub_menus/security_compliance' autoload :SecurityCompliance, 'qa/ee/page/project/sub_menus/security_compliance'
autoload :Repository, 'qa/ee/page/project/sub_menus/repository' autoload :Repository, 'qa/ee/page/project/sub_menus/repository'
autoload :Settings, 'qa/ee/page/project/sub_menus/settings' autoload :Settings, 'qa/ee/page/project/sub_menus/settings'
...@@ -118,6 +119,11 @@ module QA ...@@ -118,6 +119,11 @@ module QA
end end
end end
module Packages
autoload :Index, 'qa/ee/page/project/packages/index'
autoload :Show, 'qa/ee/page/project/packages/show'
end
module Pipeline module Pipeline
autoload :Show, 'qa/ee/page/project/pipeline/show' autoload :Show, 'qa/ee/page/project/pipeline/show'
end end
......
...@@ -7,6 +7,7 @@ module QA ...@@ -7,6 +7,7 @@ module QA
module Menu module Menu
prepend QA::Page::Project::SubMenus::Common prepend QA::Page::Project::SubMenus::Common
prepend SubMenus::SecurityCompliance prepend SubMenus::SecurityCompliance
prepend SubMenus::Packages
prepend SubMenus::Project prepend SubMenus::Project
prepend SubMenus::Settings prepend SubMenus::Settings
end end
......
# frozen_string_literal: true
module QA
module EE
module Page
module Project
module Packages
class Index < QA::Page::Base
view 'ee/app/views/projects/packages/packages/index.html.haml' do
element :package_row
element :package_link
end
def click_package(name)
click_element(:package_link, text: name)
end
def has_package?(name)
has_element?(:package_link, text: name)
end
def has_no_package?(name)
has_no_element?(:package_link, text: name)
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module EE
module Page
module Project
module Packages
class Show < QA::Page::Base
view 'ee/app/assets/javascripts/packages/components/app.vue' do
element :delete_button
element :delete_modal_button
element :package_information_content
end
def has_package_info?(name, version)
has_element?(:package_information_content, text: /#{name}.*#{version}/)
end
def click_delete
click_element(:delete_button)
wait_for_animated_element(:delete_modal_button)
click_element(:delete_modal_button)
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module EE
module Page
module Project
module SubMenus
module Packages
def self.included(page)
page.class_eval do
view 'ee/app/views/layouts/nav/sidebar/_project_packages_link.html.haml' do
element :packages_link
end
end
end
def click_packages_link
within_sidebar do
click_element :packages_link
end
end
end
end
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
require 'tmpdir'
module QA module QA
module Runtime module Runtime
module Fixtures module Fixtures
...@@ -18,6 +20,19 @@ module QA ...@@ -18,6 +20,19 @@ module QA
parse_body(response)[:content] parse_body(response)[:content]
end end
def with_fixtures(fixtures)
dir = Dir.mktmpdir
fixtures.each do |file_def|
path = File.join(dir, file_def[:file_path])
FileUtils.mkdir_p(File.dirname(path))
File.write(path, file_def[:content])
end
yield dir
ensure
FileUtils.remove_entry(dir)
end
private private
def api_client def api_client
......
# frozen_string_literal: true
module QA
module Service
module DockerRun
class NodeJs < Base
def initialize(volume_host_path)
@image = 'node:12.11.1-alpine'
@name = "qa-node-#{SecureRandom.hex(8)}"
@volume_host_path = volume_host_path
super()
end
def publish!
# When we run the tests via gitlab-qa, we use docker-in-docker
# which means that host of a volume mount would be the host that
# started the gitlab-qa QA container (e.g., the CI runner),
# not the gitlab-qa container itself. That means we can't
# mount a volume from the file system inside the gitlab-qa
# container.
#
# Instead, we copy the files into the container.
shell <<~CMD.tr("\n", ' ')
docker run -d --rm
--network #{network}
--hostname #{host_name}
--name #{@name}
--volume #{@volume_host_path}:/home/node
#{@image} sh -c "sleep 60"
CMD
shell "docker cp #{@volume_host_path}/. #{@name}:/home/node"
shell "docker exec -t #{@name} sh -c 'cd /home/node && npm publish'"
end
end
end
end
end
# frozen_string_literal: true
module QA
context 'Package', :docker, :orchestrated, :packages do
describe 'NPM registry' do
include Runtime::Fixtures
let(:registry_scope) { project.group.sandbox.path }
let(:package_name) { "@#{registry_scope}/#{project.name}" }
let(:auth_token) do
unless Page::Main::Menu.perform(&:signed_in?)
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
end
Resource::PersonalAccessToken.fabricate!.access_token
end
let(:project) do
Resource::Project.fabricate_via_api! do |resource|
resource.name = 'npm-registry-project'
end
end
it 'publishes an npm package and then deletes it' do
uri = URI.parse(Runtime::Scenario.gitlab_address)
gitlab_host_with_port = "#{uri.host}:#{uri.port}"
gitlab_address_with_port = "#{uri.scheme}://#{uri.host}:#{uri.port}"
package_json = {
file_path: 'package.json',
content: <<~JSON
{
"name": "#{package_name}",
"version": "1.0.0",
"description": "Example package for GitLab NPM registry",
"publishConfig": {
"@#{registry_scope}:registry": "#{gitlab_address_with_port}/api/v4/projects/#{project.id}/packages/npm/"
}
}
JSON
}
npmrc = {
file_path: '.npmrc',
content: <<~NPMRC
//#{gitlab_host_with_port}/api/v4/projects/#{project.id}/packages/npm/:_authToken=#{auth_token}
//#{gitlab_host_with_port}/api/v4/packages/npm/:_authToken=#{auth_token}
@#{registry_scope}:registry=#{gitlab_address_with_port}/api/v4/packages/npm/
NPMRC
}
# Use a node docker container to publish the package
with_fixtures([npmrc, package_json]) do |dir|
Service::DockerRun::NodeJs.new(dir).publish!
end
project.visit!
Page::Project::Menu.perform(&:click_packages_link)
EE::Page::Project::Packages::Index.perform do |index|
expect(index).to have_package(package_name)
index.click_package(package_name)
end
EE::Page::Project::Packages::Show.perform do |show|
expect(show).to have_package_info(package_name, "1.0.0")
show.click_delete
end
EE::Page::Project::Packages::Index.perform do |index|
expect(index).to have_content("Package was removed")
expect(index).to have_no_package(package_name)
end
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