diff options
Diffstat (limited to 'spec/features/issues')
11 files changed, 232 insertions, 84 deletions
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 91f0e983fa8..aa61aff3b05 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -14,9 +14,6 @@ RSpec.describe 'Issues > Labels bulk assignment' do context 'as an allowed user', :js do before do - # Make sure that issuables list FF is not turned on. - stub_feature_flags(vue_issuables_list: false) - project.add_maintainer(user) sign_in user diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 6fc648954b4..12682905559 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -8,10 +8,14 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j let(:merge_request) { create(:merge_request, source_project: project) } let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } - def resolve_all_discussions_link_selector - text = "Resolve all threads in new issue" + def resolve_all_discussions_link_selector(title: "") url = new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) - %Q{a[title="#{text}"][href="#{url}"]} + + if title.empty? + %Q{a[href="#{url}"]} + else + %Q{a[title="#{title}"][href="#{url}"]} + end end describe 'as a user with access to the project' do @@ -23,7 +27,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j it 'shows a button to resolve all threads by creating a new issue' do within('.line-resolve-all-container') do - expect(page).to have_selector resolve_all_discussions_link_selector + expect(page).to have_selector resolve_all_discussions_link_selector( title: "Resolve all threads in new issue" ) end end @@ -34,6 +38,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j it 'hides the link for creating a new issue' do expect(page).not_to have_selector resolve_all_discussions_link_selector + expect(page).not_to have_content "Resolve all threads in new issue" end end @@ -57,7 +62,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'does not show a link to create a new issue' do - expect(page).not_to have_link 'Create an issue to resolve them later' + expect(page).not_to have_link 'Resolve all threads in new issue' end end @@ -67,18 +72,20 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'shows a warning that the merge request contains unresolved threads' do - expect(page).to have_content 'There are unresolved threads.' + expect(page).to have_content 'Before this can be merged,' end it 'has a link to resolve all threads by creating an issue' do page.within '.mr-widget-body' do - expect(page).to have_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + expect(page).to have_link 'Resolve all threads in new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) end end context 'creating an issue for threads' do before do - page.click_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + page.within '.mr-widget-body' do + page.click_link 'Resolve all threads in new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + end end it_behaves_like 'creating an issue for a thread' diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 85b7a093536..61c1e35f3c8 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Recent searches', :js do include FilteredSearchHelpers + include MobileHelpers let(:project_1) { create(:project, :public) } let(:project_2) { create(:project, :public) } @@ -104,4 +105,24 @@ RSpec.describe 'Recent searches', :js do expect(find('.flash-alert')).to have_text('An error occurred while parsing recent searches') end + + context 'on tablet/mobile screen' do + it 'shows only the history icon in the dropdown' do + resize_screen_sm + visit project_issues_path(project_1) + + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('svg', visible: true) + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('span', text: 'Recent searches', visible: false) + end + end + + context 'on PC screen' do + it 'shows only the Recent searches text in the dropdown' do + restore_window_size + visit project_issues_path(project_1) + + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('svg', visible: false) + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('span', text: 'Recent searches', visible: true) + end + end end diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 59588978a8e..c585d7f6194 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -53,7 +53,7 @@ RSpec.describe 'Visual tokens', :js do end it 'ends editing mode when document is clicked' do - find('#content-body').click + find('.js-navbar').click expect_filtered_search_input_empty expect(page).to have_css('#js-dropdown-author', visible: false) @@ -142,7 +142,7 @@ RSpec.describe 'Visual tokens', :js do it 'does not tokenize incomplete token' do filtered_search.send_keys('author:=') - find('body').click + find('.js-navbar').click token = page.all('.tokens-container .js-visual-token')[1] expect_filtered_search_input_empty diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 0b2e8013304..3757985f99c 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -487,7 +487,7 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - find('.tribute-container .highlight').click + find('.tribute-container .highlight', visible: true).click click_button 'Save changes' @@ -501,30 +501,36 @@ RSpec.describe 'GFM autocomplete', :js do find('#note-body').native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) end - it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do + it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do + issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)<img src=x onerror=alert(1)>' + create(:issue, project: project, title: issue_xss_title) + page.within '.timeline-content-form' do - find('#note-body').native.send_keys('@ev') + find('#note-body').native.send_keys('#') end wait_for_requests - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) page.within '.tribute-container ul' do - expect(find('li').text).to have_content(user_xss.username) + expect(page.all('li').first.text).to include(issue_xss_title) end end - it 'doesnt open autocomplete menu character is prefixed with text' do + it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do page.within '.timeline-content-form' do - find('#note-body').native.send_keys('testing') - find('#note-body').native.send_keys('@') + find('#note-body').native.send_keys('@ev') end - expect(page).not_to have_selector('.tribute-container') + wait_for_requests + + expect(page).to have_selector('.tribute-container', visible: true) + + expect(find('.tribute-container ul', visible: true).text).to have_content(user_xss.username) end it 'selects the first item for assignee dropdowns' do @@ -532,11 +538,11 @@ RSpec.describe 'GFM autocomplete', :js do find('#note-body').native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) wait_for_requests - expect(find('.tribute-container ul')).to have_selector('.highlight:first-of-type') + expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type') end it 'includes items for assignee dropdowns with non-ASCII characters in name' do @@ -545,14 +551,26 @@ RSpec.describe 'GFM autocomplete', :js do simulate_input('#note-body', "@#{user.name[0...8]}") end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) wait_for_requests - expect(find('.tribute-container')).to have_content(user.name) + expect(find('.tribute-container ul', visible: true)).to have_content(user.name) end context 'if a selected value has special characters' do + it 'wraps the result in double quotes' do + note = find('#note-body') + page.within '.timeline-content-form' do + find('#note-body').native.send_keys('') + simulate_input('#note-body', "~#{label.title[0]}") + end + + label_item = find('.tribute-container ul', text: label.title, visible: true) + + expect_to_wrap(true, label_item, note, label.title) + end + it "shows dropdown after a new line" do note = find('#note-body') page.within '.timeline-content-form' do @@ -562,7 +580,7 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) end it "does not show dropdown when preceded with a special character" do @@ -571,12 +589,21 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys("@") end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) page.within '.timeline-content-form' do note.native.send_keys("@") end + expect(page).not_to have_selector('.tribute-container') + end + + it "does not throw an error if no labels exist" do + note = find('#note-body') + page.within '.timeline-content-form' do + note.native.send_keys('~') + end + expect(page).to have_selector('.tribute-container', visible: false) end @@ -586,7 +613,7 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys("@#{user.username[0]}") end - user_item = find('.tribute-container li', text: user.username) + user_item = find('.tribute-container ul', text: user.username, visible: true) expect_to_wrap(false, user_item, note, user.username) end @@ -611,7 +638,7 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - user_item = find('.tribute-container li', text: user.username) + user_item = find('.tribute-container ul', text: user.username, visible: true) expect(user_item).to have_content(user.username) end end @@ -640,8 +667,139 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - expect(find('.tribute-container ul')).not_to have_content(user.username) - expect(find('.tribute-container ul')).to have_content(unassigned_user.username) + expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username) + expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username) + end + + it 'lists users who are currently not assigned to the issue when using /assign on the second line' do + visit project_issue_path(project, issue_assignee) + + note = find('#note-body') + page.within '.timeline-content-form' do + note.native.send_keys('/assign @user2') + note.native.send_keys(:enter) + note.native.send_keys('/assign @') + note.native.send_keys(:right) + end + + wait_for_requests + + expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username) + expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username) + end + end + + context 'labels' do + it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do + label_xss_title = 'alert label <img src=x onerror="alert(\'Hello xss\');" a' + create(:label, project: project, title: label_xss_title) + + note = find('#note-body') + + # It should show all the labels on "~". + type(note, '~') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('alert label') + end + + it 'allows colons when autocompleting scoped labels' do + create(:label, project: project, title: 'scoped:label') + + note = find('#note-body') + type(note, '~scoped:') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('scoped:label') + end + + it 'allows colons when autocompleting scoped labels with double colons' do + create(:label, project: project, title: 'scoped::label') + + note = find('#note-body') + type(note, '~scoped::') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('scoped::label') + end + + it 'autocompletes multi-word labels' do + create(:label, project: project, title: 'Accepting merge requests') + + note = find('#note-body') + type(note, '~Acceptingmerge') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('Accepting merge requests') + end + + it 'only autocompletes the latest label' do + create(:label, project: project, title: 'documentation') + create(:label, project: project, title: 'feature') + + note = find('#note-body') + type(note, '~documentation foo bar ~feat') + note.native.send_keys(:right) + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('feature') + expect(find('.tribute-container ul', visible: true).text).not_to have_content('documentation') + end + + it 'does not autocomplete labels if no tilde is typed' do + create(:label, project: project, title: 'documentation') + + note = find('#note-body') + type(note, 'document') + + wait_for_requests + + expect(page).not_to have_selector('.tribute-container') + end + end + + context 'when other notes are destroyed' do + let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) } + + # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 + it 'keeps autocomplete key listeners' do + visit project_issue_path(project, issue) + note = find('#note-body') + + start_comment_with_emoji(note) + + start_and_cancel_discussion + + note.fill_in(with: '') + start_comment_with_emoji(note) + note.native.send_keys(:enter) + + expect(note.value).to eql('Hello :100: ') + end + + def start_comment_with_emoji(note) + note.native.send_keys('Hello :10') + + wait_for_requests + + find('.atwho-view li', text: '100') + end + + def start_and_cancel_discussion + click_button('Reply...') + + fill_in('note_note', with: 'Whoops!') + + page.accept_alert 'Are you sure you want to cancel creating this comment?' do + click_button('Cancel') + end + + wait_for_requests end end end diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb index 0995aa11654..2912ac33625 100644 --- a/spec/features/issues/service_desk_spec.rb +++ b/spec/features/issues/service_desk_spec.rb @@ -7,8 +7,6 @@ RSpec.describe 'Service Desk Issue Tracker', :js do let(:user) { create(:user) } before do - stub_feature_flags(vue_issuables_list: false) - allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true) allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true) @@ -78,11 +76,9 @@ RSpec.describe 'Service Desk Issue Tracker', :js do context 'when service desk has been activated' do context 'when there are no issues' do describe 'service desk info content' do - before do + it 'displays the large info box, documentation, and the address' do visit service_desk_project_issues_path(project) - end - it 'displays the large info box, documentation, and the address' do aggregate_failures do expect(page).to have_css('.empty-state') expect(page).to have_link('Read more', href: help_page_path('user/project/service_desk')) diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index dfe3a1bf1b3..eb78e4e2456 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -8,7 +8,6 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do let!(:user) { create(:user)} before do - stub_feature_flags(vue_issuables_list: false) project.add_maintainer(user) sign_in(user) end @@ -52,7 +51,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do click_update_issues_button page.within('.issue .controls') do - expect(find('.author-link')["title"]).to have_content(user.name) + expect(find('.author-link')['href']).to have_content(user.website_url) end end @@ -83,13 +82,15 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do find('.dropdown-menu-milestone a', text: milestone.title).click click_update_issues_button - expect(find('.issue')).to have_content milestone.title + expect(page.find('.issue')).to have_content milestone.title end it 'sets to no milestone' do create_with_milestone visit project_issues_path(project) + wait_for_requests + expect(first('.issue')).to have_content milestone.title click_button 'Edit issues' diff --git a/spec/features/issues/user_filters_issues_spec.rb b/spec/features/issues/user_filters_issues_spec.rb index 54a600910ef..1b246181523 100644 --- a/spec/features/issues/user_filters_issues_spec.rb +++ b/spec/features/issues/user_filters_issues_spec.rb @@ -2,13 +2,11 @@ require 'spec_helper' -RSpec.describe 'User filters issues' do +RSpec.describe 'User filters issues', :js do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project_empty_repo, :public) } before do - stub_feature_flags(vue_issuables_list: false) - %w[foobar barbaz].each do |title| create(:issue, author: user, diff --git a/spec/features/issues/user_sees_empty_state_spec.rb b/spec/features/issues/user_sees_empty_state_spec.rb index e39369b0150..b43ba01606a 100644 --- a/spec/features/issues/user_sees_empty_state_spec.rb +++ b/spec/features/issues/user_sees_empty_state_spec.rb @@ -2,14 +2,10 @@ require 'spec_helper' -RSpec.describe 'Issues > User sees empty state' do +RSpec.describe 'Issues > User sees empty state', :js do let_it_be(:project) { create(:project, :public) } let_it_be(:user) { project.creator } - before do - stub_feature_flags(vue_issuables_list: false) - end - shared_examples_for 'empty state with filters' do it 'user sees empty state with filters' do create(:issue, author: user, project: project) diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index 91c6419b464..f0bb055c6f2 100644 --- a/spec/features/issues/user_sorts_issues_spec.rb +++ b/spec/features/issues/user_sorts_issues_spec.rb @@ -16,8 +16,6 @@ RSpec.describe "User sorts issues" do let_it_be(:later_due_milestone) { create(:milestone, project: project, due_date: '2013-12-12') } before do - stub_feature_flags(vue_issuables_list: false) - create_list(:award_emoji, 2, :upvote, awardable: issue1) create_list(:award_emoji, 2, :downvote, awardable: issue2) create(:award_emoji, :downvote, awardable: issue1) @@ -48,7 +46,7 @@ RSpec.describe "User sorts issues" do expect(find('.issues-filters a.is-active')).to have_content('Milestone') end - it "sorts by popularity" do + it 'sorts by popularity', :js do find('.filter-dropdown-container .dropdown').click page.within('ul.dropdown-menu.dropdown-menu-right li') do @@ -70,14 +68,14 @@ RSpec.describe "User sorts issues" do end end - it 'sorts by newest' do + it 'sorts by newest', :js do visit project_issues_path(project, sort: sort_value_created_date) expect(first_issue).to include('foo') expect(last_issue).to include('baz') end - it 'sorts by most recently updated' do + it 'sorts by most recently updated', :js do issue3.updated_at = Time.now + 100 issue3.save visit project_issues_path(project, sort: sort_value_recently_updated) @@ -85,7 +83,7 @@ RSpec.describe "User sorts issues" do expect(first_issue).to include('baz') end - describe 'sorting by due date' do + describe 'sorting by due date', :js do before do issue1.update(due_date: 1.day.from_now) issue2.update(due_date: 6.days.from_now) @@ -122,7 +120,7 @@ RSpec.describe "User sorts issues" do end end - describe 'filtering by due date' do + describe 'filtering by due date', :js do before do issue1.update(due_date: 1.day.from_now) issue2.update(due_date: 6.days.from_now) @@ -205,7 +203,7 @@ RSpec.describe "User sorts issues" do end end - describe 'sorting by milestone' do + describe 'sorting by milestone', :js do before do issue1.milestone = newer_due_milestone issue1.save @@ -221,7 +219,7 @@ RSpec.describe "User sorts issues" do end end - describe 'combine filter and sort' do + describe 'combine filter and sort', :js do let(:user2) { create(:user) } before do diff --git a/spec/features/issues/user_views_issues_spec.rb b/spec/features/issues/user_views_issues_spec.rb index 34cea7f3b0b..165f4b10cff 100644 --- a/spec/features/issues/user_views_issues_spec.rb +++ b/spec/features/issues/user_views_issues_spec.rb @@ -10,10 +10,6 @@ RSpec.describe "User views issues" do let_it_be(:user) { create(:user) } - before do - stub_feature_flags(vue_issuables_list: false) - end - shared_examples "opens issue from list" do it "opens issue" do click_link(issue.title) @@ -112,7 +108,7 @@ RSpec.describe "User views issues" do end end - context "when signed in as developer" do + context "when signed in as developer", :js do before do project.add_developer(user) sign_in(user) @@ -122,27 +118,7 @@ RSpec.describe "User views issues" do include_examples "internal project" end - context "when not signed in" do + context "when not signed in", :js do include_examples "public project" end - - context 'when vue_issuables_list feature is enabled', :js do - before do - stub_feature_flags(vue_issuables_list: true) - end - - context 'when signed in' do - before do - project.add_developer(user) - sign_in(user) - end - - include_examples "public project" - include_examples "internal project" - end - - context 'when not signed in' do - include_examples "public project" - end - end end |