Commit 75e91766 authored by Coung Ngo's avatar Coung Ngo Committed by James Fargher

Refactor gfm_autocomplete_spec.rb for consistency

Before, the file contained several ways to do the same thing.
This commit updates the file to prefer Capybara actions
to make tests less brittle as they rely less on CSS selectors
parent 05c9b146
...@@ -31,315 +31,218 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -31,315 +31,218 @@ RSpec.describe 'GFM autocomplete', :js do
end end
it 'updates issue description with GFM reference' do it 'updates issue description with GFM reference' do
find('.js-issuable-edit').click click_button 'Edit title and description'
wait_for_requests wait_for_requests
simulate_input('#issue-description', "@#{user.name[0...3]}") fill_in 'Description', with: "@#{user.name[0...3]}"
wait_for_requests wait_for_requests
find('.atwho-view .cur').click find_highlighted_autocomplete_item.click
click_button 'Save changes' click_button 'Save changes'
wait_for_requests wait_for_requests
expect(find('.description')).to have_content(user.to_reference) expect(find('.description')).to have_text(user.to_reference)
end end
it 'opens quick action autocomplete when updating description' do it 'opens quick action autocomplete when updating description' do
find('.js-issuable-edit').click click_button 'Edit title and description'
find('#issue-description').native.send_keys('/') fill_in 'Description', with: '/'
expect(page).to have_selector('.atwho-container') expect(find_autocomplete_menu).to be_visible
end end
it 'opens autocomplete menu when field starts with text' do it 'opens autocomplete menu when field starts with text' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@'
find('#note-body').native.send_keys('@')
end
expect(page).to have_selector('.atwho-container') expect(find_autocomplete_menu).to be_visible
end end
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' 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) create(:issue, project: project, title: issue_xss_title)
page.within '.timeline-content-form' do fill_in 'Comment', with: '#'
find('#note-body').native.send_keys('#')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.atwho-container') expect(find_autocomplete_menu).to have_text(issue_xss_title)
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 Username when field starts with text with item escaping HTML characters' do it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@ev'
find('#note-body').native.send_keys('@ev')
end
wait_for_requests wait_for_requests
expect(find_highlighted_autocomplete_item).to have_content(user_xss.username) expect(find_highlighted_autocomplete_item).to have_text(user_xss.username)
end end
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do 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' milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title) create(:milestone, project: project, title: milestone_xss_title)
page.within '.timeline-content-form' do fill_in 'Comment', with: '%'
find('#note-body').native.send_keys('%')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.atwho-container') expect(find_autocomplete_menu).to have_text('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 it 'doesnt open autocomplete menu character is prefixed with text' do
page.within '.timeline-content-form' do fill_in 'Comment', with: 'testing@'
find('#note-body').native.send_keys('testing')
find('#note-body').native.send_keys('@')
end
expect(page).not_to have_selector('.atwho-view') expect(page).not_to have_css('.atwho-view')
end end
it 'doesnt select the first item for non-assignee dropdowns' do it 'doesnt select the first item for non-assignee dropdowns' do
page.within '.timeline-content-form' do fill_in 'Comment', with: ':'
find('#note-body').native.send_keys(':')
end
expect(page).to have_selector('.atwho-container')
wait_for_requests wait_for_requests
expect(find('#at-view-58')).not_to have_selector('.cur:first-of-type') expect(find_autocomplete_menu).not_to have_css('.cur')
end end
it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
note = find('#note-body')
# Number. # Number.
page.within '.timeline-content-form' do fill_in 'Comment', with: '7:'
note.native.send_keys('7:') expect(page).not_to have_css('.atwho-view')
end
expect(page).not_to have_selector('.atwho-view')
# ASCII letter. # ASCII letter.
page.within '.timeline-content-form' do fill_in 'Comment', with: 'w:'
note.set('') expect(page).not_to have_css('.atwho-view')
note.native.send_keys('w:')
end
expect(page).not_to have_selector('.atwho-view')
# Non-ASCII letter. # Non-ASCII letter.
page.within '.timeline-content-form' do fill_in 'Comment', with: 'Ё:'
note.set('') expect(page).not_to have_css('.atwho-view')
note.native.send_keys('Ё:')
end
expect(page).not_to have_selector('.atwho-view')
end end
it 'selects the first item for assignee dropdowns' do it 'selects the first item for assignee dropdowns' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@'
find('#note-body').native.send_keys('@')
end
expect(page).to have_selector('.atwho-container')
wait_for_requests wait_for_requests
expect(find('#at-view-users')).to have_selector('.cur:first-of-type') expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
end end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do it 'includes items for assignee dropdowns with non-ASCII characters in name' do
page.within '.timeline-content-form' do fill_in 'Comment', with: "@#{user.name[0...8]}"
find('#note-body').native.send_keys('')
simulate_input('#note-body', "@#{user.name[0...8]}")
end
expect(page).to have_selector('.atwho-container')
wait_for_requests wait_for_requests
expect(find('#at-view-users')).to have_content(user.name) expect(find_autocomplete_menu).to have_text(user.name)
end end
it 'searches across full name for assignees' do it 'searches across full name for assignees' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@speciąlsome'
find('#note-body').native.send_keys('@speciąlsome')
end
wait_for_requests wait_for_requests
expect(find_highlighted_autocomplete_item).to have_content(user.name) expect(find_highlighted_autocomplete_item).to have_text(user.name)
end end
it 'shows names that start with the query as the top result' do it 'shows names that start with the query as the top result' do
type(find('#note-body'), '@mar') fill_in 'Comment', with: '@mar'
wait_for_requests wait_for_requests
expect(find_highlighted_autocomplete_item).to have_content(user2.name) expect(find_highlighted_autocomplete_item).to have_text(user2.name)
end end
it 'shows usernames that start with the query as the top result' do it 'shows usernames that start with the query as the top result' do
type(find('#note-body'), '@msi') fill_in 'Comment', with: '@msi'
wait_for_requests wait_for_requests
expect(find_highlighted_autocomplete_item).to have_content(user2.name) expect(find_highlighted_autocomplete_item).to have_text(user2.name)
end end
# Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925 # Regression test for https://gitlab.com/gitlab-org/gitlab/-/issues/321925
it 'shows username when pasting then pressing Enter' do it 'shows username when pasting then pressing Enter' do
fill_in 'Comment', with: "@#{user.username}\n" fill_in 'Comment', with: "@#{user.username}\n"
expect(find_field('Comment').value).to have_content "@#{user.username}" expect(find_field('Comment').value).to have_text "@#{user.username}"
end end
it 'does not show `@undefined` when pressing `@` then Enter' do it 'does not show `@undefined` when pressing `@` then Enter' do
fill_in 'Comment', with: "@\n" fill_in 'Comment', with: "@\n"
expect(find_field('Comment').value).to have_content "@" expect(find_field('Comment').value).to have_text '@'
expect(find_field('Comment').value).not_to have_content "@undefined" expect(find_field('Comment').value).not_to have_text '@undefined'
end end
it 'selects the first item for non-assignee dropdowns if a query is entered' do it 'selects the first item for non-assignee dropdowns if a query is entered' do
page.within '.timeline-content-form' do fill_in 'Comment', with: ':1'
find('#note-body').native.send_keys(':1')
end
expect(page).to have_selector('.atwho-container')
wait_for_requests wait_for_requests
expect(find('#at-view-58')).to have_selector('.cur:first-of-type') expect(find_autocomplete_menu).to have_css('.cur:first-of-type')
end end
context 'if a selected value has special characters' do context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do it 'wraps the result in double quotes' do
note = find('#note-body') fill_in 'Comment', with: "~#{label.title[0]}"
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('')
simulate_input('#note-body', "~#{label.title[0]}")
end
label_item = find('.atwho-view li', text: label.title) find_highlighted_autocomplete_item.click
expect_to_wrap(true, label_item, note, label.title) expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
end end
it "shows dropdown after a new line" do it "shows dropdown after a new line" do
note = find('#note-body') fill_in 'Comment', with: "test\n\n@"
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
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).to have_selector('.atwho-container')
page.within '.timeline-content-form' do expect(find_autocomplete_menu).to be_visible
note.native.send_keys("@")
end
expect(page).to have_selector('.atwho-container', visible: false)
end end
it "does not throw an error if no labels exist" do it "does not show dropdown when preceded with a special character" do
note = find('#note-body') fill_in 'Comment', with: '@@'
page.within '.timeline-content-form' do
note.native.send_keys('~')
end
expect(page).to have_selector('.atwho-container', visible: false) expect(page).not_to have_css('.atwho-view')
end end
it 'doesn\'t wrap for assignee values' do it 'doesn\'t wrap for assignee values' do
note = find('#note-body') fill_in 'Comment', with: "@#{user.username[0]}"
page.within '.timeline-content-form' do
note.native.send_keys("@#{user.username[0]}")
end
user_item = find('.atwho-view li', text: user.username) find_highlighted_autocomplete_item.click
expect_to_wrap(false, user_item, note, user.username) expect(find_field('Comment').value).to have_text("@#{user.username}")
end end
it 'doesn\'t wrap for emoji values' do it 'doesn\'t wrap for emoji values' do
note = find('#note-body') fill_in 'Comment', with: ':cartwheel_'
page.within '.timeline-content-form' do
note.native.send_keys(":cartwheel_")
end
emoji_item = find('.atwho-view li', text: 'cartwheel_tone1') find_highlighted_autocomplete_item.click
expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1') expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end end
it 'doesn\'t open autocomplete after non-word character' do it 'doesn\'t open autocomplete after non-word character' do
page.within '.timeline-content-form' do fill_in 'Comment', with: "@#{user.username[0..2]}!"
find('#note-body').native.send_keys("@#{user.username[0..2]}!")
end
expect(page).not_to have_selector('.atwho-view') expect(page).not_to have_css('.atwho-view')
end end
it 'doesn\'t open autocomplete if there is no space before' do it 'doesn\'t open autocomplete if there is no space before' do
page.within '.timeline-content-form' do fill_in 'Comment', with: "hello:#{user.username[0..2]}"
find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
end
expect(page).not_to have_selector('.atwho-view') expect(page).not_to have_css('.atwho-view')
end end
it 'triggers autocomplete after selecting a quick action' do it 'triggers autocomplete after selecting a quick action' do
note = find('#note-body') fill_in 'Comment', with: '/as'
page.within '.timeline-content-form' do
note.native.send_keys('/as')
end
find('.atwho-view li', text: '/assign') find_highlighted_autocomplete_item.click
note.native.send_keys(:tab)
user_item = find('.atwho-view li', text: user.username) expect(find_autocomplete_menu).to have_text(user.username)
expect(user_item).to have_content(user.username)
end end
it 'does not limit quick actions autocomplete list to 5' do it 'does not limit quick actions autocomplete list to 5' do
note = find('#note-body') fill_in 'Comment', with: '/'
page.within '.timeline-content-form' do
note.native.send_keys('/')
end
expect(page).to have_selector('.atwho-view li', minimum: 6, visible: true) expect(find_autocomplete_menu).to have_css('li', minimum: 6)
end end
end end
...@@ -356,30 +259,23 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -356,30 +259,23 @@ RSpec.describe 'GFM autocomplete', :js do
it 'lists users who are currently not assigned to the issue when using /assign' do it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee) visit project_issue_path(project, issue_assignee)
note = find('#note-body') fill_in 'Comment', with: '/as'
page.within '.timeline-content-form' do
note.native.send_keys('/as')
end
find('.atwho-view li', text: '/assign')
note.native.send_keys(:tab)
wait_for_requests find_highlighted_autocomplete_item.click
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username) expect(find_autocomplete_menu).not_to have_text(user.username)
expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username) expect(find_autocomplete_menu).to have_text(unassigned_user.username)
end end
it 'shows dropdown on new issue form' do it 'shows dropdown on new issue form' do
visit new_project_issue_path(project) visit new_project_issue_path(project)
textarea = find('#issue_description') fill_in 'Description', with: '/ass'
textarea.native.send_keys('/ass')
find('.atwho-view li', text: '/assign') find_highlighted_autocomplete_item.click
textarea.native.send_keys(:tab)
expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username) expect(find_autocomplete_menu).to have_text(unassigned_user.username)
expect(find('#at-view-users .atwho-view-ul')).to have_content(user.username) expect(find_autocomplete_menu).to have_text(user.username)
end end
end end
...@@ -388,80 +284,62 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -388,80 +284,62 @@ RSpec.describe 'GFM autocomplete', :js do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title) create(:label, project: project, title: label_xss_title)
note = find('#note-body') fill_in 'Comment', with: '~'
# It should show all the labels on "~".
type(note, '~')
wait_for_requests wait_for_requests
page.within '.atwho-container #at-view-labels' do expect(find_autocomplete_menu).to have_text('alert label')
expect(find('.atwho-view-ul').text).to have_content('alert label')
end
end end
it 'allows colons when autocompleting scoped labels' do it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label') create(:label, project: project, title: 'scoped:label')
note = find('#note-body') fill_in 'Comment', with: '~scoped:'
type(note, '~scoped:')
wait_for_requests wait_for_requests
page.within '.atwho-container #at-view-labels' do expect(find_autocomplete_menu).to have_text('scoped:label')
expect(find('.atwho-view-ul').text).to have_content('scoped:label')
end
end end
it 'allows colons when autocompleting scoped labels with double colons' do it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label') create(:label, project: project, title: 'scoped::label')
note = find('#note-body') fill_in 'Comment', with: '~scoped::'
type(note, '~scoped::')
wait_for_requests wait_for_requests
page.within '.atwho-container #at-view-labels' do expect(find_autocomplete_menu).to have_text('scoped::label')
expect(find('.atwho-view-ul').text).to have_content('scoped::label')
end
end end
it 'allows spaces when autocompleting multi-word labels' do it 'allows spaces when autocompleting multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests') create(:label, project: project, title: 'Accepting merge requests')
note = find('#note-body') fill_in 'Comment', with: '~Accepting merge'
type(note, '~Accepting merge')
wait_for_requests wait_for_requests
page.within '.atwho-container #at-view-labels' do expect(find_autocomplete_menu).to have_text('Accepting merge requests')
expect(find('.atwho-view-ul').text).to have_content('Accepting merge requests')
end
end end
it 'only autocompletes the latest label' do it 'only autocompletes the latest label' do
create(:label, project: project, title: 'Accepting merge requests') create(:label, project: project, title: 'Accepting merge requests')
create(:label, project: project, title: 'Accepting job applicants') create(:label, project: project, title: 'Accepting job applicants')
note = find('#note-body') fill_in 'Comment', with: '~Accepting merge requests foo bar ~Accepting job'
type(note, '~Accepting merge requests foo bar ~Accepting job')
wait_for_requests wait_for_requests
page.within '.atwho-container #at-view-labels' do expect(find_autocomplete_menu).to have_text('Accepting job applicants')
expect(find('.atwho-view-ul').text).to have_content('Accepting job applicants')
end
end end
it 'does not autocomplete labels if no tilde is typed' do it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'Accepting merge requests') create(:label, project: project, title: 'Accepting merge requests')
note = find('#note-body') fill_in 'Comment', with: 'Accepting merge'
type(note, 'Accepting merge')
wait_for_requests wait_for_requests
expect(page).not_to have_css('.atwho-container #at-view-labels') expect(page).not_to have_css('.atwho-view')
end end
end end
...@@ -471,7 +349,7 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -471,7 +349,7 @@ RSpec.describe 'GFM autocomplete', :js do
# This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
it 'keeps autocomplete key listeners' do it 'keeps autocomplete key listeners' do
visit project_issue_path(project, issue) visit project_issue_path(project, issue)
note = find('#note-body') note = find_field('Comment')
start_comment_with_emoji(note, '.atwho-view li') start_comment_with_emoji(note, '.atwho-view li')
...@@ -487,17 +365,11 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -487,17 +365,11 @@ RSpec.describe 'GFM autocomplete', :js do
shared_examples 'autocomplete suggestions' do shared_examples 'autocomplete suggestions' do
it 'suggests objects correctly' do it 'suggests objects correctly' do
page.within '.timeline-content-form' do fill_in 'Comment', with: object.class.reference_prefix
find('#note-body').native.send_keys(object.class.reference_prefix)
end
page.within '.atwho-container' do find_autocomplete_menu.find('li').click
expect(page).to have_content(object.title)
find('ul li').click expect(find_field('Comment').value).to have_text(expected_body)
end
expect(find('.new-note #note-body').value).to include(expected_body)
end end
end end
...@@ -548,237 +420,160 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -548,237 +420,160 @@ RSpec.describe 'GFM autocomplete', :js do
end end
it 'updates issue description with GFM reference' do it 'updates issue description with GFM reference' do
find('.js-issuable-edit').click click_button 'Edit title and description'
wait_for_requests wait_for_requests
simulate_input('#issue-description', "@#{user.name[0...3]}") fill_in 'Description', with: "@#{user.name[0...3]}"
wait_for_requests wait_for_requests
find('.tribute-container .highlight', visible: true).click find_highlighted_tribute_autocomplete_menu.click
click_button 'Save changes' click_button 'Save changes'
wait_for_requests wait_for_requests
expect(find('.description')).to have_content(user.to_reference) expect(find('.description')).to have_text(user.to_reference)
end end
it 'opens autocomplete menu when field starts with text' do it 'opens autocomplete menu when field starts with text' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@'
find('#note-body').native.send_keys('@')
end
expect(page).to have_selector('.tribute-container', visible: true) expect(find_tribute_autocomplete_menu).to be_visible
end end
it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do
issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' 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) create(:issue, project: project, title: issue_xss_title)
page.within '.timeline-content-form' do fill_in 'Comment', with: '#'
find('#note-body').native.send_keys('#')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.tribute-container', visible: true) expect(find_tribute_autocomplete_menu).to have_text(issue_xss_title)
page.within '.tribute-container ul' do
expect(page.all('li').first.text).to include(issue_xss_title)
end
end end
it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@ev'
find('#note-body').native.send_keys('@ev')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.tribute-container', visible: true) expect(find_tribute_autocomplete_menu).to have_text(user_xss.username)
expect(find('.tribute-container ul', visible: true)).to have_text(user_xss.username)
end end
it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do 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' milestone_xss_title = 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:milestone, project: project, title: milestone_xss_title) create(:milestone, project: project, title: milestone_xss_title)
page.within '.timeline-content-form' do fill_in 'Comment', with: '%'
find('#note-body').native.send_keys('%')
end
wait_for_requests wait_for_requests
expect(page).to have_selector('.tribute-container', visible: true) expect(find_tribute_autocomplete_menu).to have_text('alert milestone')
expect(find('.tribute-container ul', visible: true)).to have_text('alert milestone')
end end
it 'does not open autocomplete menu when trigger character is prefixed with text' do it 'does not open autocomplete menu when trigger character is prefixed with text' do
page.within '.timeline-content-form' do fill_in 'Comment', with: 'testing@'
find('#note-body').native.send_keys('testing')
find('#note-body').native.send_keys('@')
end
expect(page).not_to have_selector('.tribute-container', visible: true) expect(page).not_to have_css('.tribute-container')
end end
it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do it 'does not open autocomplete menu when ":" is prefixed by a number and letters' do
note = find('#note-body')
# Number. # Number.
page.within '.timeline-content-form' do fill_in 'Comment', with: '7:'
note.native.send_keys('7:') expect(page).not_to have_css('.tribute-container')
end
expect(page).not_to have_selector('.tribute-container', visible: true)
# ASCII letter. # ASCII letter.
page.within '.timeline-content-form' do fill_in 'Comment', with: 'w:'
note.set('') expect(page).not_to have_css('.tribute-container')
note.native.send_keys('w:')
end
expect(page).not_to have_selector('.tribute-container', visible: true)
# Non-ASCII letter. # Non-ASCII letter.
page.within '.timeline-content-form' do fill_in 'Comment', with: 'Ё:'
note.set('') expect(page).not_to have_css('.tribute-container')
note.native.send_keys('Ё:')
end
expect(page).not_to have_selector('.tribute-container', visible: true)
end end
it 'selects the first item for assignee dropdowns' do it 'selects the first item for assignee dropdowns' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@'
find('#note-body').native.send_keys('@')
end
expect(page).to have_selector('.tribute-container', visible: true)
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type') expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
end end
it 'includes items for assignee dropdowns with non-ASCII characters in name' do it 'includes items for assignee dropdowns with non-ASCII characters in name' do
page.within '.timeline-content-form' do fill_in 'Comment', with: "@#{user.name[0...8]}"
find('#note-body').native.send_keys('')
simulate_input('#note-body', "@#{user.name[0...8]}")
end
expect(page).to have_selector('.tribute-container', visible: true)
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true)).to have_content(user.name) expect(find_tribute_autocomplete_menu).to have_text(user.name)
end end
it 'selects the first item for non-assignee dropdowns if a query is entered' do it 'selects the first item for non-assignee dropdowns if a query is entered' do
page.within '.timeline-content-form' do fill_in 'Comment', with: ':1'
find('#note-body').native.send_keys(':1')
end
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type') expect(find_tribute_autocomplete_menu).to have_css('.highlight:first-of-type')
end end
context 'when autocompleting for groups' do context 'when autocompleting for groups' do
it 'shows the group when searching for the name of the group' do it 'shows the group when searching for the name of the group' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@mygroup'
find('#note-body').native.send_keys('@mygroup')
end
expect(find('.tribute-container ul', visible: true)).to have_text('My group') expect(find_tribute_autocomplete_menu).to have_text('My group')
end end
it 'does not show the group when searching for the name of the parent of the group' do it 'does not show the group when searching for the name of the parent of the group' do
page.within '.timeline-content-form' do fill_in 'Comment', with: '@ancestor'
find('#note-body').native.send_keys('@ancestor')
end
expect(find('.tribute-container ul', visible: true)).not_to have_text('My group') expect(find_tribute_autocomplete_menu).not_to have_text('My group')
end end
end end
context 'if a selected value has special characters' do context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do it 'wraps the result in double quotes' do
note = find('#note-body') fill_in 'Comment', with: "~#{label.title[0]}"
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('')
simulate_input('#note-body', "~#{label.title[0]}")
end
label_item = find('.tribute-container ul', text: label.title, visible: true) find_highlighted_tribute_autocomplete_menu.click
expect_to_wrap(true, label_item, note, label.title) expect(find_field('Comment').value).to have_text("~\"#{label.title}\"")
end end
it "shows dropdown after a new line" do it "shows dropdown after a new line" do
note = find('#note-body') fill_in 'Comment', with: "test\n\n@"
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('.tribute-container', visible: true)
end
it "does not throw an error if no labels exist" do expect(find_tribute_autocomplete_menu).to be_visible
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('~')
end
expect(page).to have_selector('.tribute-container', visible: false)
end end
it 'doesn\'t wrap for assignee values' do it 'doesn\'t wrap for assignee values' do
note = find('#note-body') fill_in 'Comment', with: "@#{user.username[0..2]}"
page.within '.timeline-content-form' do
note.native.send_keys("@#{user.username[0]}")
end
user_item = find('.tribute-container ul', text: user.username, visible: true) find_highlighted_tribute_autocomplete_menu.click
expect_to_wrap(false, user_item, note, user.username) expect(find_field('Comment').value).to have_text("@#{user.username}")
end end
it 'does not wrap for emoji values' do it 'does not wrap for emoji values' do
note = find('#note-body') fill_in 'Comment', with: ':cartwheel_'
page.within '.timeline-content-form' do
note.native.send_keys(":cartwheel_")
end
emoji_item = first('.tribute-container li', text: 'cartwheel_tone1', visible: true) find_highlighted_tribute_autocomplete_menu.click
expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1') expect(find_field('Comment').value).to have_text('cartwheel_tone1')
end end
it 'does not open autocomplete if there is no space before' do it 'does not open autocomplete if there is no space before' do
page.within '.timeline-content-form' do fill_in 'Comment', with: "hello:#{user.username[0..2]}"
find('#note-body').native.send_keys("hello:#{user.username[0..2]}")
end
expect(page).not_to have_selector('.tribute-container') expect(page).not_to have_css('.tribute-container')
end end
it 'autocompletes for quick actions' do it 'autocompletes for quick actions' do
note = find('#note-body') fill_in 'Comment', with: '/as'
page.within '.timeline-content-form' do
note.native.send_keys('/as') find_highlighted_tribute_autocomplete_menu.click
wait_for_requests
note.native.send_keys(:tab) expect(find_field('Comment').value).to have_text('/assign')
end
expect(note.value).to have_text('/assign')
end end
end end
...@@ -795,37 +590,33 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -795,37 +590,33 @@ RSpec.describe 'GFM autocomplete', :js do
it 'lists users who are currently not assigned to the issue when using /assign' do it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee) visit project_issue_path(project, issue_assignee)
note = find('#note-body') note = find_field('Comment')
page.within '.timeline-content-form' do note.native.send_keys('/assign ')
note.native.send_keys('/assign ') # The `/assign` ajax response might replace the one by `@` below causing a failed test
# 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
# so we need to wait for the `/assign` ajax request to finish first wait_for_requests
wait_for_requests note.native.send_keys('@')
note.native.send_keys('@') wait_for_requests
wait_for_requests
end expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username)
expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username)
end end
it 'lists users who are currently not assigned to the issue when using /assign on the second line' do 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) visit project_issue_path(project, issue_assignee)
note = find('#note-body') note = find_field('Comment')
page.within '.timeline-content-form' do note.native.send_keys('/assign @user2')
note.native.send_keys('/assign @user2') note.native.send_keys(:enter)
note.native.send_keys(:enter) note.native.send_keys('/assign ')
note.native.send_keys('/assign ') # The `/assign` ajax response might replace the one by `@` below causing a failed test
# 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
# so we need to wait for the `/assign` ajax request to finish first wait_for_requests
wait_for_requests note.native.send_keys('@')
note.native.send_keys('@') wait_for_requests
wait_for_requests
end expect(find_tribute_autocomplete_menu).not_to have_text(user.username)
expect(find_tribute_autocomplete_menu).to have_text(unassigned_user.username)
expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username)
expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username)
end end
end end
...@@ -834,72 +625,65 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -834,72 +625,65 @@ RSpec.describe 'GFM autocomplete', :js do
label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' label_xss_title = 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'
create(:label, project: project, title: label_xss_title) create(:label, project: project, title: label_xss_title)
note = find('#note-body') fill_in 'Comment', with: '~'
# It should show all the labels on "~".
type(note, '~')
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content('alert label') expect(find_tribute_autocomplete_menu).to have_text('alert label')
end end
it 'allows colons when autocompleting scoped labels' do it 'allows colons when autocompleting scoped labels' do
create(:label, project: project, title: 'scoped:label') create(:label, project: project, title: 'scoped:label')
note = find('#note-body') fill_in 'Comment', with: '~scoped:'
type(note, '~scoped:')
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content('scoped:label') expect(find_tribute_autocomplete_menu).to have_text('scoped:label')
end end
it 'allows colons when autocompleting scoped labels with double colons' do it 'allows colons when autocompleting scoped labels with double colons' do
create(:label, project: project, title: 'scoped::label') create(:label, project: project, title: 'scoped::label')
note = find('#note-body') fill_in 'Comment', with: '~scoped::'
type(note, '~scoped::')
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content('scoped::label') expect(find_tribute_autocomplete_menu).to have_text('scoped::label')
end end
it 'autocompletes multi-word labels' do it 'autocompletes multi-word labels' do
create(:label, project: project, title: 'Accepting merge requests') create(:label, project: project, title: 'Accepting merge requests')
note = find('#note-body') fill_in 'Comment', with: '~Acceptingmerge'
type(note, '~Acceptingmerge')
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content('Accepting merge requests') expect(find_tribute_autocomplete_menu).to have_text('Accepting merge requests')
end end
it 'only autocompletes the latest label' do it 'only autocompletes the latest label' do
create(:label, project: project, title: 'documentation') create(:label, project: project, title: 'documentation')
create(:label, project: project, title: 'feature') create(:label, project: project, title: 'feature')
note = find('#note-body') fill_in 'Comment', with: '~documentation foo bar ~feat'
type(note, '~documentation foo bar ~feat') # Invoke autocompletion
note.native.send_keys(:right) find_field('Comment').native.send_keys(:right)
wait_for_requests wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content('feature') expect(find_tribute_autocomplete_menu).to have_text('feature')
expect(find('.tribute-container ul', visible: true).text).not_to have_content('documentation') expect(find_tribute_autocomplete_menu).not_to have_text('documentation')
end end
it 'does not autocomplete labels if no tilde is typed' do it 'does not autocomplete labels if no tilde is typed' do
create(:label, project: project, title: 'documentation') create(:label, project: project, title: 'documentation')
note = find('#note-body') fill_in 'Comment', with: 'document'
type(note, 'document')
wait_for_requests wait_for_requests
expect(page).not_to have_selector('.tribute-container') expect(page).not_to have_css('.tribute-container')
end end
end end
...@@ -909,7 +693,7 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -909,7 +693,7 @@ RSpec.describe 'GFM autocomplete', :js do
# This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729
it 'keeps autocomplete key listeners' do it 'keeps autocomplete key listeners' do
visit project_issue_path(project, issue) visit project_issue_path(project, issue)
note = find('#note-body') note = find_field('Comment')
start_comment_with_emoji(note, '.tribute-container li') start_comment_with_emoji(note, '.tribute-container li')
...@@ -925,17 +709,11 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -925,17 +709,11 @@ RSpec.describe 'GFM autocomplete', :js do
shared_examples 'autocomplete suggestions' do shared_examples 'autocomplete suggestions' do
it 'suggests objects correctly' do it 'suggests objects correctly' do
page.within '.timeline-content-form' do fill_in 'Comment', with: object.class.reference_prefix
find('#note-body').native.send_keys(object.class.reference_prefix)
end
page.within '.tribute-container' do find_tribute_autocomplete_menu.find('li').click
expect(page).to have_content(object.title)
find('ul li').click expect(find_field('Comment').value).to have_text(expected_body)
end
expect(find('.new-note #note-body').value).to include(expected_body)
end end
end end
...@@ -977,42 +755,6 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -977,42 +755,6 @@ RSpec.describe 'GFM autocomplete', :js do
private private
def expect_to_wrap(should_wrap, item, note, value)
expect(item).to have_content(value)
expect(item).not_to have_content("\"#{value}\"")
item.click
if should_wrap
expect(note.value).to include("\"#{value}\"")
else
expect(note.value).not_to include("\"#{value}\"")
end
end
def expect_labels(shown: nil, not_shown: nil)
page.within('.atwho-container') do
if shown
expect(page).to have_selector('.atwho-view li', count: shown.size)
shown.each { |label| expect(page).to have_content(label.title) }
end
if not_shown
expect(page).not_to have_selector('.atwho-view li') unless shown
not_shown.each { |label| expect(page).not_to have_content(label.title) }
end
end
end
# `note` is a textarea where the given text should be typed.
# We don't want to find it each time this function gets called.
def type(note, text)
page.within('.timeline-content-form') do
note.set('')
note.native.send_keys(text)
end
end
def start_comment_with_emoji(note, selector) def start_comment_with_emoji(note, selector)
note.native.send_keys('Hello :10') note.native.send_keys('Hello :10')
...@@ -1022,9 +764,7 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -1022,9 +764,7 @@ RSpec.describe 'GFM autocomplete', :js do
end end
def start_and_cancel_discussion def start_and_cancel_discussion
find_field('Reply…').click fill_in('Reply to comment', with: 'Whoops!')
fill_in('note_note', with: 'Whoops!')
page.accept_alert 'Are you sure you want to cancel creating this comment?' do page.accept_alert 'Are you sure you want to cancel creating this comment?' do
click_button('Cancel') click_button('Cancel')
...@@ -1033,7 +773,19 @@ RSpec.describe 'GFM autocomplete', :js do ...@@ -1033,7 +773,19 @@ RSpec.describe 'GFM autocomplete', :js do
wait_for_requests wait_for_requests
end end
def find_autocomplete_menu
find('.atwho-view ul', visible: true)
end
def find_highlighted_autocomplete_item def find_highlighted_autocomplete_item
find('.atwho-view li.cur', visible: true) find('.atwho-view li.cur', visible: true)
end end
def find_tribute_autocomplete_menu
find('.tribute-container ul', visible: true)
end
def find_highlighted_tribute_autocomplete_menu
find('.tribute-container li.highlight', visible: true)
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment