summaryrefslogtreecommitdiff
path: root/spec/features/issues/gfm_autocomplete_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features/issues/gfm_autocomplete_spec.rb')
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb752
1 files changed, 472 insertions, 280 deletions
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 4a7e1ba99e9..0b2e8013304 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -3,455 +3,647 @@
require 'spec_helper'
RSpec.describe 'GFM autocomplete', :js do
- let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
- let(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
- let(:label_xss_title) { 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' }
- let(:milestone_xss_title) { 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a' }
-
- let(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
- let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
- let(:project) { create(:project) }
- let(:label) { create(:label, project: project, title: 'special+') }
+ 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(:project) { create(:project) }
+ let_it_be(:label) { create(:label, project: project, title: 'special+') }
+
let(:issue) { create(:issue, project: project) }
- before do
+ before_all do
project.add_maintainer(user)
project.add_maintainer(user_xss)
+ end
- sign_in(user)
- visit project_issue_path(project, issue)
+ describe 'when tribute_autocomplete feature flag is off' do
+ before do
+ stub_feature_flags(tribute_autocomplete: false)
- wait_for_requests
- end
+ sign_in(user)
+ visit project_issue_path(project, issue)
- it 'updates issue description with GFM reference' do
- find('.js-issuable-edit').click
+ wait_for_requests
+ end
- wait_for_requests
+ it 'updates issue description with GFM reference' do
+ find('.js-issuable-edit').click
- simulate_input('#issue-description', "@#{user.name[0...3]}")
+ wait_for_requests
- wait_for_requests
+ simulate_input('#issue-description', "@#{user.name[0...3]}")
- find('.atwho-view .cur').click
+ wait_for_requests
- click_button 'Save changes'
+ find('.atwho-view .cur').click
- wait_for_requests
+ click_button 'Save changes'
- expect(find('.description')).to have_content(user.to_reference)
- end
+ wait_for_requests
- it 'opens autocomplete menu when field starts with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
+ expect(find('.description')).to have_content(user.to_reference)
end
- expect(page).to have_selector('.atwho-container')
- end
+ it 'opens quick action autocomplete when updating description' do
+ find('.js-issuable-edit').click
- it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
- create(:issue, project: project, title: issue_xss_title)
+ find('#issue-description').native.send_keys('/')
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('#')
+ expect(page).to have_selector('.atwho-container')
end
- wait_for_requests
-
- expect(page).to have_selector('.atwho-container')
+ it 'opens autocomplete menu when field starts with text' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@')
+ end
- page.within '.atwho-container #at-view-issues' do
- expect(page.all('li').first.text).to include(issue_xss_title)
+ expect(page).to have_selector('.atwho-container')
end
- end
- 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('@ev')
- 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)
+
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('#')
+ end
- wait_for_requests
+ wait_for_requests
- expect(page).to have_selector('.atwho-container')
+ expect(page).to have_selector('.atwho-container')
- page.within '.atwho-container #at-view-users' do
- expect(find('li').text).to have_content(user_xss.username)
+ page.within '.atwho-container #at-view-issues' do
+ expect(page.all('li').first.text).to include(issue_xss_title)
+ end
end
- end
- it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
- create(:milestone, project: project, title: milestone_xss_title)
+ 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('@ev')
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.atwho-container')
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('%')
+ page.within '.atwho-container #at-view-users' do
+ expect(find('li').text).to have_content(user_xss.username)
+ end
end
- wait_for_requests
+ 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)
+
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('%')
+ end
+
+ wait_for_requests
- expect(page).to have_selector('.atwho-container')
+ expect(page).to have_selector('.atwho-container')
- page.within '.atwho-container #at-view-milestones' do
- expect(find('li').text).to have_content('alert milestone')
+ page.within '.atwho-container #at-view-milestones' do
+ expect(find('li').text).to have_content('alert milestone')
+ end
end
- end
- it 'doesnt open autocomplete menu character is prefixed with text' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('testing')
- find('#note-body').native.send_keys('@')
+ it 'doesnt open autocomplete menu character is prefixed with text' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('testing')
+ find('#note-body').native.send_keys('@')
+ end
+
+ expect(page).not_to have_selector('.atwho-view')
end
- expect(page).not_to have_selector('.atwho-view')
- end
+ it 'doesnt select the first item for non-assignee dropdowns' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys(':')
+ end
+
+ expect(page).to have_selector('.atwho-container')
- it 'doesnt select the first item for non-assignee dropdowns' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(':')
+ wait_for_requests
+
+ expect(find('#at-view-58')).not_to have_selector('.cur:first-of-type')
end
- expect(page).to have_selector('.atwho-container')
+ it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
+ note = find('#note-body')
- wait_for_requests
+ # Number.
+ page.within '.timeline-content-form' do
+ note.native.send_keys('7:')
+ end
- expect(find('#at-view-58')).not_to have_selector('.cur:first-of-type')
- end
+ expect(page).not_to have_selector('.atwho-view')
- it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
- note = find('#note-body')
+ # ASCII letter.
+ page.within '.timeline-content-form' do
+ note.set('')
+ note.native.send_keys('w:')
+ end
- # Number.
- page.within '.timeline-content-form' do
- note.native.send_keys('7:')
- end
+ expect(page).not_to have_selector('.atwho-view')
- expect(page).not_to have_selector('.atwho-view')
+ # Non-ASCII letter.
+ page.within '.timeline-content-form' do
+ note.set('')
+ note.native.send_keys('Ё:')
+ end
- # ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('w:')
+ expect(page).not_to have_selector('.atwho-view')
end
- expect(page).not_to have_selector('.atwho-view')
+ it 'selects the first item for assignee dropdowns' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@')
+ end
- # Non-ASCII letter.
- page.within '.timeline-content-form' do
- note.set('')
- note.native.send_keys('Ё:')
- end
+ expect(page).to have_selector('.atwho-container')
- expect(page).not_to have_selector('.atwho-view')
- end
+ wait_for_requests
- it 'selects the first item for assignee dropdowns' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('@')
+ expect(find('#at-view-users')).to have_selector('.cur:first-of-type')
end
- expect(page).to have_selector('.atwho-container')
+ it 'includes items for assignee dropdowns with non-ASCII characters in name' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('')
+ simulate_input('#note-body', "@#{user.name[0...8]}")
+ end
- wait_for_requests
+ expect(page).to have_selector('.atwho-container')
- expect(find('#at-view-users')).to have_selector('.cur:first-of-type')
- end
+ wait_for_requests
- it 'includes items for assignee dropdowns with non-ASCII characters in name' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys('')
- simulate_input('#note-body', "@#{user.name[0...8]}")
+ expect(find('#at-view-users')).to have_content(user.name)
end
- expect(page).to have_selector('.atwho-container')
+ it 'selects the first item for non-assignee dropdowns if a query is entered' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys(':1')
+ end
- wait_for_requests
+ expect(page).to have_selector('.atwho-container')
- expect(find('#at-view-users')).to have_content(user.name)
- end
+ wait_for_requests
- it 'selects the first item for non-assignee dropdowns if a query is entered' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(':1')
+ expect(find('#at-view-58')).to have_selector('.cur:first-of-type')
end
- expect(page).to have_selector('.atwho-container')
+ 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
- wait_for_requests
+ label_item = find('.atwho-view li', text: label.title)
- expect(find('#at-view-58')).to have_selector('.cur:first-of-type')
- end
+ expect_to_wrap(true, label_item, note, label.title)
+ 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]}")
+ it "shows dropdown after a new line" do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('test')
+ note.native.send_keys(:enter)
+ note.native.send_keys(:enter)
+ note.native.send_keys('@')
+ end
+
+ expect(page).to have_selector('.atwho-container')
end
- label_item = find('.atwho-view li', text: label.title)
+ it "does not show dropdown when preceded with a special character" do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@")
+ end
- expect_to_wrap(true, label_item, note, label.title)
- end
+ expect(page).to have_selector('.atwho-container')
- it "shows dropdown after a new line" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('test')
- note.native.send_keys(:enter)
- note.native.send_keys(:enter)
- note.native.send_keys('@')
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@")
+ end
+
+ expect(page).to have_selector('.atwho-container', visible: false)
end
- expect(page).to have_selector('.atwho-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
- it "does not show dropdown when preceded with a special character" do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys("@")
+ expect(page).to have_selector('.atwho-container', visible: false)
end
- expect(page).to have_selector('.atwho-container')
+ it 'doesn\'t wrap for assignee values' do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@#{user.username[0]}")
+ end
- page.within '.timeline-content-form' do
- note.native.send_keys("@")
+ user_item = find('.atwho-view li', text: user.username)
+
+ expect_to_wrap(false, user_item, note, user.username)
end
- expect(page).to have_selector('.atwho-container', visible: false)
- end
+ it 'doesn\'t wrap for emoji values' do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys(":cartwheel_")
+ 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('~')
+ emoji_item = find('.atwho-view li', text: 'cartwheel_tone1')
+
+ expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1')
end
- expect(page).to have_selector('.atwho-container', visible: false)
- end
+ it 'doesn\'t open autocomplete after non-word character' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys("@#{user.username[0..2]}!")
+ end
- it 'doesn\'t wrap for assignee values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys("@#{user.username[0]}")
+ expect(page).not_to have_selector('.atwho-view')
+ end
+
+ it 'doesn\'t open autocomplete if there is no space before' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
+ end
+
+ expect(page).not_to have_selector('.atwho-view')
end
- user_item = find('.atwho-view li', text: user.username)
+ it 'triggers autocomplete after selecting a quick action' do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('/as')
+ end
+
+ find('.atwho-view li', text: '/assign')
+ note.native.send_keys(:tab)
- expect_to_wrap(false, user_item, note, user.username)
+ user_item = find('.atwho-view li', text: user.username)
+ expect(user_item).to have_content(user.username)
+ end
end
- it 'doesn\'t wrap for emoji values' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys(":cartwheel_")
+ context 'assignees' do
+ let(:issue_assignee) { create(:issue, project: project) }
+ let(:unassigned_user) { create(:user) }
+
+ before do
+ issue_assignee.update(assignees: [user])
+
+ project.add_maintainer(unassigned_user)
end
- emoji_item = find('.atwho-view li', text: 'cartwheel_tone1')
+ it 'lists users who are currently not assigned to the issue when using /assign' do
+ visit project_issue_path(project, issue_assignee)
- expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1')
- end
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('/as')
+ end
- it 'doesn\'t open autocomplete after non-word character' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys("@#{user.username[0..2]}!")
+ find('.atwho-view li', text: '/assign')
+ note.native.send_keys(:tab)
+
+ wait_for_requests
+
+ expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
+ expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
end
- expect(page).not_to have_selector('.atwho-view')
+ it 'shows dropdown on new issue form' do
+ visit new_project_issue_path(project)
+
+ textarea = find('#issue_description')
+ textarea.native.send_keys('/ass')
+ find('.atwho-view li', text: '/assign')
+ textarea.native.send_keys(:tab)
+
+ expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
+ expect(find('#at-view-users .atwho-view-ul')).to have_content(user.username)
+ end
end
- it 'doesn\'t open autocomplete if there is no space before' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
+ 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)
+
+ note = find('#note-body')
+
+ # It should show all the labels on "~".
+ type(note, '~')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('alert label')
+ end
end
- expect(page).not_to have_selector('.atwho-view')
- end
+ it 'allows colons when autocompleting scoped labels' do
+ create(:label, project: project, title: 'scoped:label')
- it 'triggers autocomplete after selecting a quick action' do
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/as')
+ note = find('#note-body')
+ type(note, '~scoped:')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('scoped:label')
+ end
end
- find('.atwho-view li', text: '/assign')
- note.native.send_keys(:tab)
+ it 'allows colons when autocompleting scoped labels with double colons' do
+ create(:label, project: project, title: 'scoped::label')
- user_item = find('.atwho-view li', text: user.username)
- expect(user_item).to have_content(user.username)
- end
- end
+ note = find('#note-body')
+ type(note, '~scoped::')
- context 'assignees' do
- let(:issue_assignee) { create(:issue, project: project) }
- let(:unassigned_user) { create(:user) }
+ wait_for_requests
- before do
- issue_assignee.update(assignees: [user])
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('scoped::label')
+ end
+ end
+
+ it 'allows spaces when autocompleting multi-word labels' do
+ create(:label, project: project, title: 'Accepting merge requests')
- project.add_maintainer(unassigned_user)
+ note = find('#note-body')
+ type(note, '~Accepting merge')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('Accepting merge requests')
+ end
+ end
+
+ it 'only autocompletes the latest label' do
+ create(:label, project: project, title: 'Accepting merge requests')
+ create(:label, project: project, title: 'Accepting job applicants')
+
+ note = find('#note-body')
+ type(note, '~Accepting merge requests foo bar ~Accepting job')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('Accepting job applicants')
+ end
+ end
+
+ it 'does not autocomplete labels if no tilde is typed' do
+ create(:label, project: project, title: 'Accepting merge requests')
+
+ note = find('#note-body')
+ type(note, 'Accepting merge')
+
+ wait_for_requests
+
+ expect(page).not_to have_css('.atwho-container #at-view-labels')
+ end
end
- it 'lists users who are currently not assigned to the issue when using /assign' do
- visit project_issue_path(project, issue_assignee)
+ shared_examples 'autocomplete suggestions' do
+ it 'suggests objects correctly' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys(object.class.reference_prefix)
+ end
- note = find('#note-body')
- page.within '.timeline-content-form' do
- note.native.send_keys('/as')
+ page.within '.atwho-container' do
+ expect(page).to have_content(object.title)
+
+ find('ul li').click
+ end
+
+ expect(find('.new-note #note-body').value).to include(expected_body)
end
+ end
- find('.atwho-view li', text: '/assign')
- note.native.send_keys(:tab)
+ context 'issues' do
+ let(:object) { issue }
+ let(:expected_body) { object.to_reference }
- wait_for_requests
+ it_behaves_like 'autocomplete suggestions'
+ end
+
+ context 'merge requests' do
+ let(:object) { create(:merge_request, source_project: project) }
+ let(:expected_body) { object.to_reference }
- expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
- expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
+ it_behaves_like 'autocomplete suggestions'
end
- it 'shows dropdown on new issue form' do
- visit new_project_issue_path(project)
+ context 'project snippets' do
+ let!(:object) { create(:project_snippet, project: project, title: 'code snippet') }
+ let(:expected_body) { object.to_reference }
- textarea = find('#issue_description')
- textarea.native.send_keys('/ass')
- find('.atwho-view li', text: '/assign')
- textarea.native.send_keys(:tab)
+ it_behaves_like 'autocomplete suggestions'
+ end
+
+ context 'label' do
+ let!(:object) { label }
+ let(:expected_body) { object.title }
+
+ it_behaves_like 'autocomplete suggestions'
+ end
+
+ context 'milestone' do
+ let!(:object) { create(:milestone, project: project) }
+ let(:expected_body) { object.to_reference }
- expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
- expect(find('#at-view-users .atwho-view-ul')).to have_content(user.username)
+ it_behaves_like 'autocomplete suggestions'
end
end
- context 'labels' do
- it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
- create(:label, project: project, title: label_xss_title)
+ 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)
- note = find('#note-body')
+ wait_for_requests
+ end
- # It should show all the labels on "~".
- type(note, '~')
+ it 'updates issue description with GFM reference' do
+ find('.js-issuable-edit').click
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('alert label')
- end
- end
+ simulate_input('#issue-description', "@#{user.name[0...3]}")
+
+ wait_for_requests
- it 'allows colons when autocompleting scoped labels' do
- create(:label, project: project, title: 'scoped:label')
+ find('.tribute-container .highlight').click
- note = find('#note-body')
- type(note, '~scoped:')
+ click_button 'Save changes'
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('scoped:label')
- end
+ expect(find('.description')).to have_content(user.to_reference)
end
- it 'allows colons when autocompleting scoped labels with double colons' do
- create(:label, project: project, title: 'scoped::label')
+ it 'opens autocomplete menu when field starts with text' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@')
+ end
- note = find('#note-body')
- type(note, '~scoped::')
+ expect(page).to have_selector('.tribute-container')
+ end
+
+ 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('@ev')
+ end
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('scoped::label')
+ expect(page).to have_selector('.tribute-container')
+
+ page.within '.tribute-container ul' do
+ expect(find('li').text).to have_content(user_xss.username)
end
end
- it 'allows spaces when autocompleting multi-word labels' do
- create(:label, project: project, title: 'Accepting merge requests')
+ it 'doesnt open autocomplete menu character is prefixed with text' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('testing')
+ find('#note-body').native.send_keys('@')
+ end
- note = find('#note-body')
- type(note, '~Accepting merge')
+ expect(page).not_to have_selector('.tribute-container')
+ end
+
+ it 'selects the first item for assignee dropdowns' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@')
+ end
+
+ expect(page).to have_selector('.tribute-container')
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('Accepting merge requests')
- end
+ expect(find('.tribute-container ul')).to have_selector('.highlight:first-of-type')
end
- it 'only autocompletes the latest label' do
- create(:label, project: project, title: 'Accepting merge requests')
- create(:label, project: project, title: 'Accepting job applicants')
+ it 'includes items for assignee dropdowns with non-ASCII characters in name' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('')
+ simulate_input('#note-body', "@#{user.name[0...8]}")
+ end
- note = find('#note-body')
- type(note, '~Accepting merge requests foo bar ~Accepting job')
+ expect(page).to have_selector('.tribute-container')
wait_for_requests
- page.within '.atwho-container #at-view-labels' do
- expect(find('.atwho-view-ul').text).to have_content('Accepting job applicants')
- end
+ expect(find('.tribute-container')).to have_content(user.name)
end
- it 'does not autocomplete labels if no tilde is typed' do
- create(:label, project: project, title: 'Accepting merge requests')
+ context 'if a selected value has special characters' do
+ it "shows dropdown after a new line" do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('test')
+ note.native.send_keys(:enter)
+ note.native.send_keys(:enter)
+ note.native.send_keys('@')
+ end
- note = find('#note-body')
- type(note, 'Accepting merge')
+ expect(page).to have_selector('.tribute-container')
+ end
- wait_for_requests
+ it "does not show dropdown when preceded with a special character" do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@")
+ end
- expect(page).not_to have_css('.atwho-container #at-view-labels')
- end
- end
+ expect(page).to have_selector('.tribute-container')
- shared_examples 'autocomplete suggestions' do
- it 'suggests objects correctly' do
- page.within '.timeline-content-form' do
- find('#note-body').native.send_keys(object.class.reference_prefix)
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@")
+ end
+
+ expect(page).to have_selector('.tribute-container', visible: false)
end
- page.within '.atwho-container' do
- expect(page).to have_content(object.title)
+ it 'doesn\'t wrap for assignee values' do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys("@#{user.username[0]}")
+ end
- find('ul li').click
+ user_item = find('.tribute-container li', text: user.username)
+
+ expect_to_wrap(false, user_item, note, user.username)
end
- expect(find('.new-note #note-body').value).to include(expected_body)
- end
- end
+ it 'doesn\'t open autocomplete after non-word character' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys("@#{user.username[0..2]}!")
+ end
- context 'issues' do
- let(:object) { issue }
- let(:expected_body) { object.to_reference }
+ expect(page).not_to have_selector('.tribute-container')
+ end
- it_behaves_like 'autocomplete suggestions'
- end
+ it 'triggers autocomplete after selecting a quick action' do
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('/as')
+ end
- context 'merge requests' do
- let(:object) { create(:merge_request, source_project: project) }
- let(:expected_body) { object.to_reference }
+ find('.atwho-view li', text: '/assign')
+ note.native.send_keys(:tab)
+ note.native.send_keys(:right)
- it_behaves_like 'autocomplete suggestions'
- end
+ wait_for_requests
- context 'project snippets' do
- let!(:object) { create(:project_snippet, project: project, title: 'code snippet') }
- let(:expected_body) { object.to_reference }
+ user_item = find('.tribute-container li', text: user.username)
+ expect(user_item).to have_content(user.username)
+ end
+ end
- it_behaves_like 'autocomplete suggestions'
- end
+ context 'assignees' do
+ let(:issue_assignee) { create(:issue, project: project) }
+ let(:unassigned_user) { create(:user) }
- context 'label' do
- let!(:object) { label }
- let(:expected_body) { object.title }
+ before do
+ issue_assignee.update(assignees: [user])
- it_behaves_like 'autocomplete suggestions'
- end
+ project.add_maintainer(unassigned_user)
+ end
+
+ it 'lists users who are currently not assigned to the issue when using /assign' do
+ visit project_issue_path(project, issue_assignee)
+
+ note = find('#note-body')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('/as')
+ end
- context 'milestone' do
- let!(:object) { create(:milestone, project: project) }
- let(:expected_body) { object.to_reference }
+ find('.atwho-view li', text: '/assign')
+ note.native.send_keys(:tab)
+ note.native.send_keys(:right)
- it_behaves_like 'autocomplete suggestions'
+ 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)
+ end
+ end
end
private