diff options
Diffstat (limited to 'qa/qa')
-rw-r--r-- | qa/qa/factory/resource/personal_access_token.rb | 27 | ||||
-rw-r--r-- | qa/qa/page/README.md | 12 | ||||
-rw-r--r-- | qa/qa/page/menu/main.rb | 9 | ||||
-rw-r--r-- | qa/qa/page/menu/profile.rb | 27 | ||||
-rw-r--r-- | qa/qa/page/profile/personal_access_tokens.rb | 33 | ||||
-rw-r--r-- | qa/qa/runtime/address.rb | 20 | ||||
-rw-r--r-- | qa/qa/runtime/api.rb | 82 | ||||
-rw-r--r-- | qa/qa/runtime/browser.rb | 19 | ||||
-rw-r--r-- | qa/qa/runtime/env.rb | 6 | ||||
-rw-r--r-- | qa/qa/specs/features/api/users_spec.rb | 42 |
10 files changed, 262 insertions, 15 deletions
diff --git a/qa/qa/factory/resource/personal_access_token.rb b/qa/qa/factory/resource/personal_access_token.rb new file mode 100644 index 00000000000..514e3615d18 --- /dev/null +++ b/qa/qa/factory/resource/personal_access_token.rb @@ -0,0 +1,27 @@ +module QA + module Factory + module Resource + ## + # Create a personal access token that can be used by the api + # + class PersonalAccessToken < Factory::Base + attr_accessor :name + + product :access_token do + Page::Profile::PersonalAccessTokens.act { created_access_token } + end + + def fabricate! + Page::Menu::Main.act { go_to_profile_settings } + Page::Menu::Profile.act { click_access_tokens } + + Page::Profile::PersonalAccessTokens.perform do |page| + page.fill_token_name(name || 'api-test-token') + page.check_api + page.create_token + end + end + end + end + end +end diff --git a/qa/qa/page/README.md b/qa/qa/page/README.md index f72fbfeafca..83710606d7c 100644 --- a/qa/qa/page/README.md +++ b/qa/qa/page/README.md @@ -77,7 +77,7 @@ module Page view 'app/views/devise/sessions/_new_base.html.haml' do element :login_field, 'text_field :login' - element :passowrd_field, 'password_field :password' + element :password_field, 'password_field :password' element :sign_in_button, 'submit "Sign in"' end @@ -103,6 +103,16 @@ view 'app/views/my/view.html.haml' do end ``` +## Running the test locally + +During development, you can run the `qa:selectors` test by running + +```shell +bin/qa Test::Sanity::Selectors +``` + +from within the `qa` directory. + ## Where to ask for help? If you need more information, ask for help on `#qa` channel on Slack (GitLab diff --git a/qa/qa/page/menu/main.rb b/qa/qa/page/menu/main.rb index f8978b8a5f7..df93a5fa2d2 100644 --- a/qa/qa/page/menu/main.rb +++ b/qa/qa/page/menu/main.rb @@ -7,6 +7,7 @@ module QA element :user_avatar element :user_menu, '.dropdown-menu-nav' element :user_sign_out_link, 'link_to "Sign out"' + element :settings_link, 'link_to "Settings"' end view 'app/views/layouts/nav/_dashboard.html.haml' do @@ -40,7 +41,13 @@ module QA def sign_out within_user_menu do - click_link('Sign out') + click_link 'Sign out' + end + end + + def go_to_profile_settings + within_user_menu do + click_link 'Settings' end end diff --git a/qa/qa/page/menu/profile.rb b/qa/qa/page/menu/profile.rb new file mode 100644 index 00000000000..95e88d863e4 --- /dev/null +++ b/qa/qa/page/menu/profile.rb @@ -0,0 +1,27 @@ +module QA + module Page + module Menu + class Profile < Page::Base + view 'app/views/layouts/nav/sidebar/_profile.html.haml' do + element :access_token_link, 'link_to profile_personal_access_tokens_path' + element :access_token_title, 'Access Tokens' + element :top_level_items, '.sidebar-top-level-items' + end + + def click_access_tokens + within_sidebar do + click_link('Access Tokens') + end + end + + private + + def within_sidebar + page.within('.sidebar-top-level-items') do + yield + end + end + end + end + end +end diff --git a/qa/qa/page/profile/personal_access_tokens.rb b/qa/qa/page/profile/personal_access_tokens.rb new file mode 100644 index 00000000000..f5ae47dadd0 --- /dev/null +++ b/qa/qa/page/profile/personal_access_tokens.rb @@ -0,0 +1,33 @@ +module QA + module Page + module Profile + class PersonalAccessTokens < Page::Base + view 'app/views/shared/_personal_access_tokens_form.html.haml' do + element :personal_access_token_name_field, 'text_field :name' + element :create_token_button, 'submit "Create #{type} token"' # rubocop:disable Lint/InterpolationCheck + element :scopes_api_radios, "label :scopes" + end + + view 'app/views/profiles/personal_access_tokens/index.html.haml' do + element :create_token_field, "text_field_tag 'created-personal-access-token'" + end + + def fill_token_name(name) + fill_in 'personal_access_token_name', with: name + end + + def check_api + check 'personal_access_token_scopes_api' + end + + def create_token + click_on 'Create personal access token' + end + + def created_access_token + page.find('#created-personal-access-token').value + end + end + end + end +end diff --git a/qa/qa/runtime/address.rb b/qa/qa/runtime/address.rb new file mode 100644 index 00000000000..ffad3974b02 --- /dev/null +++ b/qa/qa/runtime/address.rb @@ -0,0 +1,20 @@ +module QA + module Runtime + class Address + attr_reader :address + + def initialize(instance, page = nil) + @instance = instance + @address = host + (page.is_a?(String) ? page : page&.path) + end + + def host + if @instance.is_a?(Symbol) + Runtime::Scenario.send("#{@instance}_address") + else + @instance.to_s + end + end + end + end +end diff --git a/qa/qa/runtime/api.rb b/qa/qa/runtime/api.rb new file mode 100644 index 00000000000..e2a096b971d --- /dev/null +++ b/qa/qa/runtime/api.rb @@ -0,0 +1,82 @@ +require 'airborne' + +module QA + module Runtime + module API + class Client + attr_reader :address + + def initialize(address = :gitlab) + @address = address + end + + def personal_access_token + @personal_access_token ||= get_personal_access_token + end + + def get_personal_access_token + # you can set the environment variable PERSONAL_ACCESS_TOKEN + # to use a specific access token rather than create one from the UI + if Runtime::Env.personal_access_token + Runtime::Env.personal_access_token + else + create_personal_access_token + end + end + + private + + def create_personal_access_token + Runtime::Browser.visit(@address, Page::Main::Login) do + Page::Main::Login.act { sign_in_using_credentials } + Factory::Resource::PersonalAccessToken.fabricate!.access_token + end + end + end + + class Request + API_VERSION = 'v4'.freeze + + def initialize(api_client, path, personal_access_token: nil) + personal_access_token ||= api_client.personal_access_token + request_path = request_path(path, personal_access_token: personal_access_token) + @session_address = Runtime::Address.new(api_client.address, request_path) + end + + def url + @session_address.address + end + + # Prepend a request path with the path to the API + # + # path - Path to append + # + # Examples + # + # >> request_path('/issues') + # => "/api/v4/issues" + # + # >> request_path('/issues', personal_access_token: 'sometoken) + # => "/api/v4/issues?private_token=..." + # + # Returns the relative path to the requested API resource + def request_path(path, version: API_VERSION, personal_access_token: nil, oauth_access_token: nil) + full_path = File.join('/api', version, path) + + if oauth_access_token + query_string = "access_token=#{oauth_access_token}" + elsif personal_access_token + query_string = "private_token=#{personal_access_token}" + end + + if query_string + full_path << (path.include?('?') ? '&' : '?') + full_path << query_string + end + + full_path + end + end + end + end +end diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 14b2a488760..7b1be3d5ef3 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -24,9 +24,7 @@ module QA # based on `Runtime::Scenario#something_address`. # def visit(address, page, &block) - Browser::Session.new(address, page).tap do |session| - session.perform(&block) - end + Browser::Session.new(address, page).perform(&block) end def self.visit(address, page, &block) @@ -94,20 +92,15 @@ module QA include Capybara::DSL def initialize(instance, page = nil) - @instance = instance - @address = host + page&.path + @session_address = Runtime::Address.new(instance, page) end - def host - if @instance.is_a?(Symbol) - Runtime::Scenario.send("#{@instance}_address") - else - @instance.to_s - end + def url + @session_address.address end def perform(&block) - visit(@address) + visit(url) yield if block_given? rescue @@ -130,7 +123,7 @@ module QA # See gitlab-org/gitlab-qa#102 # def clear! - visit(@address) + visit(url) reset_session! end end diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb index d5c28e9a7db..56944e8b641 100644 --- a/qa/qa/runtime/env.rb +++ b/qa/qa/runtime/env.rb @@ -3,6 +3,7 @@ module QA module Env extend self + # set to 'false' to have Chrome run visibly instead of headless def chrome_headless? (ENV['CHROME_HEADLESS'] =~ /^(false|no|0)$/i) != 0 end @@ -10,6 +11,11 @@ module QA def running_in_ci? ENV['CI'] || ENV['CI_SERVER'] end + + # specifies token that can be used for the api + def personal_access_token + ENV['PERSONAL_ACCESS_TOKEN'] + end end end end diff --git a/qa/qa/specs/features/api/users_spec.rb b/qa/qa/specs/features/api/users_spec.rb new file mode 100644 index 00000000000..9d039590a0e --- /dev/null +++ b/qa/qa/specs/features/api/users_spec.rb @@ -0,0 +1,42 @@ +module QA + feature 'API users', :core do + before(:context) do + @api_client = Runtime::API::Client.new(:gitlab) + end + + context 'when authenticated' do + let(:request) { Runtime::API::Request.new(@api_client, '/users') } + + scenario 'get list of users' do + get request.url + + expect_status(200) + end + + scenario 'submit request with a valid user name' do + get request.url, { params: { username: 'root' } } + + expect_status(200) + expect(json_body).to be_an Array + expect(json_body.size).to eq(1) + expect(json_body.first[:username]).to eq Runtime::User.name + end + + scenario 'submit request with an invalid user name' do + get request.url, { params: { username: 'invalid' } } + + expect_status(200) + expect(json_body).to be_an Array + expect(json_body.size).to eq(0) + end + end + + scenario 'submit request with an invalid token' do + request = Runtime::API::Request.new(@api_client, '/users', personal_access_token: 'invalid') + + get request.url + + expect_status(401) + end + end +end |