Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
commit9dc93a4519d9d5d7be48ff274127136236a3adb3 (patch)
tree70467ae3692a0e35e5ea56bcb803eb512a10bedb /spec/features/issues
parent4b0f34b6d759d6299322b3a54453e930c6121ff0 (diff)
Add latest changes from gitlab-org/gitlab@13-11-stable-eev13.11.0-rc43
Diffstat (limited to 'spec/features/issues')
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb4
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb6
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb6
-rw-r--r--spec/features/issues/form_spec.rb2
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb984
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb215
-rw-r--r--spec/features/issues/markdown_toolbar_spec.rb28
-rw-r--r--spec/features/issues/note_polling_spec.rb2
-rw-r--r--spec/features/issues/spam_issues_spec.rb22
-rw-r--r--spec/features/issues/user_comments_on_issue_spec.rb18
-rw-r--r--spec/features/issues/user_creates_branch_and_merge_request_spec.rb2
-rw-r--r--spec/features/issues/user_creates_confidential_merge_request_spec.rb2
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb10
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb198
-rw-r--r--spec/features/issues/user_filters_issues_spec.rb2
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb4
-rw-r--r--spec/features/issues/user_invites_from_a_comment_spec.rb25
-rw-r--r--spec/features/issues/user_sees_live_update_spec.rb2
-rw-r--r--spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb5
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb46
20 files changed, 860 insertions, 723 deletions
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index aa61aff3b05..80bf964e2ee 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -295,8 +295,8 @@ RSpec.describe 'Issues > Labels bulk assignment' do
before do
issue1.milestone = milestone
issue2.milestone = milestone
- issue1.save
- issue2.save
+ issue1.save!
+ issue2.save!
issue1.labels << bug
issue2.labels << feature
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 a4e9df604a9..34d78880991 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
@@ -18,10 +18,6 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
end
end
- before do
- stub_feature_flags(remove_resolve_note: false)
- end
-
describe 'as a user with access to the project' do
before do
project.add_maintainer(user)
@@ -37,7 +33,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j
context 'resolving the thread' do
before do
- click_button 'Resolve thread'
+ find('button[data-qa-selector="resolve_discussion_button"]').click
end
it 'hides the link for creating a new issue' do
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index 99dc71f0559..ac3471e8401 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -14,10 +14,6 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue',
"a[title=\"#{title}\"][href=\"#{url}\"]"
end
- before do
- stub_feature_flags(remove_resolve_note: false)
- end
-
describe 'As a user with access to the project' do
before do
project.add_maintainer(user)
@@ -39,7 +35,7 @@ RSpec.describe 'Resolve an open thread in a merge request by creating an issue',
context 'resolving the thread' do
before do
- click_button 'Resolve thread'
+ find('button[data-qa-selector="resolve_discussion_button"]').click
end
it 'hides the link for creating a new issue' do
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index dac066856c0..5ca20028485 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe 'New/edit issue', :js do
expect(page.all('input[name="issue[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="issue[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
- click_button 'Submit issue'
+ click_button 'Create issue'
page.within '.issuable-sidebar' do
page.within '.assignee' do
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index e6ebc37ba59..0cefbae4d37 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -3,16 +3,23 @@
require 'spec_helper'
RSpec.describe 'GFM autocomplete', :js do
- let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
- let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let_it_be(:user2) { create(:user, name: 'Marge Simpson', username: 'msimpson') }
+
let_it_be(:group) { create(:group, name: 'Ancestor') }
let_it_be(:child_group) { create(:group, parent: group, name: 'My group') }
let_it_be(:project) { create(:project, group: child_group) }
+
+ let_it_be(:issue) { create(:issue, project: project, assignees: [user]) }
let_it_be(:label) { create(:label, project: project, title: 'special+') }
+ let_it_be(:label_scoped) { create(:label, project: project, title: 'scoped::label') }
+ let_it_be(:label_with_spaces) { create(:label, project: project, title: 'Accepting merge requests') }
+ let_it_be(:snippet) { create(:project_snippet, project: project, title: 'code snippet') }
- let(:issue) { create(:issue, project: project) }
+ let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
+ let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
+ let_it_be(:label_xss_title) { 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' }
+ let_it_be(:label_xss) { create(:label, project: project, title: label_xss_title) }
before_all do
project.add_maintainer(user)
@@ -21,418 +28,366 @@ RSpec.describe 'GFM autocomplete', :js do
end
describe 'when tribute_autocomplete feature flag is off' do
- before do
- stub_feature_flags(tribute_autocomplete: false)
-
- sign_in(user)
- visit project_issue_path(project, issue)
-
- wait_for_requests
- end
-
- it 'updates issue description with GFM reference' do
- click_button 'Edit title and description'
-
- wait_for_requests
-
- fill_in 'Description', with: "@#{user.name[0...3]}"
-
- wait_for_requests
-
- find_highlighted_autocomplete_item.click
-
- click_button 'Save changes'
-
- wait_for_requests
-
- expect(find('.description')).to have_text(user.to_reference)
- end
-
- it 'opens quick action autocomplete when updating description' do
- click_button 'Edit title and description'
-
- fill_in 'Description', with: '/'
-
- expect(find_autocomplete_menu).to be_visible
- end
-
- it 'opens autocomplete menu when field starts with text' do
- fill_in 'Comment', with: '@'
-
- expect(find_autocomplete_menu).to be_visible
- end
-
- 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)&lt;img src=x onerror=alert(1)&gt;'
- create(:issue, project: project, title: issue_xss_title)
-
- fill_in 'Comment', with: '#'
-
- wait_for_requests
+ describe 'new issue page' do
+ before do
+ stub_feature_flags(tribute_autocomplete: false)
- expect(find_autocomplete_menu).to have_text(issue_xss_title)
- end
+ sign_in(user)
+ visit new_project_issue_path(project)
- it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '@ev'
+ wait_for_requests
+ end
- wait_for_requests
+ it 'allows quick actions' do
+ fill_in 'Description', with: '/'
- expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
+ expect(find_autocomplete_menu).to be_visible
+ end
end
- it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
- milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:milestone, project: project, title: milestone_xss_title)
+ describe 'issue description' do
+ let(:issue_to_edit) { create(:issue, project: project) }
- fill_in 'Comment', with: '%'
+ before do
+ stub_feature_flags(tribute_autocomplete: false)
- wait_for_requests
+ sign_in(user)
+ visit project_issue_path(project, issue_to_edit)
- expect(find_autocomplete_menu).to have_text('alert milestone')
- end
+ wait_for_requests
+ end
- it 'doesnt open autocomplete menu character is prefixed with text' do
- fill_in 'Comment', with: 'testing@'
+ it 'updates with GFM reference' do
+ click_button 'Edit title and description'
- expect(page).not_to have_css('.atwho-view')
- end
+ wait_for_requests
- it 'doesnt select the first item for non-assignee dropdowns' do
- fill_in 'Comment', with: ':'
+ fill_in 'Description', with: "@#{user.name[0...3]}"
- wait_for_requests
+ wait_for_requests
- expect(find_autocomplete_menu).not_to have_css('.cur')
- end
+ find_highlighted_autocomplete_item.click
- it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
- # Number.
- fill_in 'Comment', with: '7:'
- expect(page).not_to have_css('.atwho-view')
+ click_button 'Save changes'
- # ASCII letter.
- fill_in 'Comment', with: 'w:'
- expect(page).not_to have_css('.atwho-view')
+ wait_for_requests
- # Non-ASCII letter.
- fill_in 'Comment', with: 'Ё:'
- expect(page).not_to have_css('.atwho-view')
- end
+ expect(find('.description')).to have_text(user.to_reference)
+ end
- it 'selects the first item for assignee dropdowns' do
- fill_in 'Comment', with: '@'
+ it 'allows quick actions' do
+ click_button 'Edit title and description'
- wait_for_requests
+ fill_in 'Description', with: '/'
- expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
+ expect(find_autocomplete_menu).to be_visible
+ end
end
- it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- fill_in 'Comment', with: "@#{user.name[0...8]}"
+ describe 'issue comment' do
+ before do
+ stub_feature_flags(tribute_autocomplete: false)
- wait_for_requests
+ sign_in(user)
+ visit project_issue_path(project, issue)
- expect(find_autocomplete_menu).to have_text(user.name)
- end
+ wait_for_requests
+ end
- it 'searches across full name for assignees' do
- fill_in 'Comment', with: '@speciąlsome'
+ describe 'triggering autocomplete' do
+ it 'only opens autocomplete menu when trigger character is after whitespace', :aggregate_failures do
+ fill_in 'Comment', with: 'testing@'
+ expect(page).not_to have_css('.atwho-view')
- wait_for_requests
+ fill_in 'Comment', with: '@@'
+ expect(page).not_to have_css('.atwho-view')
- expect(find_highlighted_autocomplete_item).to have_text(user.name)
- end
+ fill_in 'Comment', with: "@#{user.username[0..2]}!"
+ expect(page).not_to have_css('.atwho-view')
- it 'shows names that start with the query as the top result' do
- fill_in 'Comment', with: '@mar'
+ fill_in 'Comment', with: "hello:#{user.username[0..2]}"
+ expect(page).not_to have_css('.atwho-view')
- wait_for_requests
+ fill_in 'Comment', with: '7:'
+ expect(page).not_to have_css('.atwho-view')
- expect(find_highlighted_autocomplete_item).to have_text(user2.name)
- end
-
- it 'shows usernames that start with the query as the top result' do
- fill_in 'Comment', with: '@msi'
+ fill_in 'Comment', with: 'w:'
+ expect(page).not_to have_css('.atwho-view')
- wait_for_requests
+ fill_in 'Comment', with: 'Ё:'
+ expect(page).not_to have_css('.atwho-view')
- expect(find_highlighted_autocomplete_item).to have_text(user2.name)
- end
+ fill_in 'Comment', with: "test\n\n@"
+ expect(find_autocomplete_menu).to be_visible
+ end
+ end
- # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925
- it 'shows username when pasting then pressing Enter' do
- fill_in 'Comment', with: "@#{user.username}\n"
+ context 'xss checks' 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)&lt;img src=x onerror=alert(1)&gt;'
+ create(:issue, project: project, title: issue_xss_title)
- expect(find_field('Comment').value).to have_text "@#{user.username}"
- end
+ fill_in 'Comment', with: '#'
- it 'does not show `@undefined` when pressing `@` then Enter' do
- fill_in 'Comment', with: "@\n"
+ wait_for_requests
- expect(find_field('Comment').value).to have_text '@'
- expect(find_field('Comment').value).not_to have_text '@undefined'
- end
+ expect(find_autocomplete_menu).to have_text(issue_xss_title)
+ end
- it 'selects the first item for non-assignee dropdowns if a query is entered' do
- fill_in 'Comment', with: ':1'
+ it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '@ev'
- wait_for_requests
+ wait_for_requests
- expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
- end
+ expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
+ end
- context 'if a selected value has special characters' do
- it 'wraps the result in double quotes' do
- fill_in 'Comment', with: "~#{label.title[0]}"
+ it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
+ milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
+ create(:milestone, project: project, title: milestone_xss_title)
- find_highlighted_autocomplete_item.click
+ fill_in 'Comment', with: '%'
- expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
- end
+ wait_for_requests
- it "shows dropdown after a new line" do
- fill_in 'Comment', with: "test\n\n@"
+ expect(find_autocomplete_menu).to have_text('alert milestone')
+ end
- expect(find_autocomplete_menu).to be_visible
- end
+ it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '~'
- it "does not show dropdown when preceded with a special character" do
- fill_in 'Comment', with: '@@'
+ wait_for_requests
- expect(page).not_to have_css('.atwho-view')
+ expect(find_autocomplete_menu).to have_text('alert label')
+ end
end
- it 'doesn\'t wrap for assignee values' do
- fill_in 'Comment', with: "@#{user.username[0]}"
+ describe 'autocomplete highlighting' do
+ it 'auto-selects the first item when there is a query, and only for assignees with no query', :aggregate_failures do
+ fill_in 'Comment', with: ':'
+ wait_for_requests
+ expect(find_autocomplete_menu).not_to have_css('.cur')
- find_highlighted_autocomplete_item.click
+ fill_in 'Comment', with: ':1'
+ wait_for_requests
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
- expect(find_field('Comment').value).to have_text("@#{user.username}")
+ fill_in 'Comment', with: '@'
+ wait_for_requests
+ expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
+ end
end
- it 'doesn\'t wrap for emoji values' do
- fill_in 'Comment', with: ':cartwheel_'
-
- find_highlighted_autocomplete_item.click
+ describe 'assignees' do
+ it 'does not wrap with quotes for assignee values' do
+ fill_in 'Comment', with: "@#{user.username[0]}"
- expect(find_field('Comment').value).to have_text('cartwheel_tone1')
- end
+ find_highlighted_autocomplete_item.click
- it 'doesn\'t open autocomplete after non-word character' do
- fill_in 'Comment', with: "@#{user.username[0..2]}!"
+ expect(find_field('Comment').value).to have_text("@#{user.username}")
+ end
- expect(page).not_to have_css('.atwho-view')
- end
+ it 'includes items for assignee dropdowns with non-ASCII characters in name' do
+ fill_in 'Comment', with: "@#{user.name[0...8]}"
- it 'doesn\'t open autocomplete if there is no space before' do
- fill_in 'Comment', with: "hello:#{user.username[0..2]}"
+ wait_for_requests
- expect(page).not_to have_css('.atwho-view')
- end
+ expect(find_autocomplete_menu).to have_text(user.name)
+ end
- it 'triggers autocomplete after selecting a quick action' do
- fill_in 'Comment', with: '/as'
+ it 'searches across full name for assignees' do
+ fill_in 'Comment', with: '@speciąlsome'
- find_highlighted_autocomplete_item.click
+ wait_for_requests
- expect(find_autocomplete_menu).to have_text(user.username)
- end
+ expect(find_highlighted_autocomplete_item).to have_text(user.name)
+ end
- it 'does not limit quick actions autocomplete list to 5' do
- fill_in 'Comment', with: '/'
+ it 'shows names that start with the query as the top result' do
+ fill_in 'Comment', with: '@mar'
- expect(find_autocomplete_menu).to have_css('li', minimum: 6)
- end
- end
+ wait_for_requests
- context 'assignees' do
- let(:issue_assignee) { create(:issue, project: project) }
- let(:unassigned_user) { create(:user) }
+ expect(find_highlighted_autocomplete_item).to have_text(user2.name)
+ end
- before do
- issue_assignee.update(assignees: [user])
+ it 'shows usernames that start with the query as the top result' do
+ fill_in 'Comment', with: '@msi'
- project.add_maintainer(unassigned_user)
- end
+ wait_for_requests
- it 'lists users who are currently not assigned to the issue when using /assign' do
- visit project_issue_path(project, issue_assignee)
+ expect(find_highlighted_autocomplete_item).to have_text(user2.name)
+ end
- fill_in 'Comment', with: '/as'
+ # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925
+ it 'shows username when pasting then pressing Enter' do
+ fill_in 'Comment', with: "@#{user.username}\n"
- find_highlighted_autocomplete_item.click
+ expect(find_field('Comment').value).to have_text "@#{user.username}"
+ end
- expect(find_autocomplete_menu).not_to have_text(user.username)
- expect(find_autocomplete_menu).to have_text(unassigned_user.username)
- end
+ it 'does not show `@undefined` when pressing `@` then Enter' do
+ fill_in 'Comment', with: "@\n"
- it 'shows dropdown on new issue form' do
- visit new_project_issue_path(project)
+ expect(find_field('Comment').value).to have_text '@'
+ expect(find_field('Comment').value).not_to have_text '@undefined'
+ end
- fill_in 'Description', with: '/ass'
+ context 'when /assign quick action is selected' do
+ it 'triggers user autocomplete and lists users who are currently not assigned to the issue' do
+ fill_in 'Comment', with: '/as'
- find_highlighted_autocomplete_item.click
+ find_highlighted_autocomplete_item.click
- expect(find_autocomplete_menu).to have_text(unassigned_user.username)
- expect(find_autocomplete_menu).to have_text(user.username)
+ expect(find_autocomplete_menu).not_to have_text(user.username)
+ expect(find_autocomplete_menu).to have_text(user2.username)
+ end
+ end
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 &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:label, project: project, title: label_xss_title)
- fill_in 'Comment', with: '~'
-
- wait_for_requests
+ context 'if a selected value has special characters' do
+ it 'wraps the result in double quotes' do
+ fill_in 'Comment', with: "~#{label.title[0..2]}"
- expect(find_autocomplete_menu).to have_text('alert label')
- end
+ find_highlighted_autocomplete_item.click
- it 'allows colons when autocompleting scoped labels' do
- create(:label, project: project, title: 'scoped:label')
+ expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
+ end
- fill_in 'Comment', with: '~scoped:'
+ it 'doesn\'t wrap for emoji values' do
+ fill_in 'Comment', with: ':cartwheel_'
- wait_for_requests
+ find_highlighted_autocomplete_item.click
- expect(find_autocomplete_menu).to have_text('scoped:label')
+ expect(find_field('Comment').value).to have_text('cartwheel_tone1')
+ end
end
- it 'allows colons when autocompleting scoped labels with double colons' do
- create(:label, project: project, title: 'scoped::label')
+ context 'quick actions' do
+ it 'does not limit quick actions autocomplete list to 5' do
+ fill_in 'Comment', with: '/'
- fill_in 'Comment', with: '~scoped::'
-
- wait_for_requests
-
- expect(find_autocomplete_menu).to have_text('scoped::label')
+ expect(find_autocomplete_menu).to have_css('li', minimum: 6)
+ end
end
- it 'allows spaces when autocompleting multi-word labels' do
- create(:label, project: project, title: 'Accepting merge requests')
+ context 'labels' do
+ it 'allows colons when autocompleting scoped labels' do
+ fill_in 'Comment', with: '~scoped:'
- fill_in 'Comment', with: '~Accepting merge'
+ wait_for_requests
- wait_for_requests
+ expect(find_autocomplete_menu).to have_text('scoped::label')
+ end
- expect(find_autocomplete_menu).to have_text('Accepting merge requests')
- end
+ it 'allows spaces when autocompleting multi-word labels' do
+ fill_in 'Comment', with: '~Accepting merge'
- it 'only autocompletes the latest label' do
- create(:label, project: project, title: 'Accepting merge requests')
- create(:label, project: project, title: 'Accepting job applicants')
+ wait_for_requests
- fill_in 'Comment', with: '~Accepting merge requests foo bar ~Accepting job'
+ expect(find_autocomplete_menu).to have_text('Accepting merge requests')
+ end
- wait_for_requests
+ it 'only autocompletes the last label' do
+ fill_in 'Comment', with: '~scoped:: foo bar ~Accepting merge'
- expect(find_autocomplete_menu).to have_text('Accepting job applicants')
- end
+ wait_for_requests
- it 'does not autocomplete labels if no tilde is typed' do
- create(:label, project: project, title: 'Accepting merge requests')
+ expect(find_autocomplete_menu).to have_text('Accepting merge requests')
+ end
- fill_in 'Comment', with: 'Accepting merge'
+ it 'does not autocomplete labels if no tilde is typed' do
+ fill_in 'Comment', with: 'Accepting merge'
- wait_for_requests
+ wait_for_requests
- expect(page).not_to have_css('.atwho-view')
+ expect(page).not_to have_css('.atwho-view')
+ end
end
- end
- context 'when other notes are destroyed' do
- let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
+ 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_field('Comment')
+ # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
+ it 'keeps autocomplete key listeners' do
+ note = find_field('Comment')
- start_comment_with_emoji(note, '.atwho-view li')
+ start_comment_with_emoji(note, '.atwho-view li')
- start_and_cancel_discussion
+ start_and_cancel_discussion
- note.fill_in(with: '')
- start_comment_with_emoji(note, '.atwho-view li')
- note.native.send_keys(:enter)
+ note.fill_in(with: '')
+ start_comment_with_emoji(note, '.atwho-view li')
+ note.native.send_keys(:enter)
- expect(note.value).to eql('Hello :100: ')
+ expect(note.value).to eql('Hello :100: ')
+ end
end
- end
- shared_examples 'autocomplete suggestions' do
- it 'suggests objects correctly' do
- fill_in 'Comment', with: object.class.reference_prefix
+ shared_examples 'autocomplete suggestions' do
+ it 'suggests objects correctly' do
+ fill_in 'Comment', with: object.class.reference_prefix
- find_autocomplete_menu.find('li').click
+ find_autocomplete_menu.find('li').click
- expect(find_field('Comment').value).to have_text(expected_body)
+ expect(find_field('Comment').value).to have_text(expected_body)
+ end
end
- end
- context 'issues' do
- let(:object) { issue }
- let(:expected_body) { object.to_reference }
+ context 'issues' do
+ let(:object) { issue }
+ let(:expected_body) { object.to_reference }
- it_behaves_like 'autocomplete suggestions'
- end
-
- context 'merge requests' do
- let(:object) { create(:merge_request, source_project: project) }
- let(:expected_body) { object.to_reference }
-
- it_behaves_like 'autocomplete suggestions'
- end
+ it_behaves_like 'autocomplete suggestions'
+ end
- context 'project snippets' do
- let!(:object) { create(:project_snippet, project: project, title: 'code snippet') }
- let(:expected_body) { object.to_reference }
+ context 'merge requests' do
+ let(:object) { create(:merge_request, source_project: project) }
+ let(:expected_body) { object.to_reference }
- it_behaves_like 'autocomplete suggestions'
- end
+ it_behaves_like 'autocomplete suggestions'
+ end
- context 'label' do
- let!(:object) { label }
- let(:expected_body) { object.title }
+ context 'project snippets' do
+ let!(:object) { snippet }
+ let(:expected_body) { object.to_reference }
- it_behaves_like 'autocomplete suggestions'
- end
+ it_behaves_like 'autocomplete suggestions'
+ end
- context 'milestone' do
- let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
- let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
- let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
- let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
- let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
+ context 'milestone' do
+ let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
+ let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
+ let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
+ let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
+ let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
- before do
- fill_in 'Comment', with: '/milestone %'
+ before do
+ fill_in 'Comment', with: '/milestone %'
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'shows milestons list in the autocomplete menu' do
- page.within(find_autocomplete_menu) do
- expect(page).to have_selector('li', count: 5)
+ it 'shows milestons list in the autocomplete menu' do
+ page.within(find_autocomplete_menu) do
+ expect(page).to have_selector('li', count: 5)
+ end
end
- end
- it 'shows expired milestone at the bottom of the list' do
- page.within(find_autocomplete_menu) do
- expect(page.find('li:last-child')).to have_content milestone_expired.title
+ it 'shows expired milestone at the bottom of the list' do
+ page.within(find_autocomplete_menu) do
+ expect(page.find('li:last-child')).to have_content milestone_expired.title
+ end
end
- end
- it 'shows milestone due earliest at the top of the list' do
- page.within(find_autocomplete_menu) do
- aggregate_failures do
- expect(page.all('li')[0]).to have_content milestone3.title
- expect(page.all('li')[1]).to have_content milestone2.title
- expect(page.all('li')[2]).to have_content milestone1.title
- expect(page.all('li')[3]).to have_content milestone_no_duedate.title
+ it 'shows milestone due earliest at the top of the list' do
+ page.within(find_autocomplete_menu) do
+ aggregate_failures do
+ expect(page.all('li')[0]).to have_content milestone3.title
+ expect(page.all('li')[1]).to have_content milestone2.title
+ expect(page.all('li')[2]).to have_content milestone1.title
+ expect(page.all('li')[3]).to have_content milestone_no_duedate.title
+ end
end
end
end
@@ -440,346 +395,303 @@ RSpec.describe 'GFM autocomplete', :js do
end
describe 'when tribute_autocomplete feature flag is on' do
- before do
- stub_feature_flags(tribute_autocomplete: true)
-
- sign_in(user)
- visit project_issue_path(project, issue)
-
- wait_for_requests
- end
+ describe 'issue description' do
+ let(:issue_to_edit) { create(:issue, project: project) }
- it 'updates issue description with GFM reference' do
- click_button 'Edit title and description'
-
- wait_for_requests
-
- fill_in 'Description', with: "@#{user.name[0...3]}"
-
- wait_for_requests
+ before do
+ stub_feature_flags(tribute_autocomplete: true)
- find_highlighted_tribute_autocomplete_menu.click
+ sign_in(user)
+ visit project_issue_path(project, issue_to_edit)
- click_button 'Save changes'
+ wait_for_requests
+ end
- wait_for_requests
+ it 'updates with GFM reference' do
+ click_button 'Edit title and description'
- expect(find('.description')).to have_text(user.to_reference)
- end
+ wait_for_requests
- it 'opens autocomplete menu when field starts with text' do
- fill_in 'Comment', with: '@'
+ fill_in 'Description', with: "@#{user.name[0...3]}"
- expect(find_tribute_autocomplete_menu).to be_visible
- end
+ wait_for_requests
- 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)&lt;img src=x onerror=alert(1)&gt;'
- create(:issue, project: project, title: issue_xss_title)
+ find_highlighted_tribute_autocomplete_menu.click
- fill_in 'Comment', with: '#'
+ click_button 'Save changes'
- wait_for_requests
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
+ expect(find('.description')).to have_text(user.to_reference)
+ end
end
- it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
- fill_in 'Comment', with: '@ev'
-
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
- end
+ describe 'issue comment' do
+ before do
+ stub_feature_flags(tribute_autocomplete: true)
- it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
- milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:milestone, project: project, title: milestone_xss_title)
+ sign_in(user)
+ visit project_issue_path(project, issue)
- fill_in 'Comment', with: '%'
+ wait_for_requests
+ end
- wait_for_requests
+ describe 'triggering autocomplete' do
+ it 'only opens autocomplete menu when trigger character is after whitespace', :aggregate_failures do
+ fill_in 'Comment', with: 'testing@'
+ expect(page).not_to have_css('.tribute-container')
- expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
- end
+ fill_in 'Comment', with: "hello:#{user.username[0..2]}"
+ expect(page).not_to have_css('.tribute-container')
- it 'does not open autocomplete menu when trigger character is prefixed with text' do
- fill_in 'Comment', with: 'testing@'
+ fill_in 'Comment', with: '7:'
+ expect(page).not_to have_css('.tribute-container')
- expect(page).not_to have_css('.tribute-container')
- end
+ fill_in 'Comment', with: 'w:'
+ expect(page).not_to have_css('.tribute-container')
- it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
- # Number.
- fill_in 'Comment', with: '7:'
- expect(page).not_to have_css('.tribute-container')
+ fill_in 'Comment', with: 'Ё:'
+ expect(page).not_to have_css('.tribute-container')
- # ASCII letter.
- fill_in 'Comment', with: 'w:'
- expect(page).not_to have_css('.tribute-container')
+ fill_in 'Comment', with: "test\n\n@"
+ expect(find_tribute_autocomplete_menu).to be_visible
+ end
+ end
- # Non-ASCII letter.
- fill_in 'Comment', with: 'Ё:'
- expect(page).not_to have_css('.tribute-container')
- end
+ context 'xss checks' 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)&lt;img src=x onerror=alert(1)&gt;'
+ create(:issue, project: project, title: issue_xss_title)
- it 'selects the first item for assignee dropdowns' do
- fill_in 'Comment', with: '@'
+ fill_in 'Comment', with: '#'
- wait_for_requests
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
- end
+ expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
+ end
- it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- fill_in 'Comment', with: "@#{user.name[0...8]}"
+ it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '@ev'
- wait_for_requests
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_text(user.name)
- end
+ expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
+ end
- it 'selects the first item for non-assignee dropdowns if a query is entered' do
- fill_in 'Comment', with: ':1'
+ it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
+ milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
+ create(:milestone, project: project, title: milestone_xss_title)
- wait_for_requests
+ fill_in 'Comment', with: '%'
- expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
- end
+ wait_for_requests
- context 'when autocompleting for groups' do
- it 'shows the group when searching for the name of the group' do
- fill_in 'Comment', with: '@mygroup'
+ expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
+ end
- expect(find_tribute_autocomplete_menu).to have_text('My group')
- end
+ it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
+ fill_in 'Comment', with: '~'
- it 'does not show the group when searching for the name of the parent of the group' do
- fill_in 'Comment', with: '@ancestor'
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).not_to have_text('My group')
+ expect(find_tribute_autocomplete_menu).to have_text('alert label')
+ end
end
- end
- context 'if a selected value has special characters' do
- it 'wraps the result in double quotes' do
- fill_in 'Comment', with: "~#{label.title[0]}"
+ describe 'autocomplete highlighting' do
+ it 'auto-selects the first item with query', :aggregate_failures do
+ fill_in 'Comment', with: ':1'
+ wait_for_requests
+ expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
- find_highlighted_tribute_autocomplete_menu.click
-
- expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
+ fill_in 'Comment', with: '@'
+ wait_for_requests
+ expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
+ end
end
- it "shows dropdown after a new line" do
- fill_in 'Comment', with: "test\n\n@"
-
- expect(find_tribute_autocomplete_menu).to be_visible
- end
+ describe 'assignees' do
+ it 'does not wrap with quotes for assignee values' do
+ fill_in 'Comment', with: "@#{user.username[0..2]}"
- it 'doesn\'t wrap for assignee values' do
- fill_in 'Comment', with: "@#{user.username[0..2]}"
+ find_highlighted_tribute_autocomplete_menu.click
- find_highlighted_tribute_autocomplete_menu.click
+ expect(find_field('Comment').value).to have_text("@#{user.username}")
+ end
- expect(find_field('Comment').value).to have_text("@#{user.username}")
- end
+ it 'includes items for assignee dropdowns with non-ASCII characters in name' do
+ fill_in 'Comment', with: "@#{user.name[0...8]}"
- it 'does not wrap for emoji values' do
- fill_in 'Comment', with: ':cartwheel_'
+ wait_for_requests
- find_highlighted_tribute_autocomplete_menu.click
+ expect(find_tribute_autocomplete_menu).to have_text(user.name)
+ end
- expect(find_field('Comment').value).to have_text('cartwheel_tone1')
- end
+ context 'when autocompleting for groups' do
+ it 'shows the group when searching for the name of the group' do
+ fill_in 'Comment', with: '@mygroup'
- it 'does not open autocomplete if there is no space before' do
- fill_in 'Comment', with: "hello:#{user.username[0..2]}"
+ expect(find_tribute_autocomplete_menu).to have_text('My group')
+ end
- expect(page).not_to have_css('.tribute-container')
- end
+ it 'does not show the group when searching for the name of the parent of the group' do
+ fill_in 'Comment', with: '@ancestor'
- it 'autocompletes for quick actions' do
- fill_in 'Comment', with: '/as'
+ expect(find_tribute_autocomplete_menu).not_to have_text('My group')
+ end
+ end
- find_highlighted_tribute_autocomplete_menu.click
+ context 'when /assign quick action is selected' do
+ it 'lists users who are currently not assigned to the issue' do
+ note = find_field('Comment')
+ note.native.send_keys('/assign ')
+ # The `/assign` ajax response might replace the one by `@` below causing a failed test
+ # so we need to wait for the `/assign` ajax request to finish first
+ wait_for_requests
+ note.native.send_keys('@')
+ wait_for_requests
+
+ expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
+ expect(find_tribute_autocomplete_menu).to have_text(user2.username)
+ end
- expect(find_field('Comment').value).to have_text('/assign')
+ it 'lists users who are currently not assigned to the issue when using /assign on the second line' do
+ note = find_field('Comment')
+ note.native.send_keys('/assign @user2')
+ note.native.send_keys(:enter)
+ note.native.send_keys('/assign ')
+ # The `/assign` ajax response might replace the one by `@` below causing a failed test
+ # so we need to wait for the `/assign` ajax request to finish first
+ wait_for_requests
+ note.native.send_keys('@')
+ wait_for_requests
+
+ expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
+ expect(find_tribute_autocomplete_menu).to have_text(user2.username)
+ end
+ end
end
- end
- context 'assignees' do
- let(:issue_assignee) { create(:issue, project: project) }
- let(:unassigned_user) { create(:user) }
+ context 'if a selected value has special characters' do
+ it 'wraps the result in double quotes' do
+ fill_in 'Comment', with: "~#{label.title[0..2]}"
- before do
- issue_assignee.update(assignees: [user])
+ find_highlighted_tribute_autocomplete_menu.click
- project.add_maintainer(unassigned_user)
- end
+ expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
+ end
- it 'lists users who are currently not assigned to the issue when using /assign' do
- visit project_issue_path(project, issue_assignee)
+ it 'does not wrap for emoji values' do
+ fill_in 'Comment', with: ':cartwheel_'
- note = find_field('Comment')
- note.native.send_keys('/assign ')
- # The `/assign` ajax response might replace the one by `@` below causing a failed test
- # so we need to wait for the `/assign` ajax request to finish first
- wait_for_requests
- note.native.send_keys('@')
- wait_for_requests
+ find_highlighted_tribute_autocomplete_menu.click
- expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
- expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
+ expect(find_field('Comment').value).to have_text('cartwheel_tone1')
+ end
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)
+ context 'quick actions' do
+ it 'autocompletes for quick actions' do
+ fill_in 'Comment', with: '/as'
- note = find_field('Comment')
- note.native.send_keys('/assign @user2')
- note.native.send_keys(:enter)
- note.native.send_keys('/assign ')
- # The `/assign` ajax response might replace the one by `@` below causing a failed test
- # so we need to wait for the `/assign` ajax request to finish first
- wait_for_requests
- note.native.send_keys('@')
- wait_for_requests
+ find_highlighted_tribute_autocomplete_menu.click
- expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
- expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
+ expect(find_field('Comment').value).to have_text('/assign')
+ end
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 &lt;img src=x onerror="alert(\'Hello xss\');" a'
- create(:label, project: project, title: label_xss_title)
+ context 'labels' do
+ it 'allows colons when autocompleting scoped labels' do
+ fill_in 'Comment', with: '~scoped:'
- fill_in 'Comment', with: '~'
+ wait_for_requests
- wait_for_requests
+ expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
+ end
- expect(find_tribute_autocomplete_menu).to have_text('alert label')
- end
+ it 'autocompletes multi-word labels' do
+ fill_in 'Comment', with: '~Acceptingmerge'
- it 'allows colons when autocompleting scoped labels' do
- create(:label, project: project, title: 'scoped:label')
+ wait_for_requests
- fill_in 'Comment', with: '~scoped:'
+ expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
+ end
- wait_for_requests
+ it 'only autocompletes the last label' do
+ fill_in 'Comment', with: '~scoped:: foo bar ~Acceptingmerge'
+ # Invoke autocompletion
+ find_field('Comment').native.send_keys(:right)
- expect(find_tribute_autocomplete_menu).to have_text('scoped:label')
- end
+ wait_for_requests
- it 'allows colons when autocompleting scoped labels with double colons' do
- create(:label, project: project, title: 'scoped::label')
+ expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
+ end
- fill_in 'Comment', with: '~scoped::'
+ it 'does not autocomplete labels if no tilde is typed' do
+ fill_in 'Comment', with: 'Accepting'
- wait_for_requests
+ wait_for_requests
- expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
+ expect(page).not_to have_css('.tribute-container')
+ end
end
- it 'autocompletes multi-word labels' do
- create(:label, project: project, title: 'Accepting merge requests')
+ context 'when other notes are destroyed' do
+ let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
- fill_in 'Comment', with: '~Acceptingmerge'
+ # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
+ it 'keeps autocomplete key listeners' do
+ note = find_field('Comment')
- wait_for_requests
-
- expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
- end
-
- it 'only autocompletes the latest label' do
- create(:label, project: project, title: 'documentation')
- create(:label, project: project, title: 'feature')
+ start_comment_with_emoji(note, '.tribute-container li')
- fill_in 'Comment', with: '~documentation foo bar ~feat'
- # Invoke autocompletion
- find_field('Comment').native.send_keys(:right)
+ start_and_cancel_discussion
- wait_for_requests
+ note.fill_in(with: '')
+ start_comment_with_emoji(note, '.tribute-container li')
+ note.native.send_keys(:enter)
- expect(find_tribute_autocomplete_menu).to have_text('feature')
- expect(find_tribute_autocomplete_menu).not_to have_text('documentation')
+ expect(note.value).to eql('Hello :100: ')
+ end
end
- it 'does not autocomplete labels if no tilde is typed' do
- create(:label, project: project, title: 'documentation')
+ shared_examples 'autocomplete suggestions' do
+ it 'suggests objects correctly' do
+ fill_in 'Comment', with: object.class.reference_prefix
- fill_in 'Comment', with: 'document'
-
- wait_for_requests
+ find_tribute_autocomplete_menu.find('li').click
- expect(page).not_to have_css('.tribute-container')
+ expect(find_field('Comment').value).to have_text(expected_body)
+ end
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_field('Comment')
-
- start_comment_with_emoji(note, '.tribute-container li')
-
- start_and_cancel_discussion
- note.fill_in(with: '')
- start_comment_with_emoji(note, '.tribute-container li')
- note.native.send_keys(:enter)
+ context 'issues' do
+ let(:object) { issue }
+ let(:expected_body) { object.to_reference }
- expect(note.value).to eql('Hello :100: ')
+ it_behaves_like 'autocomplete suggestions'
end
- end
-
- shared_examples 'autocomplete suggestions' do
- it 'suggests objects correctly' do
- fill_in 'Comment', with: object.class.reference_prefix
- find_tribute_autocomplete_menu.find('li').click
+ context 'merge requests' do
+ let(:object) { create(:merge_request, source_project: project) }
+ let(:expected_body) { object.to_reference }
- expect(find_field('Comment').value).to have_text(expected_body)
+ it_behaves_like 'autocomplete suggestions'
end
- end
-
- context 'issues' do
- let(:object) { issue }
- let(:expected_body) { object.to_reference }
- it_behaves_like 'autocomplete suggestions'
- end
-
- context 'merge requests' do
- let(:object) { create(:merge_request, source_project: project) }
- let(:expected_body) { object.to_reference }
-
- it_behaves_like 'autocomplete suggestions'
- end
+ context 'project snippets' do
+ let!(:object) { snippet }
+ let(:expected_body) { object.to_reference }
- context 'project snippets' do
- let!(:object) { create(:project_snippet, project: project, title: 'code snippet') }
- let(:expected_body) { object.to_reference }
-
- it_behaves_like 'autocomplete suggestions'
- end
-
- context 'label' do
- let!(:object) { label }
- let(:expected_body) { object.title }
-
- it_behaves_like 'autocomplete suggestions'
- end
+ it_behaves_like 'autocomplete suggestions'
+ end
- context 'milestone' do
- let!(:object) { create(:milestone, project: project) }
- let(:expected_body) { object.to_reference }
+ context 'milestone' do
+ let!(:object) { create(:milestone, project: project) }
+ let(:expected_body) { object.to_reference }
- it_behaves_like 'autocomplete suggestions'
+ it_behaves_like 'autocomplete suggestions'
+ end
end
end
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index ca44978d223..04b4caa52fe 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -30,79 +30,199 @@ RSpec.describe 'Issue Sidebar' do
let(:user2) { create(:user) }
let(:issue2) { create(:issue, project: project, author: user2) }
- include_examples 'issuable invite members experiments' do
- let(:issuable_path) { project_issue_path(project, issue2) }
- end
-
- context 'when user is a developer' do
+ context 'when GraphQL assignees widget feature flag is disabled' do
before do
- project.add_developer(user)
- visit_issue(project, issue2)
-
- find('.block.assignee .edit-link').click
+ stub_feature_flags(issue_assignees_widget: false)
+ end
- wait_for_requests
+ include_examples 'issuable invite members experiments' do
+ let(:issuable_path) { project_issue_path(project, issue2) }
end
- it 'shows author in assignee dropdown' do
- page.within '.dropdown-menu-user' do
- expect(page).to have_content(user2.name)
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ visit_issue(project, issue2)
+
+ find('.block.assignee .edit-link').click
+ wait_for_requests
+ end
+
+ it 'shows author in assignee dropdown' do
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_content(user2.name)
+ end
+ end
+
+ it 'shows author when filtering assignee dropdown' do
+ page.within '.dropdown-menu-user' do
+ find('.dropdown-input-field').set(user2.name)
+
+ wait_for_requests
+
+ expect(page).to have_content(user2.name)
+ end
+ end
+
+ it 'assigns yourself' do
+ find('.block.assignee .dropdown-menu-toggle').click
+
+ click_button 'assign yourself'
+
+ wait_for_requests
+
+ find('.block.assignee .edit-link').click
+
+ page.within '.dropdown-menu-user' do
+ expect(page.find('.dropdown-header')).to be_visible
+ expect(page.find('.dropdown-menu-user-link.is-active')).to have_content(user.name)
+ end
end
- end
- it 'shows author when filtering assignee dropdown' do
- page.within '.dropdown-menu-user' do
+ it 'keeps your filtered term after filtering and dismissing the dropdown' do
find('.dropdown-input-field').set(user2.name)
wait_for_requests
- expect(page).to have_content(user2.name)
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_content 'Unassigned'
+ click_link user2.name
+ end
+
+ find('.js-right-sidebar').click
+ find('.block.assignee .edit-link').click
+
+ expect(page.all('.dropdown-menu-user li').length).to eq(1)
+ expect(find('.dropdown-input-field').value).to eq(user2.name)
+ end
+
+ it 'shows label text as "Apply" when assignees are changed' do
+ project.add_developer(user)
+ visit_issue(project, issue2)
+
+ find('.block.assignee .edit-link').click
+ wait_for_requests
+
+ click_on 'Unassigned'
+
+ expect(page).to have_link('Apply')
end
end
+ end
- it 'assigns yourself' do
- find('.block.assignee .dropdown-menu-toggle').click
+ context 'when GraphQL assignees widget feature flag is enabled' do
+ context 'when a privileged user can invite' do
+ it 'shows a link for inviting members and launches invite modal' do
+ project.add_maintainer(user)
+ visit_issue(project, issue2)
- click_button 'assign yourself'
+ open_assignees_dropdown
- wait_for_requests
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_link('Invite members')
+ expect(page).to have_selector('[data-track-event="click_invite_members"]')
+ expect(page).to have_selector('[data-track-label="edit_assignee"]')
+ end
- find('.block.assignee .edit-link').click
+ click_link 'Invite members'
- page.within '.dropdown-menu-user' do
- expect(page.find('.dropdown-header')).to be_visible
- expect(page.find('.dropdown-menu-user-link.is-active')).to have_content(user.name)
+ expect(page).to have_content("You're inviting members to the")
end
end
- it 'keeps your filtered term after filtering and dismissing the dropdown' do
- find('.dropdown-input-field').set(user2.name)
+ context 'when invite_members_version_b experiment is enabled' do
+ before do
+ stub_experiment_for_subject(invite_members_version_b: true)
+ end
+
+ it 'shows a link for inviting members and follows through to modal' do
+ project.add_developer(user)
+ visit_issue(project, issue2)
- wait_for_requests
+ open_assignees_dropdown
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_content 'Unassigned'
- click_link user2.name
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_link('Invite members', href: '#')
+ expect(page).to have_selector('[data-track-event="click_invite_members_version_b"]')
+ expect(page).to have_selector('[data-track-label="edit_assignee"]')
+ end
+
+ click_link 'Invite members'
+
+ expect(page).to have_content("Oops, this feature isn't ready yet")
end
+ end
+
+ context 'when invite_members_version_b experiment is disabled' do
+ it 'shows author in assignee dropdown and no invite link' do
+ project.add_developer(user)
+ visit_issue(project, issue2)
- find('.js-right-sidebar').click
- find('.block.assignee .edit-link').click
+ open_assignees_dropdown
- expect(page.all('.dropdown-menu-user li').length).to eq(1)
- expect(find('.dropdown-input-field').value).to eq(user2.name)
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_link('Invite members')
+ end
+ end
end
- end
- it 'shows label text as "Apply" when assignees are changed' do
- project.add_developer(user)
- visit_issue(project, issue2)
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ visit_issue(project, issue2)
+ end
+
+ it 'shows author in assignee dropdown' do
+ open_assignees_dropdown
+
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_content(user2.name)
+ end
+ end
+
+ it 'shows author when filtering assignee dropdown' do
+ open_assignees_dropdown
+
+ page.within '.dropdown-menu-user' do
+ find('.js-dropdown-input-field').find('input').set(user2.name)
+
+ wait_for_requests
+
+ expect(page).to have_content(user2.name)
+ end
+ end
+
+ it 'assigns yourself' do
+ click_button 'assign yourself'
+ wait_for_requests
+
+ page.within '.assignee' do
+ expect(page).to have_content(user.name)
+ end
+ end
- find('.block.assignee .edit-link').click
- wait_for_requests
+ it 'keeps your filtered term after filtering and dismissing the dropdown' do
+ open_assignees_dropdown
- click_on 'Unassigned'
+ find('.js-dropdown-input-field').find('input').set(user2.name)
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_content 'Unassigned'
+ click_link user2.name
+ end
- expect(page).to have_link('Apply')
+ find('.js-right-sidebar').click
+
+ open_assignees_dropdown
+
+ page.within('.assignee') do
+ expect(page.all('[data-testid="selected-participant"]').length).to eq(1)
+ end
+
+ expect(find('.js-dropdown-input-field').find('input').value).to eq(user2.name)
+ end
+ end
end
end
@@ -171,7 +291,7 @@ RSpec.describe 'Issue Sidebar' do
context 'editing issue labels', :js do
before do
- issue.update(labels: [label])
+ issue.update!(labels: [label])
page.within('.block.labels') do
click_on 'Edit'
end
@@ -334,4 +454,11 @@ RSpec.describe 'Issue Sidebar' do
find('aside.right-sidebar.right-sidebar-collapsed .js-sidebar-toggle').click
find('aside.right-sidebar.right-sidebar-expanded')
end
+
+ def open_assignees_dropdown
+ page.within('.assignee') do
+ click_button('Edit')
+ wait_for_requests
+ end
+ end
end
diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb
index 6dc1cbfb2d7..aad5d319bc4 100644
--- a/spec/features/issues/markdown_toolbar_spec.rb
+++ b/spec/features/issues/markdown_toolbar_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe 'Issue markdown toolbar', :js do
- let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, project: project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:user) { create(:user) }
before do
sign_in(user)
@@ -14,28 +14,22 @@ RSpec.describe 'Issue markdown toolbar', :js do
end
it "doesn't include first new line when adding bold" do
- find('#note-body').native.send_keys('test')
- find('#note-body').native.send_key(:enter)
- find('#note-body').native.send_keys('bold')
+ fill_in 'Comment', with: "test\nbold"
- find('.js-main-target-form #note-body')
- page.evaluate_script('document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 9)')
+ page.evaluate_script('document.getElementById("note-body").setSelectionRange(4, 9)')
- first('.toolbar-btn').click
+ click_button 'Add bold text'
- expect(find('#note-body')[:value]).to eq("test\n**bold**\n")
+ expect(find_field('Comment').value).to eq("test\n**bold**\n")
end
it "doesn't include first new line when adding underline" do
- find('#note-body').native.send_keys('test')
- find('#note-body').native.send_key(:enter)
- find('#note-body').native.send_keys('underline')
+ fill_in 'Comment', with: "test\nunderline"
- find('.js-main-target-form #note-body')
- page.evaluate_script('document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 50)')
+ page.evaluate_script('document.getElementById("note-body").setSelectionRange(4, 50)')
- all('.toolbar-btn')[1].click
+ click_button 'Add italic text'
- expect(find('#note-body')[:value]).to eq("test\n_underline_\n")
+ expect(find_field('Comment').value).to eq("test\n_underline_\n")
end
end
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
index bc4c67fdd79..5e02d5ad038 100644
--- a/spec/features/issues/note_polling_spec.rb
+++ b/spec/features/issues/note_polling_spec.rb
@@ -103,7 +103,7 @@ RSpec.describe 'Issue notes polling', :js do
end
def update_note(note, new_text)
- note.update(note: new_text)
+ note.update!(note: new_text)
wait_for_requests
end
diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb
index aec806c566d..461030d3176 100644
--- a/spec/features/issues/spam_issues_spec.rb
+++ b/spec/features/issues/spam_issues_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe 'New issue', :js do
end
it 'rejects issue creation' do
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page).to have_content('discarded')
expect(page).not_to have_content('potential spam')
@@ -51,7 +51,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
- expect { click_button 'Submit issue' }
+ expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
@@ -63,14 +63,14 @@ RSpec.describe 'New issue', :js do
end
it 'allows issue creation' do
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
- expect { click_button 'Submit issue' }
+ expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
@@ -101,14 +101,14 @@ RSpec.describe 'New issue', :js do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
- click_button 'Submit issue'
+ click_button 'Create issue'
# it is impossible to test reCAPTCHA automatically and there is no possibility to fill in recaptcha
# reCAPTCHA verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
@@ -122,7 +122,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates an issue without a need to solve reCAPTCHA' do
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
@@ -130,7 +130,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
- expect { click_button 'Submit issue' }
+ expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
@@ -148,7 +148,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates an issue without a need to solve reCaptcha' do
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
@@ -156,7 +156,7 @@ RSpec.describe 'New issue', :js do
end
it 'creates a spam log record' do
- expect { click_button 'Submit issue' }
+ expect { click_button 'Create issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end
@@ -178,7 +178,7 @@ RSpec.describe 'New issue', :js do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
- click_button 'Submit issue'
+ click_button 'Create issue'
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb
index 004488f2f64..09d3ad15641 100644
--- a/spec/features/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/issues/user_comments_on_issue_spec.rb
@@ -57,17 +57,9 @@ RSpec.describe "User comments on issue", :js do
project.add_maintainer(user)
create(:label, project: project, title: 'label')
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('/l')
- end
-
- wait_for_requests
-
- expect(page).to have_selector('.atwho-container')
+ fill_in 'Comment', with: '/l'
- page.within '.atwho-container #at-view-commands' do
- expect(find('li', match: :first)).to have_content('/label')
- end
+ expect(find_highlighted_autocomplete_item).to have_content('/label')
end
end
@@ -110,4 +102,10 @@ RSpec.describe "User comments on issue", :js do
end
end
end
+
+ private
+
+ def find_highlighted_autocomplete_item
+ find('.atwho-view li.cur', visible: true)
+ end
end
diff --git a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
index e225a45481d..6e8b3e4fb7c 100644
--- a/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_branch_and_merge_request_spec.rb
@@ -150,7 +150,7 @@ RSpec.describe 'User creates branch and merge request on issue page', :js do
context 'when merge requests are disabled' do
before do
- project.project_feature.update(merge_requests_access_level: 0)
+ project.project_feature.update!(merge_requests_access_level: 0)
visit project_issue_path(project, issue)
end
diff --git a/spec/features/issues/user_creates_confidential_merge_request_spec.rb b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
index ea96165d7b7..6b4526cd624 100644
--- a/spec/features/issues/user_creates_confidential_merge_request_spec.rb
+++ b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe 'User creates confidential merge request on issue page', :js do
let(:forked_project) { fork_project(project, user, repository: true) }
before do
- forked_project.update(visibility: Gitlab::VisibilityLevel::PRIVATE)
+ forked_project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
visit_confidential_issue
end
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 98f9ed6c6a2..e2e204f03db 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe "User creates issue" do
.and have_no_content("Milestone")
expect(page.find('#issue_title')['placeholder']).to eq 'Title'
- expect(page.find('#issue_description')['placeholder']).to eq 'Write a comment or drag your files here…'
+ expect(page.find('#issue_description')['placeholder']).to eq 'Write a description or drag your files here…'
end
issue_title = "500 error on profile"
@@ -54,7 +54,7 @@ RSpec.describe "User creates issue" do
first('.js-md').click
first('.rspec-issuable-form-description').native.send_keys('Description')
- click_button("Submit issue")
+ click_button("Create issue")
expect(page).to have_content(issue_title)
.and have_content(user.name)
@@ -112,7 +112,7 @@ RSpec.describe "User creates issue" do
fill_in("Title", with: issue_title)
click_button("Label")
click_link(label_titles.first)
- click_button("Submit issue")
+ click_button("Create issue")
expect(page).to have_content(issue_title)
.and have_content(user.name)
@@ -135,7 +135,7 @@ RSpec.describe "User creates issue" do
expect(find('#issuable-due-date').value).to eq date.to_s
- click_button 'Submit issue'
+ click_button 'Create issue'
page.within '.issuable-sidebar' do
expect(page).to have_content date.to_s(:medium)
@@ -259,7 +259,7 @@ RSpec.describe "User creates issue" do
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
- click_button 'Submit issue'
+ click_button 'Create issue'
end
end
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index 9d4a6cdb522..1bbb96ff479 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe "Issues > User edits issue", :js do
end
it 'warns about version conflict' do
- issue.update(title: "New title")
+ issue.update!(title: "New title")
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
@@ -142,10 +142,8 @@ RSpec.describe "Issues > User edits issue", :js do
it 'can remove label without removing label added via quick action', :aggregate_failures do
# Add `syzygy` label with a quick action
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/label ~syzygy')
- end
+ fill_in 'Comment', with: '/label ~syzygy'
+
click_button 'Comment'
wait_for_requests
@@ -169,80 +167,165 @@ RSpec.describe "Issues > User edits issue", :js do
end
describe 'update assignee' do
- context 'by authorized user' do
- def close_dropdown_menu_if_visible
- find('.dropdown-menu-toggle', visible: :all).tap do |toggle|
- toggle.click if toggle.visible?
- end
+ context 'when GraphQL assignees widget feature flag is disabled' do
+ before do
+ stub_feature_flags(issue_assignees_widget: false)
end
- it 'allows user to select unassigned' do
- visit project_issue_path(project, issue)
+ context 'by authorized user' do
+ def close_dropdown_menu_if_visible
+ find('.dropdown-menu-toggle', visible: :all).tap do |toggle|
+ toggle.click if toggle.visible?
+ end
+ end
- page.within('.assignee') do
- expect(page).to have_content "#{user.name}"
+ it 'allows user to select unassigned' do
+ visit project_issue_path(project, issue)
- click_link 'Edit'
- click_link 'Unassigned'
- first('.title').click
- expect(page).to have_content 'None - assign yourself'
+ page.within('.assignee') do
+ expect(page).to have_content "#{user.name}"
+
+ click_link 'Edit'
+ click_link 'Unassigned'
+ first('.title').click
+
+ expect(page).to have_content 'None - assign yourself'
+ end
end
- end
- it 'allows user to select an assignee' do
- issue2 = create(:issue, project: project, author: user)
- visit project_issue_path(project, issue2)
+ it 'allows user to select an assignee' do
+ issue2 = create(:issue, project: project, author: user)
+ visit project_issue_path(project, issue2)
- page.within('.assignee') do
- expect(page).to have_content "None"
+ page.within('.assignee') do
+ expect(page).to have_content "None"
+ end
+
+ page.within '.assignee' do
+ click_link 'Edit'
+ end
+
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+
+ page.within('.assignee') do
+ expect(page).to have_content user.name
+ end
end
- page.within '.assignee' do
- click_link 'Edit'
+ it 'allows user to unselect themselves' do
+ issue2 = create(:issue, project: project, author: user, assignees: [user])
+
+ visit project_issue_path(project, issue2)
+
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+
+ click_link 'Edit'
+ click_link user.name
+
+ close_dropdown_menu_if_visible
+
+ page.within '.value .assign-yourself' do
+ expect(page).to have_content "None"
+ end
+ end
end
+ end
+
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- page.within '.dropdown-menu-user' do
- click_link user.name
+ before do
+ project.add_guest(guest)
end
- page.within('.assignee') do
- expect(page).to have_content user.name
+ it 'shows assignee text' do
+ sign_out(:user)
+ sign_in(guest)
+
+ visit project_issue_path(project, issue)
+ expect(page).to have_content issue.assignees.first.name
end
end
+ end
- it 'allows user to unselect themselves' do
- issue2 = create(:issue, project: project, author: user, assignees: [user])
+ context 'when GraphQL assignees widget feature flag is enabled' do
+ context 'by authorized user' do
+ it 'allows user to select unassigned' do
+ visit project_issue_path(project, issue)
- visit project_issue_path(project, issue2)
+ page.within('.assignee') do
+ expect(page).to have_content "#{user.name}"
- page.within '.assignee' do
- expect(page).to have_content user.name
+ click_button('Edit')
+ wait_for_requests
- click_link 'Edit'
- click_link user.name
+ find('[data-testid="unassign"]').click
+ find('[data-testid="title"]').click
+ wait_for_requests
+
+ expect(page).to have_content 'None - assign yourself'
+ end
+ end
- close_dropdown_menu_if_visible
+ it 'allows user to select an assignee' do
+ issue2 = create(:issue, project: project, author: user)
+ visit project_issue_path(project, issue2)
- page.within '.value .assign-yourself' do
+ page.within('.assignee') do
expect(page).to have_content "None"
+ click_button('Edit')
+ wait_for_requests
+ end
+
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+
+ page.within('.assignee') do
+ find('[data-testid="title"]').click
+ wait_for_requests
+
+ expect(page).to have_content user.name
end
end
- end
- end
- context 'by unauthorized user' do
- let(:guest) { create(:user) }
+ it 'allows user to unselect themselves' do
+ issue2 = create(:issue, project: project, author: user, assignees: [user])
- before do
- project.add_guest(guest)
+ visit project_issue_path(project, issue2)
+
+ page.within '.assignee' do
+ expect(page).to have_content user.name
+
+ click_button('Edit')
+ wait_for_requests
+ click_link user.name
+
+ find('[data-testid="title"]').click
+ wait_for_requests
+
+ expect(page).to have_content "None"
+ end
+ end
end
- it 'shows assignee text' do
- sign_out(:user)
- sign_in(guest)
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- visit project_issue_path(project, issue)
- expect(page).to have_content issue.assignees.first.name
+ before do
+ project.add_guest(guest)
+ end
+
+ it 'shows assignee text' do
+ sign_out(:user)
+ sign_in(guest)
+
+ visit project_issue_path(project, issue)
+ expect(page).to have_content issue.assignees.first.name
+ end
end
end
end
@@ -309,7 +392,7 @@ RSpec.describe "Issues > User edits issue", :js do
before do
project.add_guest(guest)
issue.milestone = milestone
- issue.save
+ issue.save!
end
it 'shows milestone text' do
@@ -326,24 +409,23 @@ RSpec.describe "Issues > User edits issue", :js do
it 'adds due date to issue' do
date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
-
+ page.within '[data-testid="due-date"]' do
+ click_button 'Edit'
page.within '.pika-single' do
click_button date.day
end
wait_for_requests
- expect(find('.value').text).to have_content date.strftime('%b %-d, %Y')
+ expect(find('[data-testid="sidebar-duedate-value"]').text).to have_content date.strftime('%b %-d, %Y')
end
end
it 'removes due date from issue' do
date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
+ page.within '[data-testid="due-date"]' do
+ click_button 'Edit'
page.within '.pika-single' do
click_button date.day
@@ -353,7 +435,7 @@ RSpec.describe "Issues > User edits issue", :js do
expect(page).to have_no_content 'None'
- click_link 'remove due date'
+ click_button 'remove due date'
expect(page).to have_content 'None'
end
end
diff --git a/spec/features/issues/user_filters_issues_spec.rb b/spec/features/issues/user_filters_issues_spec.rb
index 1b246181523..5d05df6aaf0 100644
--- a/spec/features/issues/user_filters_issues_spec.rb
+++ b/spec/features/issues/user_filters_issues_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'User filters issues', :js do
@issue = Issue.find_by(title: 'foobar')
@issue.milestone = create(:milestone, project: project)
@issue.assignees = []
- @issue.save
+ @issue.save!
end
let(:issue) { @issue }
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index 1c7bc5f239f..e862f7030c0 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe 'User interacts with awards' do
let(:user) { create(:user) }
+ before do
+ stub_feature_flags(improved_emoji_picker: false)
+ end
+
describe 'User interacts with awards in an issue', :js do
let(:issue) { create(:issue, project: project)}
let(:project) { create(:project) }
diff --git a/spec/features/issues/user_invites_from_a_comment_spec.rb b/spec/features/issues/user_invites_from_a_comment_spec.rb
new file mode 100644
index 00000000000..82061f6ed79
--- /dev/null
+++ b/spec/features/issues/user_invites_from_a_comment_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe "User invites from a comment", :js do
+ let_it_be(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:user) { project.owner }
+
+ before do
+ sign_in(user)
+ end
+
+ it "launches the invite modal from invite link on a comment" do
+ stub_experiments(invite_members_in_comment: :invite_member_link)
+
+ visit project_issue_path(project, issue)
+
+ page.within(".new-note") do
+ click_button 'Invite Member'
+ end
+
+ expect(page).to have_content("You're inviting members to the")
+ end
+end
diff --git a/spec/features/issues/user_sees_live_update_spec.rb b/spec/features/issues/user_sees_live_update_spec.rb
index 79c6978cbc0..7e4880f209e 100644
--- a/spec/features/issues/user_sees_live_update_spec.rb
+++ b/spec/features/issues/user_sees_live_update_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe 'Issues > User sees live update', :js do
expect(page).to have_text("new title")
- issue.update(title: "updated title")
+ issue.update!(title: "updated title")
wait_for_requests
expect(page).to have_text("updated title")
diff --git a/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
index 7a2b637e48e..6473fe01052 100644
--- a/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
+++ b/spec/features/issues/user_sees_sidebar_updates_in_realtime_spec.rb
@@ -19,11 +19,14 @@ RSpec.describe 'Issues > Real-time sidebar', :js do
expect(page.find('.assignee')).to have_content 'None'
end
- gitlab_sign_in(user)
+ sign_in(user)
+
visit project_issue_path(project, issue)
expect(page.find('.assignee')).to have_content 'None'
click_button 'assign yourself'
+ wait_for_requests
+ expect(page.find('.assignee')).to have_content user.name
using_session :other_session do
expect(page.find('.assignee')).to have_content user.name
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index f0bb055c6f2..c161e1deb83 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe "User sorts issues" do
it 'sorts by most recently updated', :js do
issue3.updated_at = Time.now + 100
- issue3.save
+ issue3.save!
visit project_issues_path(project, sort: sort_value_recently_updated)
expect(first_issue).to include('baz')
@@ -85,8 +85,8 @@ RSpec.describe "User sorts issues" 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)
+ issue1.update!(due_date: 1.day.from_now)
+ issue2.update!(due_date: 6.days.from_now)
end
it 'sorts by due date' do
@@ -96,7 +96,7 @@ RSpec.describe "User sorts issues" do
end
it 'sorts by due date by excluding nil due dates' do
- issue2.update(due_date: nil)
+ issue2.update!(due_date: nil)
visit project_issues_path(project, sort: sort_value_due_date)
@@ -111,7 +111,7 @@ RSpec.describe "User sorts issues" do
end
it 'sorts by least recently due date by excluding nil due dates' do
- issue2.update(due_date: nil)
+ issue2.update!(due_date: nil)
visit project_issues_path(project, label_names: [label.name], sort: sort_value_due_date_later)
@@ -122,8 +122,8 @@ RSpec.describe "User sorts issues" 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)
+ issue1.update!(due_date: 1.day.from_now)
+ issue2.update!(due_date: 6.days.from_now)
end
it 'filters by none' do
@@ -147,9 +147,9 @@ RSpec.describe "User sorts issues" do
end
it 'filters by due this week' do
- issue1.update(due_date: Date.today.beginning_of_week + 2.days)
- issue2.update(due_date: Date.today.end_of_week)
- issue3.update(due_date: Date.today - 8.days)
+ issue1.update!(due_date: Date.today.beginning_of_week + 2.days)
+ issue2.update!(due_date: Date.today.end_of_week)
+ issue3.update!(due_date: Date.today - 8.days)
visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
@@ -161,9 +161,9 @@ RSpec.describe "User sorts issues" do
end
it 'filters by due this month' do
- issue1.update(due_date: Date.today.beginning_of_month + 2.days)
- issue2.update(due_date: Date.today.end_of_month)
- issue3.update(due_date: Date.today - 50.days)
+ issue1.update!(due_date: Date.today.beginning_of_month + 2.days)
+ issue2.update!(due_date: Date.today.end_of_month)
+ issue3.update!(due_date: Date.today - 50.days)
visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
@@ -175,9 +175,9 @@ RSpec.describe "User sorts issues" do
end
it 'filters by overdue' do
- issue1.update(due_date: Date.today + 2.days)
- issue2.update(due_date: Date.today + 20.days)
- issue3.update(due_date: Date.yesterday)
+ issue1.update!(due_date: Date.today + 2.days)
+ issue2.update!(due_date: Date.today + 20.days)
+ issue3.update!(due_date: Date.yesterday)
visit project_issues_path(project, due_date: Issue::Overdue.name)
@@ -189,9 +189,9 @@ RSpec.describe "User sorts issues" do
end
it 'filters by due next month and previous two weeks' do
- issue1.update(due_date: Date.today - 4.weeks)
- issue2.update(due_date: (Date.today + 2.months).beginning_of_month)
- issue3.update(due_date: Date.yesterday)
+ issue1.update!(due_date: Date.today - 4.weeks)
+ issue2.update!(due_date: (Date.today + 2.months).beginning_of_month)
+ issue3.update!(due_date: Date.yesterday)
visit project_issues_path(project, due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name)
@@ -206,9 +206,9 @@ RSpec.describe "User sorts issues" do
describe 'sorting by milestone', :js do
before do
issue1.milestone = newer_due_milestone
- issue1.save
+ issue1.save!
issue2.milestone = later_due_milestone
- issue2.save
+ issue2.save!
end
it 'sorts by milestone' do
@@ -224,9 +224,9 @@ RSpec.describe "User sorts issues" do
before do
issue1.assignees << user2
- issue1.save
+ issue1.save!
issue2.assignees << user2
- issue2.save
+ issue2.save!
end
it 'sorts with a filter applied' do