diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-17 19:05:49 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-17 19:05:49 +0300 |
commit | 43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch) | |
tree | dceebdc68925362117480a5d672bcff122fb625b /spec/support/shared_examples/features | |
parent | 20c84b99005abd1c82101dfeff264ac50d2df211 (diff) |
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'spec/support/shared_examples/features')
33 files changed, 1200 insertions, 417 deletions
diff --git a/spec/support/shared_examples/features/2fa_shared_examples.rb b/spec/support/shared_examples/features/2fa_shared_examples.rb index 44f30c32472..6c4e98c9989 100644 --- a/spec/support/shared_examples/features/2fa_shared_examples.rb +++ b/spec/support/shared_examples/features/2fa_shared_examples.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true RSpec.shared_examples 'hardware device for 2fa' do |device_type| - include Spec::Support::Helpers::Features::TwoFactorHelpers + include Features::TwoFactorHelpers include Spec::Support::Helpers::ModalHelpers def register_device(device_type, **kwargs) case device_type.downcase - when "u2f" - register_u2f_device(**kwargs) when "webauthn" register_webauthn_device(**kwargs) else @@ -98,9 +96,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type| end it 'provides a button that shows the fallback otp code UI' do - expect(page).to have_link('Sign in via 2FA code') - - click_link('Sign in via 2FA code') + click_button(_('Sign in via 2FA code')) assert_fallback_ui(page) end diff --git a/spec/support/shared_examples/features/abuse_report_shared_examples.rb b/spec/support/shared_examples/features/abuse_report_shared_examples.rb new file mode 100644 index 00000000000..ea9b4e9f4b2 --- /dev/null +++ b/spec/support/shared_examples/features/abuse_report_shared_examples.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'reports the user with an abuse category' do + it 'creates abuse report' do + click_button 'Report abuse' + choose "They're posting spam." + click_button 'Next' + + page.attach_file('spec/fixtures/dk.png') do + click_button "Choose file" + end + + fill_in 'abuse_report_message', with: 'This user sends spam' + click_button 'Send report' + + expect(page).to have_content 'Thank you for your report' + end +end diff --git a/spec/support/shared_examples/features/access_tokens_shared_examples.rb b/spec/support/shared_examples/features/access_tokens_shared_examples.rb index 32a7b32ac72..3c78869ffaa 100644 --- a/spec/support/shared_examples/features/access_tokens_shared_examples.rb +++ b/spec/support/shared_examples/features/access_tokens_shared_examples.rb @@ -9,7 +9,7 @@ RSpec.shared_examples 'resource access tokens missing access rights' do end RSpec.shared_examples 'resource access tokens creation' do |resource_type| - include Spec::Support::Helpers::AccessTokenHelpers + include Features::AccessTokenHelpers it 'allows creation of an access token', :aggregate_failures do name = 'My access token' diff --git a/spec/support/shared_examples/features/confidential_notes_shared_examples.rb b/spec/support/shared_examples/features/confidential_notes_shared_examples.rb index 289da025af6..cd0e8f94934 100644 --- a/spec/support/shared_examples/features/confidential_notes_shared_examples.rb +++ b/spec/support/shared_examples/features/confidential_notes_shared_examples.rb @@ -3,7 +3,7 @@ require "spec_helper" RSpec.shared_examples 'confidential notes on issuables' do - include Spec::Support::Helpers::Features::NotesHelpers + include Features::NotesHelpers context 'when user does not have permissions' do it 'does not show confidential note checkbox' do diff --git a/spec/support/shared_examples/features/content_editor_shared_examples.rb b/spec/support/shared_examples/features/content_editor_shared_examples.rb index 6cd9c4ce1c4..41114197ff5 100644 --- a/spec/support/shared_examples/features/content_editor_shared_examples.rb +++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb @@ -1,116 +1,310 @@ # frozen_string_literal: true +require 'spec_helper' + RSpec.shared_examples 'edits content using the content editor' do + include ContentEditorHelpers + let(:content_editor_testid) { '[data-testid="content-editor"] [contenteditable].ProseMirror' } - def switch_to_content_editor - click_button _('View rich text') - click_button _('Rich text') - end + let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') } + let(:modifier_key) { is_mac ? :command : :control } - def type_in_content_editor(keys) - find(content_editor_testid).send_keys keys - end + it 'saves page content in local storage if the user navigates away' do + switch_to_content_editor - def open_insert_media_dropdown - page.find('svg[data-testid="media-icon"]').click - end + expect(page).to have_css(content_editor_testid) - def set_source_editor_content(content) - find('.js-gfm-input').set content - end + type_in_content_editor ' Typing text in the content editor' - def expect_formatting_menu_to_be_visible - expect(page).to have_css('[data-testid="formatting-bubble-menu"]') - end + wait_until_hidden_field_is_updated /Typing text in the content editor/ - def expect_formatting_menu_to_be_hidden - expect(page).not_to have_css('[data-testid="formatting-bubble-menu"]') - end + begin + refresh + rescue Selenium::WebDriver::Error::UnexpectedAlertOpenError + end - def expect_media_bubble_menu_to_be_visible - expect(page).to have_css('[data-testid="media-bubble-menu"]') + expect(page).to have_text('Typing text in the content editor') end - def upload_asset(fixture_name) - attach_file('content_editor_image', Rails.root.join('spec', 'fixtures', fixture_name), make_visible: true) - end + describe 'creating and editing links' do + before do + switch_to_content_editor + end - def wait_until_hidden_field_is_updated(value) - expect(page).to have_field('wiki[content]', with: value, type: 'hidden') - end + context 'when clicking the link icon in the toolbar' do + it 'shows the link bubble menu' do + page.find('[data-testid="formatting-toolbar"] [data-testid="link"]').click - it 'saves page content in local storage if the user navigates away' do - switch_to_content_editor + expect(page).to have_css('[data-testid="link-bubble-menu"]') + end - expect(page).to have_css(content_editor_testid) + context 'if no text is selected' do + before do + page.find('[data-testid="formatting-toolbar"] [data-testid="link"]').click + end + + it 'opens an empty inline modal to create a link' do + page.within '[data-testid="link-bubble-menu"]' do + expect(page).to have_field('link-text', with: '') + expect(page).to have_field('link-href', with: '') + end + end + + context 'when the user clicks the apply button' do + it 'applies the changes to the document' do + page.within '[data-testid="link-bubble-menu"]' do + fill_in 'link-text', with: 'Link to GitLab home page' + fill_in 'link-href', with: 'https://gitlab.com' + + click_button 'Apply' + end + + page.within content_editor_testid do + expect(page).to have_css('a[href="https://gitlab.com"]') + expect(page).to have_text('Link to GitLab home page') + end + end + end + + context 'when the user clicks the cancel button' do + it 'does not apply the changes to the document' do + page.within '[data-testid="link-bubble-menu"]' do + fill_in 'link-text', with: 'Link to GitLab home page' + fill_in 'link-href', with: 'https://gitlab.com' + + click_button 'Cancel' + end + + page.within content_editor_testid do + expect(page).not_to have_css('a') + end + end + end + end - type_in_content_editor ' Typing text in the content editor' + context 'if text is selected' do + before do + type_in_content_editor 'The quick brown fox jumps over the lazy dog' + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + + page.find('[data-testid="formatting-toolbar"] [data-testid="link"]').click + end + + it 'prefills inline modal to create a link' do + page.within '[data-testid="link-bubble-menu"]' do + expect(page).to have_field('link-text', with: 'dog') + expect(page).to have_field('link-href', with: '') + end + end + + context 'when the user clicks the apply button' do + it 'applies the changes to the document' do + page.within '[data-testid="link-bubble-menu"]' do + fill_in 'link-text', with: 'new dog' + fill_in 'link-href', with: 'https://en.wikipedia.org/wiki/Shiba_Inu' + + click_button 'Apply' + end + + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://en.wikipedia.org/wiki/Shiba_Inu"]', + text: 'new dog' + ) + end + end + end + end + end - wait_until_hidden_field_is_updated /Typing text in the content editor/ + context 'if cursor is placed on an existing link' do + before do + type_in_content_editor 'Link to [GitLab home **page**](https://gitlab.com)' + type_in_content_editor :left + end - refresh + it 'prefills inline modal to edit the link' do + page.within '[data-testid="link-bubble-menu"]' do + page.find('[data-testid="edit-link"]').click - expect(page).to have_text('Typing text in the content editor') + expect(page).to have_field('link-text', with: 'GitLab home page') + expect(page).to have_field('link-href', with: 'https://gitlab.com') + end + end - refresh # also retained after second refresh + it 'updates the link attributes if text is not updated' do + page.within '[data-testid="link-bubble-menu"]' do + page.find('[data-testid="edit-link"]').click - expect(page).to have_text('Typing text in the content editor') + fill_in 'link-href', with: 'https://about.gitlab.com' - click_link 'Cancel' # draft is deleted on cancel + click_button 'Apply' + end - page.go_back + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://about.gitlab.com"]') + expect(page.find('a')).to have_text('GitLab home page') + expect(page).to have_selector('strong', text: 'page') + end + end - expect(page).not_to have_text('Typing text in the content editor') - end + it 'updates the link attributes and text if text is updated' do + page.within '[data-testid="link-bubble-menu"]' do + page.find('[data-testid="edit-link"]').click - describe 'formatting bubble menu' do - it 'shows a formatting bubble menu for a regular paragraph and headings' do - switch_to_content_editor + fill_in 'link-text', with: 'GitLab about page' + fill_in 'link-href', with: 'https://about.gitlab.com' - expect(page).to have_css(content_editor_testid) + click_button 'Apply' + end - type_in_content_editor 'Typing text in the content editor' - type_in_content_editor [:shift, :left] + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://about.gitlab.com"]', + text: 'GitLab about page' + ) + expect(page).not_to have_selector('strong') + end + end - expect_formatting_menu_to_be_visible + it 'does nothing if Cancel is clicked' do + page.within '[data-testid="link-bubble-menu"]' do + page.find('[data-testid="edit-link"]').click - type_in_content_editor [:right, :right, :enter, '## Heading'] + click_button 'Cancel' + end - expect_formatting_menu_to_be_hidden + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://gitlab.com"]', + text: 'GitLab home page' + ) + expect(page).to have_selector('strong') + end + end - type_in_content_editor [:shift, :left] + context 'when the user clicks the unlink button' do + it 'removes the link' do + page.within '[data-testid="link-bubble-menu"]' do + page.find('[data-testid="remove-link"]').click + end + + page.within content_editor_testid do + expect(page).not_to have_selector('a') + expect(page).to have_selector('strong', text: 'page') + end + end + end + end + + context 'when selection spans more than a link' do + before do + type_in_content_editor 'a [b **c**](https://gitlab.com)' + + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + type_in_content_editor [:shift, :left] + + page.find('[data-testid="formatting-toolbar"] [data-testid="link"]').click + end + + it 'prefills inline modal with the entire selection' do + page.within '[data-testid="link-bubble-menu"]' do + expect(page).to have_field('link-text', with: 'a b c') + expect(page).to have_field('link-href', with: '') + end + end - expect_formatting_menu_to_be_visible + it 'expands the link and updates the link attributes if text is not updated' do + page.within '[data-testid="link-bubble-menu"]' do + fill_in 'link-href', with: 'https://about.gitlab.com' + + click_button 'Apply' + end + + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://about.gitlab.com"]') + expect(page.find('a')).to have_text('a b c') + expect(page).to have_selector('strong', text: 'c') + end + end + + it 'expands the link, updates the link attributes and text if text is updated' do + page.within '[data-testid="link-bubble-menu"]' do + fill_in 'link-text', with: 'new text' + fill_in 'link-href', with: 'https://about.gitlab.com' + + click_button 'Apply' + end + + page.within content_editor_testid do + expect(page).to have_selector('a[href="https://about.gitlab.com"]', + text: 'new text' + ) + expect(page).not_to have_selector('strong') + end + end end end - describe 'media elements bubble menu' do + describe 'selecting text' do before do switch_to_content_editor - open_insert_media_dropdown + # delete all text first + type_in_content_editor [modifier_key, 'a'] + type_in_content_editor :backspace + + type_in_content_editor 'The quick **brown** fox _jumps_ over the lazy dog!' + type_in_content_editor :enter + type_in_content_editor '[Link](https://gitlab.com)' + type_in_content_editor :enter + type_in_content_editor 'Jackdaws love my ~~big~~ sphinx of quartz!' + + # select all text + type_in_content_editor [modifier_key, 'a'] end - def test_displays_media_bubble_menu(media_element_selector, fixture_file) - upload_asset fixture_file + it 'renders selected text in a .content-editor-selection class' do + page.within content_editor_testid do + assert_selected 'The quick' + assert_selected 'brown' + assert_selected 'fox' + assert_selected 'jumps' + assert_selected 'over the lazy dog!' - wait_for_requests + assert_selected 'Link' - expect(page).to have_css(media_element_selector) + assert_selected 'Jackdaws love my' + assert_selected 'big' + assert_selected 'sphinx of quartz!' + end + end - page.find(media_element_selector).click + def assert_selected(text) + expect(page).to have_selector('.content-editor-selection', text: text) + end + end - expect_formatting_menu_to_be_hidden - expect_media_bubble_menu_to_be_visible + describe 'media elements bubble menu' do + before do + switch_to_content_editor + + click_attachment_button end it 'displays correct media bubble menu for images', :js do - test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'dk.png' + display_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'dk.png' + + expect_media_bubble_menu_to_be_visible end it 'displays correct media bubble menu for video', :js do - test_displays_media_bubble_menu '[data-testid="content_editor_editablebox"] video', 'video_sample.mp4' + display_media_bubble_menu '[data-testid="content_editor_editablebox"] video', 'video_sample.mp4' + + expect_media_bubble_menu_to_be_visible end end @@ -150,7 +344,6 @@ RSpec.shared_examples 'edits content using the content editor' do type_in_content_editor 'var a = 0' type_in_content_editor [:shift, :left] - expect_formatting_menu_to_be_hidden expect(page).to have_css('[data-testid="code-block-bubble-menu"]') end @@ -187,8 +380,8 @@ RSpec.shared_examples 'edits content using the content editor' do expect(iframe['src']).to include('/-/sandbox/mermaid') within_frame(iframe) do - expect(find('svg').text).to include('JohnDoe12') - expect(find('svg').text).to include('HelloWorld34') + expect(find('svg .nodes').text).to include('JohnDoe12') + expect(find('svg .nodes').text).to include('HelloWorld34') end expect(iframe['height'].to_i).to be > 100 @@ -198,12 +391,13 @@ RSpec.shared_examples 'edits content using the content editor' do within_frame(iframe) do page.has_content?('JaneDoe34') - expect(find('svg').text).to include('JaneDoe34') - expect(find('svg').text).to include('HelloWorld56') + expect(find('svg .nodes').text).to include('JaneDoe34') + expect(find('svg .nodes').text).to include('HelloWorld56') end end - it 'toggles the diagram when preview button is clicked' do + it 'toggles the diagram when preview button is clicked', + quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/397682' do find('[data-testid="preview-diagram"]').click expect(find(content_editor_testid)).not_to have_selector('iframe') @@ -213,8 +407,61 @@ RSpec.shared_examples 'edits content using the content editor' do iframe = find(content_editor_testid).find('iframe') within_frame(iframe) do - expect(find('svg').text).to include('JohnDoe12') - expect(find('svg').text).to include('HelloWorld34') + expect(find('svg .nodes').text).to include('JohnDoe12') + expect(find('svg .nodes').text).to include('HelloWorld34') + end + end + end + + describe 'pasting text' do + before do + switch_to_content_editor + + type_in_content_editor "Some **rich** _text_ ~~content~~ [link](https://gitlab.com)" + + type_in_content_editor [modifier_key, 'a'] + type_in_content_editor [modifier_key, 'x'] + end + + it 'pastes text with formatting if ctrl + v is pressed' do + type_in_content_editor [modifier_key, 'v'] + + page.within content_editor_testid do + expect(page).to have_selector('strong', text: 'rich') + expect(page).to have_selector('em', text: 'text') + expect(page).to have_selector('s', text: 'content') + expect(page).to have_selector('a[href="https://gitlab.com"]', text: 'link') + end + end + + it 'pastes raw text without formatting if shift + ctrl + v is pressed' do + type_in_content_editor [modifier_key, :shift, 'v'] + + page.within content_editor_testid do + expect(page).to have_text('Some rich text content link') + + expect(page).not_to have_selector('strong') + expect(page).not_to have_selector('em') + expect(page).not_to have_selector('s') + expect(page).not_to have_selector('a') + end + end + + it 'pastes raw text without formatting, stripping whitespaces, if shift + ctrl + v is pressed' do + type_in_content_editor " Some **rich**" + type_in_content_editor :enter + type_in_content_editor " _text_" + type_in_content_editor :enter + type_in_content_editor " ~~content~~" + type_in_content_editor :enter + type_in_content_editor " [link](https://gitlab.com)" + + type_in_content_editor [modifier_key, 'a'] + type_in_content_editor [modifier_key, 'x'] + type_in_content_editor [modifier_key, :shift, 'v'] + + page.within content_editor_testid do + expect(page).to have_text('Some rich text content link') end end end @@ -225,7 +472,7 @@ RSpec.shared_examples 'edits content using the content editor' do before do if defined?(project) create(:issue, project: project, title: 'My Cool Linked Issue') - create(:merge_request, source_project: project, title: 'My Cool Merge Request') + create(:merge_request, source_project: project, source_branch: 'branch-1', title: 'My Cool Merge Request') create(:label, project: project, title: 'My Cool Label') create(:milestone, project: project, title: 'My Cool Milestone') @@ -234,7 +481,7 @@ RSpec.shared_examples 'edits content using the content editor' do project = create(:project, group: group) create(:issue, project: project, title: 'My Cool Linked Issue') - create(:merge_request, source_project: project, title: 'My Cool Merge Request') + create(:merge_request, source_project: project, source_branch: 'branch-1', title: 'My Cool Merge Request') create(:group_label, group: group, title: 'My Cool Label') create(:milestone, group: group, title: 'My Cool Milestone') @@ -251,7 +498,9 @@ RSpec.shared_examples 'edits content using the content editor' do expect(find(suggestions_dropdown)).to have_text('abc123') expect(find(suggestions_dropdown)).to have_text('all') - expect(find(suggestions_dropdown)).to have_text('Group Members (2)') + expect(find(suggestions_dropdown)).to have_text('Group Members') + + type_in_content_editor 'bc' send_keys [:arrow_down, :enter] @@ -332,3 +581,23 @@ RSpec.shared_examples 'edits content using the content editor' do end end end + +RSpec.shared_examples 'inserts diagrams.net diagram using the content editor' do + include ContentEditorHelpers + + before do + switch_to_content_editor + + click_attachment_button + end + + it 'displays correct media bubble menu with edit diagram button' do + display_media_bubble_menu '[data-testid="content_editor_editablebox"] img[src]', 'diagram.drawio.svg' + + expect_media_bubble_menu_to_be_visible + + click_edit_diagram_button + + expect_drawio_editor_is_opened + end +end diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb index 96e57980c68..7e0e235698e 100644 --- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb @@ -5,20 +5,20 @@ RSpec.shared_examples 'a creatable merge request' do include ListboxHelpers it 'creates new merge request', :js do - find('.js-assignee-search').click + find('[data-testid="assignee-ids-dropdown-toggle"]').click page.within '.dropdown-menu-user' do click_link user2.name end expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s) - page.within '.js-assignee-search' do + page.within '[data-testid="assignee-ids-dropdown-toggle"]' do expect(page).to have_content user2.name end click_link 'Assign to me' expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user.id.to_s) - page.within '.js-assignee-search' do + page.within '[data-testid="assignee-ids-dropdown-toggle"]' do expect(page).to have_content user.name end diff --git a/spec/support/shared_examples/features/dashboard/sidebar_shared_examples.rb b/spec/support/shared_examples/features/dashboard/sidebar_shared_examples.rb index efbd735c451..9b5d9d66890 100644 --- a/spec/support/shared_examples/features/dashboard/sidebar_shared_examples.rb +++ b/spec/support/shared_examples/features/dashboard/sidebar_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples "a dashboard page with sidebar" do |page_path, menu_label| +RSpec.shared_examples 'a "Your work" page with sidebar and breadcrumbs' do |page_path, menu_label| before do sign_in(user) visit send(page_path) @@ -18,4 +18,13 @@ RSpec.shared_examples "a dashboard page with sidebar" do |page_path, menu_label| expect(page).to have_css(active_menu_item_css) end end + + describe "breadcrumbs" do + it 'has "Your work" as its root breadcrumb' do + breadcrumbs = page.find('[data-testid="breadcrumb-links"]') + within breadcrumbs do + expect(page).to have_css("li:first-child a[href=\"#{root_path}\"]", text: "Your work") + end + end + end end diff --git a/spec/support/shared_examples/features/deploy_token_shared_examples.rb b/spec/support/shared_examples/features/deploy_token_shared_examples.rb index 9fe08e5c996..80f5f1d805c 100644 --- a/spec/support/shared_examples/features/deploy_token_shared_examples.rb +++ b/spec/support/shared_examples/features/deploy_token_shared_examples.rb @@ -17,9 +17,11 @@ RSpec.shared_examples 'a deploy token in settings' do it 'add a new deploy token', :js do visit page_path - fill_in _('Name'), with: 'new_deploy_key' - fill_in _('Expiration date (optional)'), with: (Date.today + 1.month).to_s - fill_in _('Username (optional)'), with: 'deployer' + within('#js-deploy-tokens') do + fill_in _('Name'), with: 'new_deploy_key' + fill_in _('Expiration date (optional)'), with: (Date.today + 1.month).to_s + fill_in _('Username (optional)'), with: 'deployer' + end check 'read_repository' check 'read_registry' click_button 'Create deploy token' diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb index ea6d1655694..14e53dc8655 100644 --- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb @@ -77,15 +77,21 @@ RSpec.shared_examples 'an editable merge request' do expect(page).to have_selector('.js-quick-submit') end - it 'warns about version conflict' do + it 'warns about version conflict', :js do merge_request.update!(title: "New title") fill_in 'merge_request_title', with: 'bug 345' fill_in 'merge_request_description', with: 'bug description' - click_button 'Save changes' + click_button _('Save changes') - expect(page).to have_content 'Someone edited the merge request the same time you did' + expect(page).to have_content( + format( + _("Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."), # rubocop:disable Layout/LineLength + model_name: _('merge request'), + link_to_model: _('merge request') + ) + ) end it 'preserves description textarea height', :js do @@ -104,8 +110,8 @@ RSpec.shared_examples 'an editable merge request' do fill_in 'merge_request_description', with: long_description height = get_textarea_height - find('.js-md-preview-button').click - find('.js-md-write-button').click + click_button("Preview") + click_button("Continue editing") new_height = get_textarea_height expect(height).to eq(new_height) diff --git a/spec/support/shared_examples/features/explore/sidebar_shared_examples.rb b/spec/support/shared_examples/features/explore/sidebar_shared_examples.rb new file mode 100644 index 00000000000..1754c8bf53d --- /dev/null +++ b/spec/support/shared_examples/features/explore/sidebar_shared_examples.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'an "Explore" page with sidebar and breadcrumbs' do |page_path, menu_label| + before do + visit send(page_path) + end + + let(:sidebar_css) { 'aside.nav-sidebar[aria-label="Explore"]' } + let(:active_menu_item_css) { "li.active[data-track-label=\"#{menu_label}_menu\"]" } + + it 'shows the "Explore" sidebar' do + expect(page).to have_css(sidebar_css) + end + + it 'shows the correct sidebar menu item as active' do + within(sidebar_css) do + expect(page).to have_css(active_menu_item_css) + end + end + + describe 'breadcrumbs' do + it 'has "Explore" as its root breadcrumb' do + within '.breadcrumbs-list' do + expect(page).to have_css("li:first a[href=\"#{explore_root_path}\"]", text: 'Explore') + end + end + end +end diff --git a/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb b/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb index dab125caa60..b8e42843e6f 100644 --- a/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb +++ b/spec/support/shared_examples/features/incident_details_routing_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples 'for each incident details route' do |example, tab_text:| +RSpec.shared_examples 'for each incident details route' do |example, tab_text:, tab:| before do sign_in(user) visit incident_path @@ -25,4 +25,16 @@ RSpec.shared_examples 'for each incident details route' do |example, tab_text:| it_behaves_like example end + + context "for /-/issues/incident/:id/#{tab} route" do + let(:incident_path) { incident_project_issues_path(project, incident, tab) } + + it_behaves_like example + end + + context "for /-/issues/:id/#{tab} route" do + let(:incident_path) { incident_issue_project_issue_path(project, incident, tab) } + + it_behaves_like example + end end diff --git a/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb index 4c312b42c0a..148ff2cfb54 100644 --- a/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb +++ b/spec/support/shared_examples/features/integrations/user_activates_mattermost_slash_command_integration_shared_examples.rb @@ -8,7 +8,7 @@ RSpec.shared_examples 'user activates the Mattermost Slash Command integration' it 'shows a token placeholder' do token_placeholder = find_field('service_token')['placeholder'] - expect(token_placeholder).to eq('XXxxXXxxXXxxXXxxXXxxXXxx') + expect(token_placeholder).to eq('') end it 'redirects to the integrations page after saving but not activating' do diff --git a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb index b6f7094e422..b8c6b85adb2 100644 --- a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb +++ b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.shared_examples 'issuable invite members' do - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::InviteMembersModalHelpers context 'when a privileged user can invite' do before do @@ -17,8 +17,6 @@ RSpec.shared_examples 'issuable invite members' do page.within '.dropdown-menu-user' do expect(page).to have_link('Invite Members') - expect(page).to have_selector('[data-track-action="click_invite_members"]') - expect(page).to have_selector('[data-track-label="edit_assignee"]') end click_link 'Invite Members' diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb index b59f3f1e27b..b8fd58e7efa 100644 --- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb +++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb @@ -5,87 +5,40 @@ RSpec.shared_examples 'manage applications' do let_it_be(:application_name_changed) { "#{application_name} changed" } let_it_be(:application_redirect_uri) { 'https://foo.bar' } - context 'when hash_oauth_secrets flag set' do - before do - stub_feature_flags(hash_oauth_secrets: true) - end - - it 'allows user to manage applications', :js do - visit new_application_path + it 'allows user to manage applications', :js do + visit new_application_path - expect(page).to have_content 'Add new application' + expect(page).to have_content 'Add new application' - fill_in :doorkeeper_application_name, with: application_name - fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri - check :doorkeeper_application_scopes_read_user - click_on 'Save application' + fill_in :doorkeeper_application_name, with: application_name + fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri + check :doorkeeper_application_scopes_read_user + click_on 'Save application' - validate_application(application_name, 'Yes') - expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely') - expect(page).to have_link('Continue', href: index_path) + validate_application(application_name, 'Yes') + expect(page).to have_content _('This is the only time the secret is accessible. Copy the secret and store it securely') + expect(page).to have_link('Continue', href: index_path) - expect(page).to have_css("button[title=\"Copy secret\"]", text: 'Copy') + expect(page).to have_button(_('Copy secret')) - click_on 'Edit' + click_on 'Edit' - application_name_changed = "#{application_name} changed" + application_name_changed = "#{application_name} changed" - fill_in :doorkeeper_application_name, with: application_name_changed - uncheck :doorkeeper_application_confidential - click_on 'Save application' - - validate_application(application_name_changed, 'No') - expect(page).not_to have_link('Continue') - expect(page).to have_content _('The secret is only available when you first create the application') - - visit_applications_path - - page.within '.oauth-applications' do - click_on 'Destroy' - end - expect(page.find('.oauth-applications')).not_to have_content 'test_changed' - end - end - - context 'when hash_oauth_secrets flag not set' do - before do - stub_feature_flags(hash_oauth_secrets: false) - end - - it 'allows user to manage applications', :js do - visit new_application_path - - expect(page).to have_content 'Add new application' - - fill_in :doorkeeper_application_name, with: application_name - fill_in :doorkeeper_application_redirect_uri, with: application_redirect_uri - check :doorkeeper_application_scopes_read_user - click_on 'Save application' - - validate_application(application_name, 'Yes') - expect(page).to have_link('Continue', href: index_path) - - application = Doorkeeper::Application.find_by(name: application_name) - expect(page).to have_css("button[title=\"Copy secret\"][data-clipboard-text=\"#{application.secret}\"]", text: 'Copy') - - click_on 'Edit' - - application_name_changed = "#{application_name} changed" - - fill_in :doorkeeper_application_name, with: application_name_changed - uncheck :doorkeeper_application_confidential - click_on 'Save application' + fill_in :doorkeeper_application_name, with: application_name_changed + uncheck :doorkeeper_application_confidential + click_on 'Save application' - validate_application(application_name_changed, 'No') - expect(page).not_to have_link('Continue') + validate_application(application_name_changed, 'No') + expect(page).not_to have_link('Continue') + expect(page).to have_content _('The secret is only available when you create the application or renew the secret.') - visit_applications_path + visit_applications_path - page.within '.oauth-applications' do - click_on 'Destroy' - end - expect(page.find('.oauth-applications')).not_to have_content 'test_changed' + page.within '.oauth-applications' do + click_on 'Destroy' end + expect(page.find('.oauth-applications')).not_to have_content 'test_changed' end context 'when scopes are blank' do diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb index c2dc87b0fb0..6487e6a94c1 100644 --- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb +++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.shared_examples 'Maintainer manages access requests' do - include Spec::Support::Helpers::Features::MembersHelpers + include Features::MembersHelpers let(:user) { create(:user) } let(:maintainer) { create(:user) } diff --git a/spec/support/shared_examples/features/milestone_editing_shared_examples.rb b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb new file mode 100644 index 00000000000..d21bf62ecfa --- /dev/null +++ b/spec/support/shared_examples/features/milestone_editing_shared_examples.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'milestone handling version conflicts' do + it 'warns about version conflict when milestone has been updated in the background' do + # Update the milestone in the background in order to trigger a version conflict + milestone.update!(title: "New title") + + fill_in _('Title'), with: 'Title for version conflict' + fill_in _('Description'), with: 'Description for version conflict' + + click_button _('Save changes') + + expect(page).to have_content( + format( + _("Someone edited this %{model_name} at the same time you did. Please check out the %{link_to_model} and make sure your changes will not unintentionally remove theirs."), # rubocop:disable Layout/LineLength + model_name: _('milestone'), + link_to_model: _('milestone') + ) + ) + end +end diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb index f09cf0613a1..5126e849c2e 100644 --- a/spec/support/shared_examples/features/packages_shared_examples.rb +++ b/spec/support/shared_examples/features/packages_shared_examples.rb @@ -9,7 +9,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false| expect(package_row).to have_content(pkg.name) expect(package_row).to have_content(pkg.version) - expect(package_row).to have_content(pkg.project.name) if check_project_name + expect(package_row).to have_content(pkg.project.path) if check_project_name end end @@ -18,7 +18,35 @@ RSpec.shared_examples 'packages list' do |check_project_name: false| end end +RSpec.shared_examples 'pipelines on packages list' do + let_it_be(:pipelines) do + %w[c83d6e391c22777fca1ed3012fce84f633d7fed0 + d83d6e391c22777fca1ed3012fce84f633d7fed0].map do |sha| + create(:ci_pipeline, project: project, sha: sha) + end + end + + before do + pipelines.each do |pipeline| + create(:package_build_info, package: package, pipeline: pipeline) + end + end + + it 'shows the latest pipeline' do + # Test after reload + page.evaluate_script 'window.location.reload()' + + wait_for_requests + + expect(page).to have_content('d83d6e39') + end +end + RSpec.shared_examples 'package details link' do |property| + before do + stub_application_setting(npm_package_requests_forwarding: false) + end + it 'navigates to the correct url' do page.within(packages_table_selector) do click_link package.name @@ -30,6 +58,45 @@ RSpec.shared_examples 'package details link' do |property| expect(page).to have_content('Installation') expect(page).to have_content('Registry setup') + expect(page).to have_content('Other versions 0') + end + + context 'with other versions' do + let_it_be(:npm_package1) { create(:npm_package, project: project, name: 'zzz', version: '1.1.0') } + let_it_be(:npm_package2) { create(:npm_package, project: project, name: 'zzz', version: '1.2.0') } + + before do + page.within(packages_table_selector) do + first(:link, package.name).click + end + end + + it 'shows tab with count' do + expect(page).to have_content('Other versions 2') + end + + it 'visiting tab shows total on page' do + click_link 'Other versions' + + expect(page).to have_content('2 versions') + end + + it 'deleting version updates count' do + click_link 'Other versions' + + find('[data-testid="delete-dropdown"]', match: :first).click + find('[data-testid="action-delete"]', match: :first).click + click_button('Permanently delete') + + expect(page).to have_content 'Package deleted successfully' + + expect(page).to have_content('Other versions 1') + expect(page).to have_content('1 version') + + expect(page).not_to have_content('1.0.0') + expect(page).to have_content('1.1.0') + expect(page).to have_content('1.2.0') + end end end diff --git a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb index 81d548e000a..2d3f1949716 100644 --- a/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb +++ b/spec/support/shared_examples/features/protected_branches_access_control_ce_shared_examples.rb @@ -1,126 +1,67 @@ # frozen_string_literal: true RSpec.shared_examples "protected branches > access control > CE" do - ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)| + let(:no_one) { ProtectedRef::AccessLevel.humanize(::Gitlab::Access::NO_ACCESS) } + + ProtectedRef::AccessLevel.human_access_levels.each do |(access_type_id, access_type_name)| it "allows creating protected branches that #{access_type_name} can push to" do visit project_protected_branches_path(project) set_protected_branch_name('master') - - find(".js-allowed-to-merge").click - within('[data-testid="allowed-to-merge-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - - within('.js-new-protected-branch') do - allowed_to_push_button = find(".js-allowed-to-push") - - unless allowed_to_push_button.text == access_type_name - allowed_to_push_button.click - within(".dropdown.show .dropdown-menu") { click_on access_type_name } - end - end - + set_allowed_to('merge', no_one) + set_allowed_to('push', access_type_name) click_on_protect - wait_for_requests expect(ProtectedBranch.count).to eq(1) expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to eq([access_type_id]) end - it "allows updating protected branches so that #{access_type_name} can push to them" do + it "allows creating protected branches that #{access_type_name} can merge to" do visit project_protected_branches_path(project) set_protected_branch_name('master') - - find(".js-allowed-to-merge").click - within('[data-testid="allowed-to-merge-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - - find(".js-allowed-to-push").click - within('[data-testid="allowed-to-push-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - + set_allowed_to('merge', access_type_name) + set_allowed_to('push', no_one) click_on_protect expect(ProtectedBranch.count).to eq(1) - - within(".protected-branches-list") do - find(".js-allowed-to-push").click - - within('.js-allowed-to-push-container') do - expect(first("li")).to have_content("Roles") - find(:link, access_type_name).click - end - - find(".js-allowed-to-push").click - end - - wait_for_requests - - expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id) + expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to eq([access_type_id]) end - end - ProtectedRefAccess::HUMAN_ACCESS_LEVELS.each do |(access_type_id, access_type_name)| - it "allows creating protected branches that #{access_type_name} can merge to" do + it "allows updating protected branches so that #{access_type_name} can push to them" do visit project_protected_branches_path(project) set_protected_branch_name('master') + set_allowed_to('merge', no_one) + set_allowed_to('push', no_one) + click_on_protect - within('.js-new-protected-branch') do - allowed_to_merge_button = find(".js-allowed-to-merge") + expect(ProtectedBranch.count).to eq(1) - unless allowed_to_merge_button.text == access_type_name - allowed_to_merge_button.click - within(".dropdown.show .dropdown-menu") { click_on access_type_name } + within(".protected-branches-list") do + within_select(".js-allowed-to-push") do + click_on(access_type_name) end end - find(".js-allowed-to-push").click - within('[data-testid="allowed-to-push-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - - click_on_protect + wait_for_requests - expect(ProtectedBranch.count).to eq(1) - expect(ProtectedBranch.last.merge_access_levels.map(&:access_level)).to eq([access_type_id]) + expect(ProtectedBranch.last.push_access_levels.map(&:access_level)).to include(access_type_id) end it "allows updating protected branches so that #{access_type_name} can merge to them" do visit project_protected_branches_path(project) set_protected_branch_name('master') - - find(".js-allowed-to-merge").click - within('[data-testid="allowed-to-merge-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - - find(".js-allowed-to-push").click - within('[data-testid="allowed-to-push-dropdown"]') do - expect(first("li")).to have_content("Roles") - find(:link, 'No one').click - end - + set_allowed_to('merge', no_one) + set_allowed_to('push', no_one) click_on_protect expect(ProtectedBranch.count).to eq(1) within(".protected-branches-list") do - find(".js-allowed-to-merge").click - - within('.js-allowed-to-merge-container') do - expect(first("li")).to have_content("Roles") - find(:link, access_type_name).click + within_select(".js-allowed-to-merge") do + click_on(access_type_name) end end diff --git a/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb b/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb new file mode 100644 index 00000000000..cc0984b6226 --- /dev/null +++ b/spec/support/shared_examples/features/protected_tags_with_deploy_keys_examples.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'Deploy keys with protected tags' do + let(:dropdown_sections_minus_deploy_keys) { all_dropdown_sections - ['Deploy Keys'] } + + context 'when deploy keys are enabled to this project' do + let!(:deploy_key_1) { create(:deploy_key, title: 'title 1', projects: [project]) } + let!(:deploy_key_2) { create(:deploy_key, title: 'title 2', projects: [project]) } + + context 'when only one deploy key can push' do + before do + deploy_key_1.deploy_keys_projects.first.update!(can_push: true) + end + + it "shows all dropdown sections in the 'Allowed to create' main dropdown, with only one deploy key" do + visit project_protected_tags_path(project) + + find(".js-allowed-to-create").click + wait_for_requests + + within('[data-testid="allowed-to-create-dropdown"]') do + dropdown_headers = page.all('.dropdown-header').map(&:text) + + expect(dropdown_headers).to contain_exactly(*all_dropdown_sections) + expect(page).to have_content('title 1') + expect(page).not_to have_content('title 2') + end + end + + it "shows all sections in the 'Allowed to create' update dropdown" do + create(:protected_tag, :no_one_can_create, project: project, name: 'v1.0.0') + + visit project_protected_tags_path(project) + + within(".js-protected-tag-edit-form") do + find(".js-allowed-to-create").click + wait_for_requests + + dropdown_headers = page.all('.dropdown-header').map(&:text) + + expect(dropdown_headers).to contain_exactly(*all_dropdown_sections) + end + end + end + + context 'when no deploy key can push' do + it "just shows all sections but not deploy keys in the 'Allowed to create' dropdown" do + visit project_protected_tags_path(project) + + find(".js-allowed-to-create").click + wait_for_requests + + within('[data-testid="allowed-to-create-dropdown"]') do + dropdown_headers = page.all('.dropdown-header').map(&:text) + + expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys) + end + end + end + end +end diff --git a/spec/support/shared_examples/features/reportable_note_shared_examples.rb b/spec/support/shared_examples/features/reportable_note_shared_examples.rb index bb3fab5b23e..133da230bed 100644 --- a/spec/support/shared_examples/features/reportable_note_shared_examples.rb +++ b/spec/support/shared_examples/features/reportable_note_shared_examples.rb @@ -20,7 +20,7 @@ RSpec.shared_examples 'reportable note' do |type| dropdown = comment.find(more_actions_selector) open_dropdown(dropdown) - expect(dropdown).to have_button('Report abuse to administrator') + expect(dropdown).to have_button('Report abuse') if type == 'issue' || type == 'merge_request' expect(dropdown).to have_button('Delete comment') @@ -33,7 +33,7 @@ RSpec.shared_examples 'reportable note' do |type| dropdown = comment.find(more_actions_selector) open_dropdown(dropdown) - dropdown.click_button('Report abuse to administrator') + dropdown.click_button('Report abuse') choose "They're posting spam." click_button "Next" @@ -48,6 +48,6 @@ RSpec.shared_examples 'reportable note' do |type| restore_window_size dropdown.find('.more-actions-toggle').click - dropdown.find('.dropdown-menu li', match: :first) + dropdown.find('.more-actions li', match: :first) end end diff --git a/spec/support/shared_examples/features/rss_shared_examples.rb b/spec/support/shared_examples/features/rss_shared_examples.rb index ad865b084e1..f6566214e32 100644 --- a/spec/support/shared_examples/features/rss_shared_examples.rb +++ b/spec/support/shared_examples/features/rss_shared_examples.rb @@ -13,6 +13,12 @@ RSpec.shared_examples "it has an RSS button with current_user's feed token" do end end +RSpec.shared_examples "it has an RSS link with current_user's feed token" do + it "shows the RSS link with current_user's feed token" do + expect(page).to have_link 'Subscribe to RSS feed', href: /feed_token=#{user.feed_token}/ + end +end + RSpec.shared_examples "an autodiscoverable RSS feed without a feed token" do it "has an RSS autodiscovery link tag without a feed token" do expect(page).to have_css("link[type*='atom+xml']:not([href*='feed_token'])", visible: false) @@ -26,10 +32,18 @@ RSpec.shared_examples "it has an RSS button without a feed token" do end end +RSpec.shared_examples "it has an RSS link without a feed token" do + it "shows the RSS link without a feed token" do + expect(page).to have_link 'Subscribe to RSS feed' + expect(page).not_to have_link 'Subscribe to RSS feed', href: /feed_token/ + end +end + RSpec.shared_examples "updates atom feed link" do |type| it "for #{type}" do sign_in(user) visit path + click_button 'Actions', match: :first link = find_link('Subscribe to RSS feed') params = CGI.parse(URI.parse(link[:href]).query) diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb index 63a0832117d..7edf306183e 100644 --- a/spec/support/shared_examples/features/runners_shared_examples.rb +++ b/spec/support/shared_examples/features/runners_shared_examples.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.shared_examples 'shows and resets runner registration token' do - include Spec::Support::Helpers::Features::RunnersHelpers + include Features::RunnersHelpers include Spec::Support::Helpers::ModalHelpers before do @@ -63,16 +63,15 @@ RSpec.shared_examples 'shows and resets runner registration token' do end RSpec.shared_examples 'shows no runners registered' do - it 'shows total count with 0' do + it 'shows 0 count and the empty state' do expect(find('[data-testid="runner-type-tabs"]')).to have_text "#{s_('Runners|All')} 0" # No stats are shown expect(page).not_to have_text s_('Runners|Online') expect(page).not_to have_text s_('Runners|Offline') expect(page).not_to have_text s_('Runners|Stale') - end - it 'shows "no runners" message' do + # "no runners" message expect(page).to have_text s_('Runners|Get started with runners') end end @@ -84,16 +83,14 @@ RSpec.shared_examples 'shows no runners found' do end RSpec.shared_examples 'shows runner in list' do - it 'does not show empty state' do - expect(page).not_to have_content s_('Runners|Get started with runners') - end - - it 'shows runner row' do + it 'shows runner row and no empty state' do within_runner_row(runner.id) do expect(page).to have_text "##{runner.id}" expect(page).to have_text runner.short_sha expect(page).to have_text runner.description end + + expect(page).not_to have_content s_('Runners|Get started with runners') end end @@ -229,3 +226,33 @@ RSpec.shared_examples 'submits edit runner form' do end end end + +RSpec.shared_examples 'creates runner and shows register page' do + context 'when runner is saved' do + before do + fill_in s_('Runners|Runner description'), with: 'runner-foo' + fill_in s_('Runners|Tags'), with: 'tag1' + click_on _('Submit') + wait_for_requests + end + + it 'navigates to registration page and opens install instructions drawer' do + expect(page.find('[data-testid="alert-success"]')).to have_content(s_('Runners|Runner created.')) + expect(current_url).to match(register_path_pattern) + + click_on 'How do I install GitLab Runner?' + expect(page.find('[data-testid="runner-platforms-drawer"]')).to have_content('gitlab-runner install') + end + + it 'warns from leaving page without finishing registration' do + click_on s_('Runners|Go to runners page') + + alert = page.driver.browser.switch_to.alert + + expect(alert).not_to be_nil + alert.dismiss + + expect(current_url).to match(register_path_pattern) + end + end +end diff --git a/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb b/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb index 4d242d0e719..cbd0ffbab21 100644 --- a/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb +++ b/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb @@ -48,14 +48,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible issue' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'Issue', id: unreadable.id, ability: :read_issue } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'Issue', id: unreadable.id, ability: :read_issue } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -95,16 +99,18 @@ RSpec.shared_examples 'a redacted search results' do end let(:unredacted_results) do - ar_relation(Note, - readable_note_on_commit, - readable_diff_note, - readable_note_on_mr, - readable_diff_note_on_mr, - readable_note_on_project_snippet, - unreadable_note_on_commit, - unreadable_diff_note, - unreadable_note_on_mr, - unreadable_note_on_project_snippet) + ar_relation( + Note, + readable_note_on_commit, + readable_diff_note, + readable_note_on_mr, + readable_diff_note_on_mr, + readable_note_on_project_snippet, + unreadable_note_on_commit, + unreadable_diff_note, + unreadable_note_on_mr, + unreadable_note_on_project_snippet + ) end let(:scope) { 'notes' } @@ -112,23 +118,29 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible notes' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'Note', id: unreadable_note_on_commit.id, ability: :read_note }, - { class_name: 'DiffNote', id: unreadable_diff_note.id, ability: :read_note }, - { class_name: 'DiscussionNote', id: unreadable_note_on_mr.id, ability: :read_note }, - { class_name: 'Note', id: unreadable_note_on_project_snippet.id, ability: :read_note } - ]))) - - expect(result).to contain_exactly(readable_note_on_commit, - readable_diff_note, - readable_note_on_mr, - readable_diff_note_on_mr, - readable_note_on_project_snippet) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'Note', id: unreadable_note_on_commit.id, ability: :read_note }, + { class_name: 'DiffNote', id: unreadable_diff_note.id, ability: :read_note }, + { class_name: 'DiscussionNote', id: unreadable_note_on_mr.id, ability: :read_note }, + { class_name: 'Note', id: unreadable_note_on_project_snippet.id, ability: :read_note } + ] + ) + ) + ) + + expect(result).to contain_exactly( + readable_note_on_commit, + readable_diff_note, + readable_note_on_mr, + readable_diff_note_on_mr, + readable_note_on_project_snippet + ) end end @@ -141,14 +153,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible merge request' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'MergeRequest', id: unreadable.id, ability: :read_merge_request } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'MergeRequest', id: unreadable.id, ability: :read_merge_request } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -169,14 +185,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible blob' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'Gitlab::Search::FoundBlob', id: unreadable.id, ability: :read_blob } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'Gitlab::Search::FoundBlob', id: unreadable.id, ability: :read_blob } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -191,14 +211,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible blob' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'Gitlab::Search::FoundWikiPage', id: unreadable.id, ability: :read_wiki_page } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'Gitlab::Search::FoundWikiPage', id: unreadable.id, ability: :read_wiki_page } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -213,14 +237,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible snippet' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'ProjectSnippet', id: unreadable.id, ability: :read_snippet } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'ProjectSnippet', id: unreadable.id, ability: :read_snippet } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -239,14 +267,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible snippet' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'PersonalSnippet', id: unreadable.id, ability: :read_snippet } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'PersonalSnippet', id: unreadable.id, ability: :read_snippet } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end @@ -265,14 +297,18 @@ RSpec.shared_examples 'a redacted search results' do it 'redacts the inaccessible commit' do expect(search_service.send(:logger)) .to receive(:error) - .with(hash_including( - message: "redacted_search_results", - current_user_id: user.id, - query: search, - filtered: array_including( - [ - { class_name: 'Commit', id: unreadable.id, ability: :read_commit } - ]))) + .with( + hash_including( + message: "redacted_search_results", + current_user_id: user.id, + query: search, + filtered: array_including( + [ + { class_name: 'Commit', id: unreadable.id, ability: :read_commit } + ] + ) + ) + ) expect(result).to contain_exactly(readable) end diff --git a/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb index 028e075c87a..231406289b4 100644 --- a/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb +++ b/spec/support/shared_examples/features/secure_oauth_authorizations_shared_examples.rb @@ -10,7 +10,7 @@ RSpec.shared_examples 'Secure OAuth Authorizations' do end context 'when user is unconfirmed' do - let(:user) { create(:user, confirmed_at: nil) } + let(:user) { create(:user, :unconfirmed) } it 'displays an error' do expect(page).to have_text I18n.t('doorkeeper.errors.messages.unconfirmed_email') diff --git a/spec/support/shared_examples/features/trial_email_validation_shared_example.rb b/spec/support/shared_examples/features/trial_email_validation_shared_example.rb index 8304a91af86..81c9ac1164b 100644 --- a/spec/support/shared_examples/features/trial_email_validation_shared_example.rb +++ b/spec/support/shared_examples/features/trial_email_validation_shared_example.rb @@ -1,59 +1,38 @@ # frozen_string_literal: true RSpec.shared_examples 'user email validation' do - let(:email_hint_message) { 'We recommend a work email address.' } - let(:email_error_message) { 'Please provide a valid email address.' } + let(:email_hint_message) { _('We recommend a work email address.') } + let(:email_error_message) { _('Please provide a valid email address.') } let(:email_warning_message) do - 'This email address does not look right, are you sure you typed it correctly?' + _('This email address does not look right, are you sure you typed it correctly?') end - context 'with trial_email_validation flag enabled' do - it 'shows an error message until a correct email is entered' do - visit path - expect(page).to have_content(email_hint_message) - expect(page).not_to have_content(email_error_message) - expect(page).not_to have_content(email_warning_message) + it 'shows an error message until a correct email is entered' do + visit path + expect(page).to have_content(email_hint_message) + expect(page).not_to have_content(email_error_message) + expect(page).not_to have_content(email_warning_message) - fill_in 'new_user_email', with: 'foo@' - fill_in 'new_user_first_name', with: '' + fill_in 'new_user_email', with: 'foo@' + fill_in 'new_user_first_name', with: '' - expect(page).not_to have_content(email_hint_message) - expect(page).to have_content(email_error_message) - expect(page).not_to have_content(email_warning_message) + expect(page).not_to have_content(email_hint_message) + expect(page).to have_content(email_error_message) + expect(page).not_to have_content(email_warning_message) - fill_in 'new_user_email', with: 'foo@bar' - fill_in 'new_user_first_name', with: '' + fill_in 'new_user_email', with: 'foo@bar' + fill_in 'new_user_first_name', with: '' - expect(page).not_to have_content(email_hint_message) - expect(page).not_to have_content(email_error_message) - expect(page).to have_content(email_warning_message) + expect(page).not_to have_content(email_hint_message) + expect(page).not_to have_content(email_error_message) + expect(page).to have_content(email_warning_message) - fill_in 'new_user_email', with: 'foo@gitlab.com' - fill_in 'new_user_first_name', with: '' + fill_in 'new_user_email', with: 'foo@gitlab.com' + fill_in 'new_user_first_name', with: '' - expect(page).not_to have_content(email_hint_message) - expect(page).not_to have_content(email_error_message) - expect(page).not_to have_content(email_warning_message) - end - end - - context 'when trial_email_validation flag disabled' do - before do - stub_feature_flags trial_email_validation: false - end - - it 'does not show an error message' do - visit path - expect(page).to have_content(email_hint_message) - expect(page).not_to have_content(email_error_message) - expect(page).not_to have_content(email_warning_message) - - fill_in 'new_user_email', with: 'foo@' - - expect(page).to have_content(email_hint_message) - expect(page).not_to have_content(email_error_message) - expect(page).not_to have_content(email_warning_message) - end + expect(page).not_to have_content(email_hint_message) + expect(page).not_to have_content(email_error_message) + expect(page).not_to have_content(email_warning_message) end end diff --git a/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb b/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb new file mode 100644 index 00000000000..0b0c9edcb42 --- /dev/null +++ b/spec/support/shared_examples/features/variable_list_pagination_shared_examples.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'variable list pagination' do |variable_type| + first_page_count = 20 + + before do + first_page_count.times do |i| + case variable_type + when :ci_variable + create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true, project: project) + when :ci_group_variable + create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true, group: group) + else + create(variable_type, key: "test_key_#{i}", value: 'test_value', masked: true) + end + end + + visit page_path + wait_for_requests + end + + it 'can navigate between pages' do + page.within('[data-testid="ci-variable-table"]') do + expect(page.all('.js-ci-variable-row').length).to be(first_page_count) + end + + click_button 'Next' + wait_for_requests + + page.within('[data-testid="ci-variable-table"]') do + expect(page.all('.js-ci-variable-row').length).to be(1) + end + + click_button 'Previous' + wait_for_requests + + page.within('[data-testid="ci-variable-table"]') do + expect(page.all('.js-ci-variable-row').length).to be(first_page_count) + end + end + + it 'sorts variables alphabetically in ASC and DESC order' do + page.within('[data-testid="ci-variable-table"]') do + expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq(variable.key) + expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]').text).to eq('test_key_8') + end + + click_button 'Next' + wait_for_requests + + page.within('[data-testid="ci-variable-table"]') do + expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('test_key_9') + end + + page.within('[data-testid="ci-variable-table"]') do + find('.b-table-sort-icon-left').click + end + + wait_for_requests + + page.within('[data-testid="ci-variable-table"]') do + expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('test_key_9') + expect(find('.js-ci-variable-row:nth-child(20) td[data-label="Key"]').text).to eq('test_key_0') + end + end +end diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb index f0b72cfaee3..1211c9d19e6 100644 --- a/spec/support/shared_examples/features/variable_list_shared_examples.rb +++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples 'variable list' do |is_admin| +RSpec.shared_examples 'variable list' do it 'shows a list of variables' do page.within('[data-testid="ci-variable-table"]') do expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq(variable.key) @@ -256,14 +256,6 @@ RSpec.shared_examples 'variable list' do |is_admin| expect(find('[data-testid="ci-variable-protected-checkbox"]')).to be_checked end end - - it 'shows a message regarding the changed default' do - if is_admin - expect(page).to have_content 'Environment variables on this GitLab instance are configured to be protected by default' - else - expect(page).to have_content 'Environment variables are configured by your administrator to be protected by default' - end - end end context 'application setting is false' do diff --git a/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb b/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb index 7a3b94ad81d..6451c531aec 100644 --- a/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb @@ -62,7 +62,7 @@ RSpec.shared_examples 'wiki file attachments' do attach_with_dropzone(true) wait_for_requests - find('.js-md-preview-button').click + click_button("Preview") file_path = page.find('input[name="files[]"]', visible: :hidden).value link = page.find('a.no-attachment-icon')['href'] img_link = page.find('a.no-attachment-icon img')['src'] diff --git a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb index 3e285bb8ad7..ca68df9a89b 100644 --- a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb @@ -78,7 +78,7 @@ RSpec.shared_examples 'User previews wiki changes' do it_behaves_like 'relative links' do before do - click_on 'Preview' + click_button("Preview") end let(:element) { preview } @@ -88,7 +88,7 @@ RSpec.shared_examples 'User previews wiki changes' do # using two `\n` ensures we're sublist to it's own line due # to list auto-continue fill_in :wiki_content, with: "1. one\n\n - sublist\n" - click_on "Preview" + click_button("Preview") # the above generates two separate lists (not embedded) in CommonMark expect(preview).to have_content("sublist") @@ -102,7 +102,7 @@ RSpec.shared_examples 'User previews wiki changes' do [[also_do_not_linkify]] ``` HEREDOC - click_on "Preview" + click_button("Preview") expect(preview).to have_content("do_not_linkify") expect(preview).to have_content('[[do_not_linkify]]') diff --git a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb index 0334187e4b1..c1e4185e058 100644 --- a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb @@ -150,6 +150,7 @@ RSpec.shared_examples 'User updates wiki page' do end it_behaves_like 'edits content using the content editor' + it_behaves_like 'inserts diagrams.net diagram using the content editor' it_behaves_like 'autocompletes items' end diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb index a7c32932ba7..767caffd417 100644 --- a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb @@ -9,9 +9,11 @@ RSpec.shared_examples 'User views a wiki page' do let(:path) { 'image.png' } let(:wiki_page) do - create(:wiki_page, - wiki: wiki, - title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})") + create( + :wiki_page, + wiki: wiki, + title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})" + ) end before do diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb index 639eb3f2b99..21c7e2b6c75 100644 --- a/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb +++ b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb @@ -84,6 +84,44 @@ RSpec.shared_examples 'User views wiki sidebar' do expect(page).not_to have_link('View All Pages') end + it 'shows all collapse buttons in the sidebar' do + visit wiki_path(wiki) + + within('.right-sidebar') do + expect(page.all("[data-testid='chevron-down-icon']").size).to eq(3) + end + end + + it 'collapses/expands children when click collapse/expand button in the sidebar', :js do + visit wiki_path(wiki) + + within('.right-sidebar') do + first("[data-testid='chevron-down-icon']").click + (11..15).each { |i| expect(page).not_to have_content("my page #{i}") } + expect(page.all("[data-testid='chevron-down-icon']").size).to eq(1) + expect(page.all("[data-testid='chevron-right-icon']").size).to eq(1) + + first("[data-testid='chevron-right-icon']").click + (11..15).each { |i| expect(page).to have_content("my page #{i}") } + expect(page.all("[data-testid='chevron-down-icon']").size).to eq(3) + expect(page.all("[data-testid='chevron-right-icon']").size).to eq(0) + end + end + + it 'shows create child page button when hover to the page title in the sidebar', :js do + visit wiki_path(wiki) + + within('.right-sidebar') do + first_wiki_list = first("[data-testid='wiki-list']") + wiki_link = first("[data-testid='wiki-list'] a:last-of-type")['href'] + + first_wiki_list.hover + wiki_new_page_link = first("[data-testid='wiki-list'] a")['href'] + + expect(wiki_new_page_link).to eq "#{wiki_link}/%7Bnew_page_title%7D" + end + end + context 'when there are more than 15 existing pages' do before do create(:wiki_page, wiki: wiki, title: 'my page 16') diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb index 4f3d957ad71..526a56e7dab 100644 --- a/spec/support/shared_examples/features/work_items_shared_examples.rb +++ b/spec/support/shared_examples/features/work_items_shared_examples.rb @@ -1,5 +1,20 @@ # frozen_string_literal: true +RSpec.shared_examples 'work items title' do + let(:title_selector) { '[data-testid="work-item-title"]' } + + it 'successfully shows and changes the title of the work item' do + expect(work_item.reload.title).to eq work_item.title + + find(title_selector).set("Work item title") + find(title_selector).native.send_keys(:return) + + wait_for_requests + + expect(work_item.reload.title).to eq 'Work item title' + end +end + RSpec.shared_examples 'work items status' do let(:state_selector) { '[data-testid="work-item-state-select"]' } @@ -15,18 +30,110 @@ RSpec.shared_examples 'work items status' do end end -RSpec.shared_examples 'work items comments' do +RSpec.shared_examples 'work items comments' do |type| let(:form_selector) { '[data-testid="work-item-add-comment"]' } + let(:textarea_selector) { '[data-testid="work-item-add-comment"] #work-item-add-or-edit-comment' } + let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') } + let(:modifier_key) { is_mac ? :command : :control } + let(:comment) { 'Test comment' } + + def set_comment + find(form_selector).fill_in(with: comment) + end it 'successfully creates and shows comments' do - click_button 'Add a comment' + set_comment - find(form_selector).fill_in(with: "Test comment") click_button "Comment" wait_for_requests - expect(page).to have_content "Test comment" + page.within(".main-notes-list") do + expect(page).to have_content comment + end + end + + context 'for work item note actions signed in user with developer role' do + it 'shows work item note actions' do + set_comment + + click_button "Comment" + + wait_for_requests + + page.within(".main-notes-list") do + expect(page).to have_selector('[data-testid="work-item-note-actions"]') + + find('[data-testid="work-item-note-actions"]', match: :first).click + + expect(page).to have_selector('[data-testid="copy-link-action"]') + expect(page).not_to have_selector('[data-testid="assign-note-action"]') + end + end + end + + it 'successfully posts comments using shortcut and checks if textarea is blank when reinitiated' do + set_comment + + send_keys([modifier_key, :enter]) + + wait_for_requests + + page.within(".main-notes-list") do + expect(page).to have_content comment + end + + expect(find(textarea_selector)).to have_content "" + end + + context 'when using quick actions' do + it 'autocompletes quick actions common to all work item types', :aggregate_failures do + click_reply_and_enter_slash + + page.within('#at-view-commands') do + expect(page).to have_text("/title") + expect(page).to have_text("/shrug") + expect(page).to have_text("/tableflip") + expect(page).to have_text("/close") + expect(page).to have_text("/cc") + end + end + + context 'when a widget is enabled' do + before do + WorkItems::Type.default_by_type(type).widget_definitions + .find_by_widget_type(:assignees).update!(disabled: false) + end + + it 'autocompletes quick action for the enabled widget' do + click_reply_and_enter_slash + + page.within('#at-view-commands') do + expect(page).to have_text("/assign") + end + end + end + + context 'when a widget is disabled' do + before do + WorkItems::Type.default_by_type(type).widget_definitions + .find_by_widget_type(:assignees).update!(disabled: true) + end + + it 'does not autocomplete quick action for the disabled widget' do + click_reply_and_enter_slash + + page.within('#at-view-commands') do + expect(page).not_to have_text("/assign") + end + end + end + + def click_reply_and_enter_slash + find(form_selector).fill_in(with: "/") + + wait_for_all_requests + end end end @@ -39,7 +146,6 @@ RSpec.shared_examples 'work items assignees' do # submit and simulate blur to save send_keys(:enter) find("body").click - wait_for_requests expect(work_item.assignees).to include(user) @@ -47,6 +153,8 @@ RSpec.shared_examples 'work items assignees' do end RSpec.shared_examples 'work items labels' do + let(:label_title_selector) { '[data-testid="labels-title"]' } + it 'successfully assigns a label' do label = create(:label, project: work_item.project, title: "testing-label") @@ -55,8 +163,7 @@ RSpec.shared_examples 'work items labels' do # submit and simulate blur to save send_keys(:enter) - find("body").click - + find(label_title_selector).click wait_for_requests expect(work_item.labels).to include(label) @@ -83,7 +190,7 @@ RSpec.shared_examples 'work items description' do wait_for_requests - page.within('.atwho-container') do + page.within('#at-view-commands') do expect(page).to have_text("title") expect(page).to have_text("shrug") expect(page).to have_text("tableflip") @@ -125,7 +232,7 @@ RSpec.shared_examples 'work items description' do end RSpec.shared_examples 'work items invite members' do - include Spec::Support::Helpers::Features::InviteMembersModalHelper + include Features::InviteMembersModalHelpers it 'successfully assigns the current user by searching' do # The button is only when the mouse is over the input @@ -139,3 +246,143 @@ RSpec.shared_examples 'work items invite members' do end end end + +RSpec.shared_examples 'work items milestone' do + def set_milestone(milestone_dropdown, milestone_text) + milestone_dropdown.click + + find('[data-testid="work-item-milestone-dropdown"] .gl-form-input', visible: true).send_keys "\"#{milestone_text}\"" + wait_for_requests + + click_button(milestone_text) + wait_for_requests + end + + let(:milestone_dropdown_selector) { '[data-testid="work-item-milestone-dropdown"]' } + + it 'searches and sets or removes milestone for the work item' do + set_milestone(find(milestone_dropdown_selector), milestone.title) + + expect(page.find(milestone_dropdown_selector)).to have_text(milestone.title) + + set_milestone(find(milestone_dropdown_selector), 'No milestone') + + expect(page.find(milestone_dropdown_selector)).to have_text('Add to milestone') + end +end + +RSpec.shared_examples 'work items comment actions for guest users' do + context 'for guest user' do + it 'hides other actions other than copy link' do + page.within(".main-notes-list") do + expect(page).to have_selector('[data-testid="work-item-note-actions"]') + + find('[data-testid="work-item-note-actions"]', match: :first).click + + expect(page).to have_selector('[data-testid="copy-link-action"]') + expect(page).not_to have_selector('[data-testid="assign-note-action"]') + end + end + end +end + +RSpec.shared_examples 'work items notifications' do + let(:actions_dropdown_selector) { '[data-testid="work-item-actions-dropdown"]' } + let(:notifications_toggle_selector) { '[data-testid="notifications-toggle-action"] > button' } + + it 'displays toast when notification is toggled' do + find(actions_dropdown_selector).click + + page.within('[data-testid="notifications-toggle-form"]') do + expect(page).not_to have_css(".is-checked") + + find(notifications_toggle_selector).click + wait_for_requests + + expect(page).to have_css(".is-checked") + end + + page.within('.gl-toast') do + expect(find('.toast-body')).to have_content(_('Notifications turned on.')) + end + end +end + +RSpec.shared_examples 'work items todos' do + let(:todos_action_selector) { '[data-testid="work-item-todos-action"]' } + let(:todos_icon_selector) { '[data-testid="work-item-todos-icon"]' } + let(:header_section_selector) { '[data-testid="work-item-body"]' } + + def toggle_todo_action + find(todos_action_selector).click + wait_for_requests + end + + it 'adds item to the list' do + page.within(header_section_selector) do + expect(find(todos_action_selector)['aria-label']).to eq('Add a to do') + + toggle_todo_action + + expect(find(todos_action_selector)['aria-label']).to eq('Mark as done') + end + + page.within ".header-content span[aria-label='#{_('Todos count')}']" do + expect(page).to have_content '1' + end + end + + it 'marks a todo as done' do + page.within(header_section_selector) do + toggle_todo_action + toggle_todo_action + end + + expect(find(todos_action_selector)['aria-label']).to eq('Add a to do') + expect(page).to have_selector(".header-content span[aria-label='#{_('Todos count')}']", visible: :hidden) + end +end + +RSpec.shared_examples 'work items award emoji' do + let(:award_section_selector) { '[data-testid="work-item-award-list"]' } + let(:award_action_selector) { '[data-testid="award-button"]' } + let(:selected_award_action_selector) { '[data-testid="award-button"].selected' } + let(:emoji_picker_action_selector) { '[data-testid="emoji-picker"]' } + let(:basketball_emoji_selector) { 'gl-emoji[data-name="basketball"]' } + + def select_emoji + first(award_action_selector).click + + wait_for_requests + end + + it 'adds award to the work item' do + within(award_section_selector) do + select_emoji + + expect(page).to have_selector(selected_award_action_selector) + expect(first(award_action_selector)).to have_content '1' + end + end + + it 'removes award from work item' do + within(award_section_selector) do + select_emoji + + expect(first(award_action_selector)).to have_content '1' + + select_emoji + + expect(first(award_action_selector)).to have_content '0' + end + end + + it 'add custom award to the work item' do + within(award_section_selector) do + find(emoji_picker_action_selector).click + find(basketball_emoji_selector).click + + expect(page).to have_selector(basketball_emoji_selector) + end + end +end |