summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-02 13:03:23 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-02 13:03:23 +0000
commita72a9af092c1bfcf9f8024d59c11cf222f07e1e7 (patch)
tree44b60265c1d476d026b2862d2c1244748f558d4f /spec
parentb085478c4c2bed74fdc6eb2c33bfc62e791baf03 (diff)
downloadgitlab-ce-a72a9af092c1bfcf9f8024d59c11cf222f07e1e7.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/resource_weight_events.rb8
-rw-r--r--spec/features/admin/admin_runners_spec.rb24
-rw-r--r--spec/features/boards/boards_spec.rb2
-rw-r--r--spec/features/boards/modal_filter_spec.rb2
-rw-r--r--spec/features/dashboard/issues_filter_spec.rb6
-rw-r--r--spec/features/dashboard/issues_spec.rb2
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/groups/issues_spec.rb2
-rw-r--r--spec/features/groups/merge_requests_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_base_spec.rb8
-rw-r--r--spec/features/issues/filtered_search/dropdown_emoji_spec.rb12
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb30
-rw-r--r--spec/features/issues/filtered_search/dropdown_label_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_release_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb164
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb31
-rw-r--r--spec/features/labels_hierarchy_spec.rb6
-rw-r--r--spec/features/merge_requests/filters_generic_behavior_spec.rb2
-rw-r--r--spec/features/merge_requests/user_filters_by_assignees_spec.rb6
-rw-r--r--spec/features/merge_requests/user_filters_by_labels_spec.rb6
-rw-r--r--spec/features/merge_requests/user_filters_by_milestones_spec.rb10
-rw-r--r--spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb4
-rw-r--r--spec/features/merge_requests/user_filters_by_target_branch_spec.rb6
-rw-r--r--spec/frontend/error_tracking/components/error_tracking_list_spec.js101
-rw-r--r--spec/frontend/filtered_search/filtered_search_token_keys_spec.js2
-rw-r--r--spec/frontend/helpers/stub_children.js3
-rw-r--r--spec/frontend/pages/admin/users/components/user_modal_manager_spec.js8
-rw-r--r--spec/javascripts/droplab/drop_down_spec.js13
-rw-r--r--spec/javascripts/filtered_search/dropdown_utils_spec.js14
-rw-r--r--spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js43
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js16
-rw-r--r--spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js88
-rw-r--r--spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js1
-rw-r--r--spec/javascripts/filtered_search/visual_token_value_spec.js10
-rw-r--r--spec/javascripts/helpers/filtered_search_spec_helper.js17
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/resource_weight_event_spec.rb75
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb78
-rw-r--r--spec/rubocop/cop/migration/add_column_with_default_spec.rb2
-rw-r--r--spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb21
-rw-r--r--spec/support/helpers/filtered_search_helpers.rb13
-rw-r--r--spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb2
47 files changed, 622 insertions, 249 deletions
diff --git a/spec/factories/resource_weight_events.rb b/spec/factories/resource_weight_events.rb
new file mode 100644
index 00000000000..cb9a34df332
--- /dev/null
+++ b/spec/factories/resource_weight_events.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :resource_weight_event do
+ issue { create(:issue) }
+ user { issue&.author || create(:user) }
+ end
+end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 0d5f5df71b6..6bcadda6523 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -57,7 +57,7 @@ describe "Admin Runners" do
expect(page).to have_content 'runner-active'
expect(page).to have_content 'runner-paused'
- input_filtered_search_keys('status:active')
+ input_filtered_search_keys('status=active')
expect(page).to have_content 'runner-active'
expect(page).not_to have_content 'runner-paused'
end
@@ -68,7 +68,7 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('status:offline')
+ input_filtered_search_keys('status=offline')
expect(page).not_to have_content 'runner-active'
expect(page).not_to have_content 'runner-paused'
@@ -83,12 +83,12 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('status:active')
+ input_filtered_search_keys('status=active')
expect(page).to have_content 'runner-a-1'
expect(page).to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
- input_filtered_search_keys('status:active runner-a')
+ input_filtered_search_keys('status=active runner-a')
expect(page).to have_content 'runner-a-1'
expect(page).not_to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
@@ -105,7 +105,7 @@ describe "Admin Runners" do
expect(page).to have_content 'runner-project'
expect(page).to have_content 'runner-group'
- input_filtered_search_keys('type:project_type')
+ input_filtered_search_keys('type=project_type')
expect(page).to have_content 'runner-project'
expect(page).not_to have_content 'runner-group'
end
@@ -116,7 +116,7 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('type:instance_type')
+ input_filtered_search_keys('type=instance_type')
expect(page).not_to have_content 'runner-project'
expect(page).not_to have_content 'runner-group'
@@ -131,12 +131,12 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('type:project_type')
+ input_filtered_search_keys('type=project_type')
expect(page).to have_content 'runner-a-1'
expect(page).to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
- input_filtered_search_keys('type:project_type runner-a')
+ input_filtered_search_keys('type=project_type runner-a')
expect(page).to have_content 'runner-a-1'
expect(page).not_to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
@@ -153,7 +153,7 @@ describe "Admin Runners" do
expect(page).to have_content 'runner-blue'
expect(page).to have_content 'runner-red'
- input_filtered_search_keys('tag:blue')
+ input_filtered_search_keys('tag=blue')
expect(page).to have_content 'runner-blue'
expect(page).not_to have_content 'runner-red'
@@ -165,7 +165,7 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('tag:red')
+ input_filtered_search_keys('tag=red')
expect(page).not_to have_content 'runner-blue'
expect(page).not_to have_content 'runner-blue'
@@ -179,13 +179,13 @@ describe "Admin Runners" do
visit admin_runners_path
- input_filtered_search_keys('tag:blue')
+ input_filtered_search_keys('tag=blue')
expect(page).to have_content 'runner-a-1'
expect(page).to have_content 'runner-b-1'
expect(page).not_to have_content 'runner-a-2'
- input_filtered_search_keys('tag:blue runner-a')
+ input_filtered_search_keys('tag=blue runner-a')
expect(page).to have_content 'runner-a-1'
expect(page).not_to have_content 'runner-b-1'
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index c740e4e26d9..a5f98e82c33 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -628,7 +628,7 @@ describe 'Issue Boards', :js do
end
def set_filter(type, text)
- find('.filtered-search').native.send_keys("#{type}:#{text}")
+ find('.filtered-search').native.send_keys("#{type}=#{text}")
end
def submit_filter
diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb
index 70bc067f79d..d14041ecf3f 100644
--- a/spec/features/boards/modal_filter_spec.rb
+++ b/spec/features/boards/modal_filter_spec.rb
@@ -211,7 +211,7 @@ describe 'Issue Boards add issue modal filtering', :js do
end
def set_filter(type, text = '')
- find('.add-issues-modal .filtered-search').native.send_keys("#{type}:#{text}")
+ find('.add-issues-modal .filtered-search').native.send_keys("#{type}=#{text}")
end
def submit_filter
diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb
index 1352e1bd8fc..8e7fd1f500f 100644
--- a/spec/features/dashboard/issues_filter_spec.rb
+++ b/spec/features/dashboard/issues_filter_spec.rb
@@ -28,14 +28,14 @@ describe 'Dashboard Issues filtering', :js do
context 'filtering by milestone' do
it 'shows all issues with no milestone' do
- input_filtered_search("milestone:none")
+ input_filtered_search("milestone=none")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_selector('.issue', count: 1)
end
it 'shows all issues with the selected milestone' do
- input_filtered_search("milestone:%\"#{milestone.title}\"")
+ input_filtered_search("milestone=%\"#{milestone.title}\"")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_selector('.issue', count: 1)
@@ -63,7 +63,7 @@ describe 'Dashboard Issues filtering', :js do
let!(:label_link) { create(:label_link, label: label, target: issue) }
it 'shows all issues with the selected label' do
- input_filtered_search("label:~#{label.title}")
+ input_filtered_search("label=~#{label.title}")
page.within 'ul.content-list' do
expect(page).to have_content issue.title
diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb
index cb055ff8416..a2ead1b5d33 100644
--- a/spec/features/dashboard/issues_spec.rb
+++ b/spec/features/dashboard/issues_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe 'Dashboard Issues' do
it 'shows issues when current user is author', :js do
reset_filters
- input_filtered_search("author:#{current_user.to_reference}")
+ input_filtered_search("author=#{current_user.to_reference}")
expect(page).to have_content(authored_issue.title)
expect(page).to have_content(authored_issue_on_public_project.title)
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 0c1e1d5910b..bb515cfae82 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -107,7 +107,7 @@ describe 'Dashboard Merge Requests' do
it 'shows authored merge requests', :js do
reset_filters
- input_filtered_search("author:#{current_user.to_reference}")
+ input_filtered_search("author=#{current_user.to_reference}")
expect(page).to have_content(authored_merge_request.title)
expect(page).to have_content(authored_merge_request_from_fork.title)
@@ -120,7 +120,7 @@ describe 'Dashboard Merge Requests' do
it 'shows labeled merge requests', :js do
reset_filters
- input_filtered_search("label:#{label.name}")
+ input_filtered_search("label=#{label.name}")
expect(page).to have_content(labeled_merge_request.title)
diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb
index b9b233026fd..a3fa87e3242 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -48,7 +48,7 @@ describe 'Group issues page' do
let(:user2) { user_outside_group }
it 'filters by only group users' do
- filtered_search.set('assignee:')
+ filtered_search.set('assignee=')
expect(find('#js-dropdown-assignee .filter-dropdown')).to have_content(user.name)
expect(find('#js-dropdown-assignee .filter-dropdown')).not_to have_content(user2.name)
diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb
index 59230d6891a..0038a8e4892 100644
--- a/spec/features/groups/merge_requests_spec.rb
+++ b/spec/features/groups/merge_requests_spec.rb
@@ -52,7 +52,7 @@ describe 'Group merge requests page' do
let(:user2) { user_outside_group }
it 'filters by assignee only group users' do
- filtered_search.set('assignee:')
+ filtered_search.set('assignee=')
expect(find('#js-dropdown-assignee .filter-dropdown')).to have_content(user.name)
expect(find('#js-dropdown-assignee .filter-dropdown')).not_to have_content(user2.name)
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 2d7f5822996..8aa29cddd5f 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -20,13 +20,13 @@ describe 'Dropdown assignee', :js do
describe 'behavior' do
it 'loads all the assignees when opened' do
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
expect_filtered_search_dropdown_results(filter_dropdown, 2)
end
it 'shows current user at top of dropdown' do
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
expect(filter_dropdown.first('.filter-dropdown-item')).to have_content(user.name)
end
@@ -35,7 +35,7 @@ describe 'Dropdown assignee', :js do
describe 'selecting from dropdown without Ajax call' do
before do
Gitlab::Testing::RequestBlockerMiddleware.block_requests!
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
end
after do
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 6567bbcf8a2..c95bd7071b3 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -20,13 +20,13 @@ describe 'Dropdown author', :js do
describe 'behavior' do
it 'loads all the authors when opened' do
- input_filtered_search('author:', submit: false, extra_space: false)
+ input_filtered_search('author=', submit: false, extra_space: false)
expect_filtered_search_dropdown_results(filter_dropdown, 2)
end
it 'shows current user at top of dropdown' do
- input_filtered_search('author:', submit: false, extra_space: false)
+ input_filtered_search('author=', submit: false, extra_space: false)
expect(filter_dropdown.first('.filter-dropdown-item')).to have_content(user.name)
end
@@ -35,7 +35,7 @@ describe 'Dropdown author', :js do
describe 'selecting from dropdown without Ajax call' do
before do
Gitlab::Testing::RequestBlockerMiddleware.block_requests!
- input_filtered_search('author:', submit: false, extra_space: false)
+ input_filtered_search('author=', submit: false, extra_space: false)
end
after do
diff --git a/spec/features/issues/filtered_search/dropdown_base_spec.rb b/spec/features/issues/filtered_search/dropdown_base_spec.rb
index 0a8d768fe49..2a800f054a0 100644
--- a/spec/features/issues/filtered_search/dropdown_base_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_base_spec.rb
@@ -27,14 +27,14 @@ describe 'Dropdown base', :js do
it 'shows loading indicator when opened' do
slow_requests do
# We aren't using `input_filtered_search` because we want to see the loading indicator
- filtered_search.set('assignee:')
+ filtered_search.set('assignee=')
expect(page).to have_css("#{js_dropdown_assignee} .filter-dropdown-loading", visible: true)
end
end
it 'hides loading indicator when loaded' do
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
expect(find(js_dropdown_assignee)).not_to have_css('.filter-dropdown-loading')
end
@@ -42,7 +42,7 @@ describe 'Dropdown base', :js do
describe 'caching requests' do
it 'caches requests after the first load' do
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
initial_size = dropdown_assignee_size
expect(initial_size).to be > 0
@@ -50,7 +50,7 @@ describe 'Dropdown base', :js do
new_user = create(:user)
project.add_maintainer(new_user)
find('.filtered-search-box .clear-search').click
- input_filtered_search('assignee:', submit: false, extra_space: false)
+ input_filtered_search('assignee=', submit: false, extra_space: false)
expect(dropdown_assignee_size).to eq(initial_size)
end
diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
index 324f39cbd2c..4c11f83318b 100644
--- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb
@@ -26,8 +26,8 @@ describe 'Dropdown emoji', :js do
end
describe 'behavior' do
- it 'does not open when the search bar has my-reaction:' do
- filtered_search.set('my-reaction:')
+ it 'does not open when the search bar has my-reaction=' do
+ filtered_search.set('my-reaction=')
expect(page).not_to have_css(js_dropdown_emoji)
end
@@ -42,20 +42,20 @@ describe 'Dropdown emoji', :js do
end
describe 'behavior' do
- it 'opens when the search bar has my-reaction:' do
- filtered_search.set('my-reaction:')
+ it 'opens when the search bar has my-reaction=' do
+ filtered_search.set('my-reaction=')
expect(page).to have_css(js_dropdown_emoji, visible: true)
end
it 'loads all the emojis when opened' do
- input_filtered_search('my-reaction:', submit: false, extra_space: false)
+ input_filtered_search('my-reaction=', submit: false, extra_space: false)
expect_filtered_search_dropdown_results(filter_dropdown, 3)
end
it 'shows the most populated emoji at top of dropdown' do
- input_filtered_search('my-reaction:', submit: false, extra_space: false)
+ input_filtered_search('my-reaction=', submit: false, extra_space: false)
expect(first("#{js_dropdown_emoji} .filter-dropdown li")).to have_content(award_emoji_star.name)
end
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index 5994f3a7902..10b092c6957 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -9,11 +9,16 @@ describe 'Dropdown hint', :js do
let!(:user) { create(:user) }
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_hint) { '#js-dropdown-hint' }
+ let(:js_dropdown_operator) { '#js-dropdown-operator' }
def click_hint(text)
find('#js-dropdown-hint .filter-dropdown .filter-dropdown-item', text: text).click
end
+ def click_operator(op)
+ find("#js-dropdown-operator .filter-dropdown .filter-dropdown-item[data-value='#{op}']").click
+ end
+
before do
project.add_maintainer(user)
create(:issue, project: project)
@@ -27,7 +32,7 @@ describe 'Dropdown hint', :js do
it 'does not exist my-reaction dropdown item' do
expect(page).to have_css(js_dropdown_hint, visible: false)
- expect(page).not_to have_content('my-reaction')
+ expect(page).not_to have_content('My-reaction')
end
end
@@ -54,15 +59,6 @@ describe 'Dropdown hint', :js do
end
describe 'filtering' do
- it 'does not filter `Press Enter or click to search`' do
- filtered_search.set('randomtext')
-
- hint_dropdown = find(js_dropdown_hint)
-
- expect(hint_dropdown).to have_content('Press Enter or click to search')
- expect(hint_dropdown).to have_selector('.filter-dropdown .filter-dropdown-item', count: 0)
- end
-
it 'filters with text' do
filtered_search.set('a')
@@ -76,21 +72,27 @@ describe 'Dropdown hint', :js do
end
it 'opens the token dropdown when you click on it' do
- click_hint('author')
+ click_hint('Author')
expect(page).to have_css(js_dropdown_hint, visible: false)
+ expect(page).to have_css(js_dropdown_operator, visible: true)
+
+ click_operator('=')
+
+ expect(page).to have_css(js_dropdown_hint, visible: false)
+ expect(page).to have_css(js_dropdown_operator, visible: false)
expect(page).to have_css('#js-dropdown-author', visible: true)
- expect_tokens([{ name: 'Author' }])
+ expect_tokens([{ name: 'Author', operator: '=' }])
expect_filtered_search_input_empty
end
end
describe 'reselecting from dropdown' do
it 'reuses existing token text' do
- filtered_search.send_keys('author:')
+ filtered_search.send_keys('author')
filtered_search.send_keys(:backspace)
filtered_search.send_keys(:backspace)
- click_hint('author')
+ click_hint('Author')
expect_tokens([{ name: 'Author' }])
expect_filtered_search_input_empty
diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb
index 45112b01eac..1e90efc8d56 100644
--- a/spec/features/issues/filtered_search/dropdown_label_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb
@@ -21,7 +21,7 @@ describe 'Dropdown label', :js do
describe 'behavior' do
it 'loads all the labels when opened' do
create(:label, project: project, title: 'bug-label')
- filtered_search.set('label:')
+ filtered_search.set('label=')
expect_filtered_search_dropdown_results(filter_dropdown, 1)
end
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index 2f18aa8abaa..1f62a8e0c8d 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -23,7 +23,7 @@ describe 'Dropdown milestone', :js do
describe 'behavior' do
before do
- filtered_search.set('milestone:')
+ filtered_search.set('milestone=')
end
it 'loads all the milestones when opened' do
diff --git a/spec/features/issues/filtered_search/dropdown_release_spec.rb b/spec/features/issues/filtered_search/dropdown_release_spec.rb
index b9cce5c6998..fd0a98f9ddc 100644
--- a/spec/features/issues/filtered_search/dropdown_release_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_release_spec.rb
@@ -23,7 +23,7 @@ describe 'Dropdown release', :js do
describe 'behavior' do
before do
- filtered_search.set('release:')
+ filtered_search.set('release=')
end
it 'loads all the releases when opened' do
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 12e010e293a..c99c205d5da 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -67,7 +67,7 @@ describe 'Filter issues', :js do
it 'filters by all available tokens' do
search_term = 'issue'
- input_filtered_search("assignee:@#{user.username} author:@#{user.username} label:~#{caps_sensitive_label.title} milestone:%#{milestone.title} #{search_term}")
+ input_filtered_search("assignee=@#{user.username} author=@#{user.username} label=~#{caps_sensitive_label.title} milestone=%#{milestone.title} #{search_term}")
wait_for_requests
@@ -84,7 +84,7 @@ describe 'Filter issues', :js do
describe 'filter issues by author' do
context 'only author' do
it 'filters issues by searched author' do
- input_filtered_search("author:@#{user.username}")
+ input_filtered_search("author=@#{user.username}")
wait_for_requests
@@ -98,7 +98,7 @@ describe 'Filter issues', :js do
describe 'filter issues by assignee' do
context 'only assignee' do
it 'filters issues by searched assignee' do
- input_filtered_search("assignee:@#{user.username}")
+ input_filtered_search("assignee=@#{user.username}")
wait_for_requests
@@ -108,7 +108,7 @@ describe 'Filter issues', :js do
end
it 'filters issues by no assignee' do
- input_filtered_search('assignee:none')
+ input_filtered_search('assignee=none')
expect_tokens([assignee_token('None')])
expect_issues_list_count(3)
@@ -122,7 +122,7 @@ describe 'Filter issues', :js do
it 'filters issues by multiple assignees' do
create(:issue, project: project, author: user, assignees: [user2, user])
- input_filtered_search("assignee:@#{user.username} assignee:@#{user2.username}")
+ input_filtered_search("assignee=@#{user.username} assignee=@#{user2.username}")
expect_tokens([
assignee_token(user.name),
@@ -138,15 +138,31 @@ describe 'Filter issues', :js do
describe 'filter issues by label' do
context 'only label' do
it 'filters issues by searched label' do
- input_filtered_search("label:~#{bug_label.title}")
+ input_filtered_search("label=~#{bug_label.title}")
expect_tokens([label_token(bug_label.title)])
expect_issues_list_count(2)
expect_filtered_search_input_empty
end
+ it 'filters issues not containing searched label' do
+ input_filtered_search("label!=~#{bug_label.title}")
+
+ expect_tokens([label_token(bug_label.title)])
+ expect_issues_list_count(6)
+ expect_filtered_search_input_empty
+ end
+
+ it 'filters issues by no label' do
+ input_filtered_search('label=none')
+
+ expect_tokens([label_token('None', false)])
+ expect_issues_list_count(4)
+ expect_filtered_search_input_empty
+ end
+
it 'filters issues by no label' do
- input_filtered_search('label:none')
+ input_filtered_search('label!=none')
expect_tokens([label_token('None', false)])
expect_issues_list_count(4)
@@ -154,7 +170,18 @@ describe 'Filter issues', :js do
end
it 'filters issues by multiple labels' do
- input_filtered_search("label:~#{bug_label.title} label:~#{caps_sensitive_label.title}")
+ input_filtered_search("label=~#{bug_label.title} label=~#{caps_sensitive_label.title}")
+
+ expect_tokens([
+ label_token(bug_label.title),
+ label_token(caps_sensitive_label.title)
+ ])
+ expect_issues_list_count(1)
+ expect_filtered_search_input_empty
+ end
+
+ it 'filters issues by multiple labels with not operator' do
+ input_filtered_search("label!=~#{bug_label.title} label=~#{caps_sensitive_label.title}")
expect_tokens([
label_token(bug_label.title),
@@ -169,22 +196,42 @@ describe 'Filter issues', :js do
special_issue = create(:issue, title: "Issue with special character label", project: project)
special_issue.labels << special_label
- input_filtered_search("label:~#{special_label.title}")
+ input_filtered_search("label=~#{special_label.title}")
expect_tokens([label_token(special_label.title)])
expect_issues_list_count(1)
expect_filtered_search_input_empty
end
+ it 'filters issues by label not containing special characters' do
+ special_label = create(:label, project: project, title: '!@#{$%^&*()-+[]<>?/:{}|\}')
+ special_issue = create(:issue, title: "Issue with special character label", project: project)
+ special_issue.labels << special_label
+
+ input_filtered_search("label!=~#{special_label.title}")
+
+ expect_tokens([label_token(special_label.title)])
+ expect_issues_list_count(8)
+ expect_filtered_search_input_empty
+ end
+
it 'does not show issues for unused labels' do
new_label = create(:label, project: project, title: 'new_label')
- input_filtered_search("label:~#{new_label.title}")
+ input_filtered_search("label=~#{new_label.title}")
expect_tokens([label_token(new_label.title)])
expect_no_issues_list
expect_filtered_search_input_empty
end
+
+ it 'does show issues for bug label' do
+ input_filtered_search("label!=~#{bug_label.title}")
+
+ expect_tokens([label_token(bug_label.title)])
+ expect_issues_list_count(6)
+ expect_filtered_search_input_empty
+ end
end
context 'label with multiple words' do
@@ -193,7 +240,7 @@ describe 'Filter issues', :js do
special_multiple_issue = create(:issue, title: "Issue with special character multiple words label", project: project)
special_multiple_issue.labels << special_multiple_label
- input_filtered_search("label:~'#{special_multiple_label.title}'")
+ input_filtered_search("label=~'#{special_multiple_label.title}'")
# Check for search results (which makes sure that the page has changed)
expect_issues_list_count(1)
@@ -205,7 +252,7 @@ describe 'Filter issues', :js do
end
it 'single quotes' do
- input_filtered_search("label:~'#{multiple_words_label.title}'")
+ input_filtered_search("label=~'#{multiple_words_label.title}'")
expect_issues_list_count(1)
expect_tokens([label_token("\"#{multiple_words_label.title}\"")])
@@ -213,7 +260,7 @@ describe 'Filter issues', :js do
end
it 'double quotes' do
- input_filtered_search("label:~\"#{multiple_words_label.title}\"")
+ input_filtered_search("label=~\"#{multiple_words_label.title}\"")
expect_tokens([label_token("\"#{multiple_words_label.title}\"")])
expect_issues_list_count(1)
@@ -225,7 +272,7 @@ describe 'Filter issues', :js do
double_quotes_label_issue = create(:issue, title: "Issue with double quotes label", project: project)
double_quotes_label_issue.labels << double_quotes_label
- input_filtered_search("label:~'#{double_quotes_label.title}'")
+ input_filtered_search("label=~'#{double_quotes_label.title}'")
expect_tokens([label_token("'#{double_quotes_label.title}'")])
expect_issues_list_count(1)
@@ -237,7 +284,7 @@ describe 'Filter issues', :js do
single_quotes_label_issue = create(:issue, title: "Issue with single quotes label", project: project)
single_quotes_label_issue.labels << single_quotes_label
- input_filtered_search("label:~\"#{single_quotes_label.title}\"")
+ input_filtered_search("label=~\"#{single_quotes_label.title}\"")
expect_tokens([label_token("\"#{single_quotes_label.title}\"")])
expect_issues_list_count(1)
@@ -249,7 +296,7 @@ describe 'Filter issues', :js do
it 'filters issues by searched label, label2, author, assignee, milestone and text' do
search_term = 'bug'
- input_filtered_search("label:~#{bug_label.title} label:~#{caps_sensitive_label.title} author:@#{user.username} assignee:@#{user.username} milestone:%#{milestone.title} #{search_term}")
+ input_filtered_search("label=~#{bug_label.title} label=~#{caps_sensitive_label.title} author=@#{user.username} assignee=@#{user.username} milestone=%#{milestone.title} #{search_term}")
wait_for_requests
@@ -263,6 +310,24 @@ describe 'Filter issues', :js do
expect_issues_list_count(1)
expect_filtered_search_input(search_term)
end
+
+ it 'filters issues by searched label, label2, author, assignee, not included in a milestone' do
+ search_term = 'bug'
+
+ input_filtered_search("label=~#{bug_label.title} label=~#{caps_sensitive_label.title} author=@#{user.username} assignee=@#{user.username} milestone!=%#{milestone.title} #{search_term}")
+
+ wait_for_requests
+
+ expect_tokens([
+ label_token(bug_label.title),
+ label_token(caps_sensitive_label.title),
+ author_token(user.name),
+ assignee_token(user.name),
+ milestone_token(milestone.title, false, '!=')
+ ])
+ expect_issues_list_count(0)
+ expect_filtered_search_input(search_term)
+ end
end
context 'issue label clicked' do
@@ -279,7 +344,7 @@ describe 'Filter issues', :js do
describe 'filter issues by milestone' do
context 'only milestone' do
it 'filters issues by searched milestone' do
- input_filtered_search("milestone:%#{milestone.title}")
+ input_filtered_search("milestone=%#{milestone.title}")
expect_tokens([milestone_token(milestone.title)])
expect_issues_list_count(5)
@@ -287,53 +352,102 @@ describe 'Filter issues', :js do
end
it 'filters issues by no milestone' do
- input_filtered_search("milestone:none")
+ input_filtered_search("milestone=none")
expect_tokens([milestone_token('None', false)])
expect_issues_list_count(3)
expect_filtered_search_input_empty
end
+ it 'filters issues by negation of no milestone' do
+ input_filtered_search("milestone!=none ")
+
+ expect_tokens([milestone_token('None', false, '!=')])
+ expect_issues_list_count(5)
+ expect_filtered_search_input_empty
+ end
+
it 'filters issues by upcoming milestones' do
create(:milestone, project: project, due_date: 1.month.from_now) do |future_milestone|
create(:issue, project: project, milestone: future_milestone, author: user)
end
- input_filtered_search("milestone:upcoming")
+ input_filtered_search("milestone=upcoming")
expect_tokens([milestone_token('Upcoming', false)])
expect_issues_list_count(1)
expect_filtered_search_input_empty
end
+ it 'filters issues by negation of upcoming milestones' do
+ create(:milestone, project: project, due_date: 1.month.from_now) do |future_milestone|
+ create(:issue, project: project, milestone: future_milestone, author: user)
+ end
+
+ input_filtered_search("milestone!=upcoming")
+
+ expect_tokens([milestone_token('Upcoming', false, '!=')])
+ expect_issues_list_count(8)
+ expect_filtered_search_input_empty
+ end
+
it 'filters issues by started milestones' do
- input_filtered_search("milestone:started")
+ input_filtered_search("milestone=started")
expect_tokens([milestone_token('Started', false)])
expect_issues_list_count(5)
expect_filtered_search_input_empty
end
+ it 'filters issues by negation of started milestones' do
+ input_filtered_search("milestone!=started")
+
+ expect_tokens([milestone_token('Started', false, '!=')])
+ expect_issues_list_count(3)
+ expect_filtered_search_input_empty
+ end
+
it 'filters issues by milestone containing special characters' do
special_milestone = create(:milestone, title: '!@\#{$%^&*()}', project: project)
create(:issue, project: project, milestone: special_milestone)
- input_filtered_search("milestone:%#{special_milestone.title}")
+ input_filtered_search("milestone=%#{special_milestone.title}")
expect_tokens([milestone_token(special_milestone.title)])
expect_issues_list_count(1)
expect_filtered_search_input_empty
end
+ it 'filters issues by milestone not containing special characters' do
+ special_milestone = create(:milestone, title: '!@\#{$%^&*()}', project: project)
+ create(:issue, project: project, milestone: special_milestone)
+
+ input_filtered_search("milestone!=%#{special_milestone.title}")
+
+ expect_tokens([milestone_token(special_milestone.title, false, '!=')])
+ expect_issues_list_count(8)
+ expect_filtered_search_input_empty
+ end
+
it 'does not show issues for unused milestones' do
new_milestone = create(:milestone, title: 'new', project: project)
- input_filtered_search("milestone:%#{new_milestone.title}")
+ input_filtered_search("milestone=%#{new_milestone.title}")
expect_tokens([milestone_token(new_milestone.title)])
expect_no_issues_list
expect_filtered_search_input_empty
end
+
+ it 'show issues for unused milestones' do
+ new_milestone = create(:milestone, title: 'new', project: project)
+
+ input_filtered_search("milestone!=%#{new_milestone.title}")
+
+ expect_tokens([milestone_token(new_milestone.title, false, '!=')])
+ expect_issues_list_count(8)
+ expect_filtered_search_input_empty
+ end
end
end
@@ -407,7 +521,7 @@ describe 'Filter issues', :js do
context 'searched text with other filters' do
it 'filters issues by searched text, author, text, assignee, text, label1, text, label2, text, milestone and text' do
- input_filtered_search("bug author:@#{user.username} report label:~#{bug_label.title} label:~#{caps_sensitive_label.title} milestone:%#{milestone.title} foo")
+ input_filtered_search("bug author=@#{user.username} report label=~#{bug_label.title} label=~#{caps_sensitive_label.title} milestone=%#{milestone.title} foo")
expect_issues_list_count(1)
expect_filtered_search_input('bug report foo')
@@ -481,7 +595,7 @@ describe 'Filter issues', :js do
end
it 'milestone dropdown loads milestones' do
- input_filtered_search("milestone:", submit: false)
+ input_filtered_search("milestone=", submit: false)
within('#js-dropdown-milestone') do
expect(page).to have_selector('.filter-dropdown .filter-dropdown-item', count: 1)
@@ -489,7 +603,7 @@ describe 'Filter issues', :js do
end
it 'label dropdown load labels' do
- input_filtered_search("label:", submit: false)
+ input_filtered_search("label=", submit: false)
within('#js-dropdown-label') do
expect(page).to have_selector('.filter-dropdown .filter-dropdown-item', count: 3)
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index c038281d825..e05c7aa3af5 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -41,8 +41,8 @@ describe 'Recent searches', :js do
items = all('.filtered-search-history-dropdown-item', visible: false, count: 2)
- expect(items[0].text).to eq('label: ~qux garply')
- expect(items[1].text).to eq('label: ~foo bar')
+ expect(items[0].text).to eq('label: = ~qux garply')
+ expect(items[1].text).to eq('label: = ~foo bar')
end
it 'saved recent searches are restored last on the list' do
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index e97314e02e6..ad994270218 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -34,7 +34,7 @@ describe 'Search bar', :js do
it 'selects item' do
filtered_search.native.send_keys(:down, :down, :enter)
- expect_tokens([author_token])
+ expect_tokens([{ name: 'Assignee' }])
expect_filtered_search_input_empty
end
end
@@ -78,7 +78,7 @@ describe 'Search bar', :js do
filtered_search.click
original_size = page.all('#js-dropdown-hint .filter-dropdown .filter-dropdown-item').size
- filtered_search.set('author')
+ filtered_search.set('autho')
expect(find('#js-dropdown-hint')).to have_selector('.filter-dropdown .filter-dropdown-item', count: 1)
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index d1e976c3bca..2af2e096bcc 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -36,8 +36,9 @@ describe 'Visual tokens', :js do
describe 'editing a single token' do
before do
- input_filtered_search('author:@root assignee:none', submit: false)
+ input_filtered_search('author=@root assignee=none', submit: false)
first('.tokens-container .filtered-search-token').click
+ wait_for_requests
end
it 'opens author dropdown' do
@@ -76,8 +77,8 @@ describe 'Visual tokens', :js do
describe 'editing multiple tokens' do
before do
- input_filtered_search('author:@root assignee:none', submit: false)
- first('.tokens-container .filtered-search-token').double_click
+ input_filtered_search('author=@root assignee=none', submit: false)
+ first('.tokens-container .filtered-search-token').click
end
it 'opens author dropdown' do
@@ -85,27 +86,33 @@ describe 'Visual tokens', :js do
end
it 'opens assignee dropdown' do
- find('.tokens-container .filtered-search-token', text: 'Assignee').double_click
+ find('.tokens-container .filtered-search-token', text: 'Assignee').click
expect(page).to have_css('#js-dropdown-assignee', visible: true)
end
end
describe 'editing a search term while editing another filter token' do
before do
- input_filtered_search('author assignee:', submit: false)
- first('.tokens-container .filtered-search-term').double_click
+ input_filtered_search('foo assignee=', submit: false)
+ first('.tokens-container .filtered-search-term').click
end
it 'opens author dropdown' do
- find('#js-dropdown-hint .filter-dropdown .filter-dropdown-item', text: 'author').click
+ find('#js-dropdown-hint .filter-dropdown .filter-dropdown-item', text: 'Author').click
+
+ expect(page).to have_css('#js-dropdown-operator', visible: true)
+ expect(page).to have_css('#js-dropdown-author', visible: false)
+
+ find('#js-dropdown-operator .filter-dropdown .filter-dropdown-item[data-value="="]').click
+ expect(page).to have_css('#js-dropdown-operator', visible: false)
expect(page).to have_css('#js-dropdown-author', visible: true)
end
end
describe 'add new token after editing existing token' do
before do
- input_filtered_search('author:@root assignee:none', submit: false)
+ input_filtered_search('author=@root assignee=none', submit: false)
first('.tokens-container .filtered-search-token').double_click
filtered_search.send_keys(' ')
end
@@ -116,7 +123,7 @@ describe 'Visual tokens', :js do
end
it 'opens token dropdown' do
- filtered_search.send_keys('author:')
+ filtered_search.send_keys('author=')
expect(page).to have_css('#js-dropdown-author', visible: true)
end
@@ -124,7 +131,7 @@ describe 'Visual tokens', :js do
describe 'visual tokens' do
it 'creates visual token' do
- filtered_search.send_keys('author:@thomas ')
+ filtered_search.send_keys('author=@thomas ')
token = page.all('.tokens-container .filtered-search-token')[1]
expect(token.find('.name').text).to eq('Author')
@@ -133,7 +140,7 @@ describe 'Visual tokens', :js do
end
it 'does not tokenize incomplete token' do
- filtered_search.send_keys('author:')
+ filtered_search.send_keys('author=')
find('body').click
token = page.all('.tokens-container .js-visual-token')[1]
@@ -145,7 +152,7 @@ describe 'Visual tokens', :js do
describe 'search using incomplete visual tokens' do
before do
- input_filtered_search('author:@root assignee:none', extra_space: false)
+ input_filtered_search('author=@root assignee=none', extra_space: false)
end
it 'tokenizes the search term to complete visual token' do
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index b7a45905845..c1a2e22a0c2 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -70,7 +70,7 @@ describe 'Labels Hierarchy', :js do
end
it 'does not filter by descendant group labels' do
- filtered_search.set("label:")
+ filtered_search.set("label=")
wait_for_requests
@@ -134,7 +134,7 @@ describe 'Labels Hierarchy', :js do
end
it 'does not filter by descendant group project labels' do
- filtered_search.set("label:")
+ filtered_search.set("label=")
wait_for_requests
@@ -227,7 +227,7 @@ describe 'Labels Hierarchy', :js do
it_behaves_like 'filtering by ancestor labels for projects'
it 'does not filter by descendant group labels' do
- filtered_search.set("label:")
+ filtered_search.set("label=")
wait_for_requests
diff --git a/spec/features/merge_requests/filters_generic_behavior_spec.rb b/spec/features/merge_requests/filters_generic_behavior_spec.rb
index 58aad1b7e91..c3400acae4f 100644
--- a/spec/features/merge_requests/filters_generic_behavior_spec.rb
+++ b/spec/features/merge_requests/filters_generic_behavior_spec.rb
@@ -23,7 +23,7 @@ describe 'Merge Requests > Filters generic behavior', :js do
context 'when filtered by a label' do
before do
- input_filtered_search('label:~bug')
+ input_filtered_search('label=~bug')
end
describe 'state tabs' do
diff --git a/spec/features/merge_requests/user_filters_by_assignees_spec.rb b/spec/features/merge_requests/user_filters_by_assignees_spec.rb
index 00bd8455ae1..3abee3b656a 100644
--- a/spec/features/merge_requests/user_filters_by_assignees_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_assignees_spec.rb
@@ -18,7 +18,7 @@ describe 'Merge Requests > User filters by assignees', :js do
context 'filtering by assignee:none' do
it 'applies the filter' do
- input_filtered_search('assignee:none')
+ input_filtered_search('assignee=none')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).not_to have_content 'Bugfix1'
@@ -26,9 +26,9 @@ describe 'Merge Requests > User filters by assignees', :js do
end
end
- context 'filtering by assignee:@username' do
+ context 'filtering by assignee=@username' do
it 'applies the filter' do
- input_filtered_search("assignee:@#{user.username}")
+ input_filtered_search("assignee=@#{user.username}")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix1'
diff --git a/spec/features/merge_requests/user_filters_by_labels_spec.rb b/spec/features/merge_requests/user_filters_by_labels_spec.rb
index fd2b4b23f96..7a80ebe9be3 100644
--- a/spec/features/merge_requests/user_filters_by_labels_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_labels_spec.rb
@@ -22,7 +22,7 @@ describe 'Merge Requests > User filters by labels', :js do
context 'filtering by label:none' do
it 'applies the filter' do
- input_filtered_search('label:none')
+ input_filtered_search('label=none')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).not_to have_content 'Bugfix1'
@@ -32,7 +32,7 @@ describe 'Merge Requests > User filters by labels', :js do
context 'filtering by label:~enhancement' do
it 'applies the filter' do
- input_filtered_search('label:~enhancement')
+ input_filtered_search('label=~enhancement')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
@@ -42,7 +42,7 @@ describe 'Merge Requests > User filters by labels', :js do
context 'filtering by label:~enhancement and label:~bug' do
it 'applies the filters' do
- input_filtered_search('label:~bug label:~enhancement')
+ input_filtered_search('label=~bug label=~enhancement')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
diff --git a/spec/features/merge_requests/user_filters_by_milestones_spec.rb b/spec/features/merge_requests/user_filters_by_milestones_spec.rb
index e0ee69d7a5b..8cb686e191e 100644
--- a/spec/features/merge_requests/user_filters_by_milestones_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_milestones_spec.rb
@@ -18,14 +18,14 @@ describe 'Merge Requests > User filters by milestones', :js do
end
it 'filters by no milestone' do
- input_filtered_search('milestone:none')
+ input_filtered_search('milestone=none')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
it 'filters by a specific milestone' do
- input_filtered_search("milestone:%'#{milestone.title}'")
+ input_filtered_search("milestone=%'#{milestone.title}'")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
@@ -33,7 +33,7 @@ describe 'Merge Requests > User filters by milestones', :js do
describe 'filters by upcoming milestone' do
it 'does not show merge requests with no expiry' do
- input_filtered_search('milestone:upcoming')
+ input_filtered_search('milestone=upcoming')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).to have_css('.merge-request', count: 0)
@@ -43,7 +43,7 @@ describe 'Merge Requests > User filters by milestones', :js do
let(:milestone) { create(:milestone, project: project, due_date: Date.tomorrow) }
it 'shows merge requests' do
- input_filtered_search('milestone:upcoming')
+ input_filtered_search('milestone=upcoming')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
@@ -54,7 +54,7 @@ describe 'Merge Requests > User filters by milestones', :js do
let(:milestone) { create(:milestone, project: project, due_date: Date.yesterday) }
it 'does not show any merge requests' do
- input_filtered_search('milestone:upcoming')
+ input_filtered_search('milestone=upcoming')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).to have_css('.merge-request', count: 0)
diff --git a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
index bc6e2ac5132..5c9d53778d2 100644
--- a/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_multiple_criteria_spec.rb
@@ -20,7 +20,7 @@ describe 'Merge requests > User filters by multiple criteria', :js do
describe 'filtering by label:~"Won\'t fix" and assignee:~bug' do
it 'applies the filters' do
- input_filtered_search("label:~\"Won't fix\" assignee:@#{user.username}")
+ input_filtered_search("label=~\"Won't fix\" assignee=@#{user.username}")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
@@ -30,7 +30,7 @@ describe 'Merge requests > User filters by multiple criteria', :js do
describe 'filtering by text, author, assignee, milestone, and label' do
it 'filters by text, author, assignee, milestone, and label' do
- input_filtered_search_keys("author:@#{user.username} assignee:@#{user.username} milestone:%\"v1.1\" label:~\"Won't fix\" Bug")
+ input_filtered_search_keys("author=@#{user.username} assignee=@#{user.username} milestone=%\"v1.1\" label=~\"Won't fix\" Bug")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
diff --git a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
index 0d03c5eae31..faff7de729d 100644
--- a/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
+++ b/spec/features/merge_requests/user_filters_by_target_branch_spec.rb
@@ -17,7 +17,7 @@ describe 'Merge Requests > User filters by target branch', :js do
context 'filtering by target-branch:master' do
it 'applies the filter' do
- input_filtered_search('target-branch:master')
+ input_filtered_search('target-branch=master')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content mr1.title
@@ -27,7 +27,7 @@ describe 'Merge Requests > User filters by target branch', :js do
context 'filtering by target-branch:merged-target' do
it 'applies the filter' do
- input_filtered_search('target-branch:merged-target')
+ input_filtered_search('target-branch=merged-target')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).not_to have_content mr1.title
@@ -37,7 +37,7 @@ describe 'Merge Requests > User filters by target branch', :js do
context 'filtering by target-branch:feature' do
it 'applies the filter' do
- input_filtered_search('target-branch:feature')
+ input_filtered_search('target-branch=feature')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).not_to have_content mr1.title
diff --git a/spec/frontend/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
index f00ba884a6c..66104724163 100644
--- a/spec/frontend/error_tracking/components/error_tracking_list_spec.js
+++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js
@@ -1,15 +1,7 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
-import {
- GlEmptyState,
- GlLoadingIcon,
- GlTable,
- GlLink,
- GlFormInput,
- GlDropdown,
- GlDropdownItem,
- GlPagination,
-} from '@gitlab/ui';
+import { GlEmptyState, GlLoadingIcon, GlFormInput, GlPagination } from '@gitlab/ui';
+import stubChildren from 'helpers/stub_children';
import ErrorTrackingList from '~/error_tracking/components/error_tracking_list.vue';
import errorsList from './list_mock.json';
@@ -32,19 +24,12 @@ describe('ErrorTrackingList', () => {
function mountComponent({
errorTrackingEnabled = true,
userCanEnableErrorTracking = true,
- sync = true,
- stubs = {
- 'gl-link': GlLink,
- 'gl-table': GlTable,
- 'gl-pagination': GlPagination,
- 'gl-dropdown': GlDropdown,
- 'gl-dropdown-item': GlDropdownItem,
- },
+ stubs = {},
} = {}) {
- wrapper = shallowMount(ErrorTrackingList, {
+ wrapper = mount(ErrorTrackingList, {
localVue,
store,
- sync,
+ sync: false,
propsData: {
indexPath: '/path',
enableErrorTrackingLink: '/link',
@@ -52,7 +37,10 @@ describe('ErrorTrackingList', () => {
errorTrackingEnabled,
illustrationPath: 'illustration/path',
},
- stubs,
+ stubs: {
+ ...stubChildren(ErrorTrackingList),
+ ...stubs,
+ },
data() {
return { errorSearchQuery: 'search' };
},
@@ -122,7 +110,14 @@ describe('ErrorTrackingList', () => {
beforeEach(() => {
store.state.list.loading = false;
store.state.list.errors = errorsList;
- mountComponent();
+ mountComponent({
+ stubs: {
+ GlTable: false,
+ GlDropdown: false,
+ GlDropdownItem: false,
+ GlLink: false,
+ },
+ });
});
it('shows table', () => {
@@ -173,7 +168,13 @@ describe('ErrorTrackingList', () => {
store.state.list.loading = false;
store.state.list.errors = [];
- mountComponent();
+ mountComponent({
+ stubs: {
+ GlTable: false,
+ GlDropdown: false,
+ GlDropdownItem: false,
+ },
+ });
});
it('shows empty table', () => {
@@ -187,7 +188,7 @@ describe('ErrorTrackingList', () => {
});
it('restarts polling', () => {
- findRefreshLink().trigger('click');
+ findRefreshLink().vm.$emit('click');
expect(actions.restartPolling).toHaveBeenCalled();
});
});
@@ -211,8 +212,8 @@ describe('ErrorTrackingList', () => {
errorTrackingEnabled: false,
userCanEnableErrorTracking: false,
stubs: {
- 'gl-link': GlLink,
- 'gl-empty-state': GlEmptyState,
+ GlLink: false,
+ GlEmptyState: false,
},
});
});
@@ -226,7 +227,12 @@ describe('ErrorTrackingList', () => {
describe('recent searches', () => {
beforeEach(() => {
- mountComponent();
+ mountComponent({
+ stubs: {
+ GlDropdown: false,
+ GlDropdownItem: false,
+ },
+ });
});
it('shows empty message', () => {
@@ -238,11 +244,12 @@ describe('ErrorTrackingList', () => {
it('shows items', () => {
store.state.list.recentSearches = ['great', 'search'];
- const dropdownItems = wrapper.findAll('.filtered-search-box li');
-
- expect(dropdownItems.length).toBe(3);
- expect(dropdownItems.at(0).text()).toBe('great');
- expect(dropdownItems.at(1).text()).toBe('search');
+ return wrapper.vm.$nextTick().then(() => {
+ const dropdownItems = wrapper.findAll('.filtered-search-box li');
+ expect(dropdownItems.length).toBe(3);
+ expect(dropdownItems.at(0).text()).toBe('great');
+ expect(dropdownItems.at(1).text()).toBe('search');
+ });
});
describe('clear', () => {
@@ -257,16 +264,20 @@ describe('ErrorTrackingList', () => {
it('is visible when list has items', () => {
store.state.list.recentSearches = ['some', 'searches'];
- expect(clearRecentButton().exists()).toBe(true);
- expect(clearRecentButton().text()).toBe('Clear recent searches');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(clearRecentButton().exists()).toBe(true);
+ expect(clearRecentButton().text()).toBe('Clear recent searches');
+ });
});
it('clears items on click', () => {
store.state.list.recentSearches = ['some', 'searches'];
- clearRecentButton().vm.$emit('click');
+ return wrapper.vm.$nextTick().then(() => {
+ clearRecentButton().vm.$emit('click');
- expect(actions.clearRecentSearches).toHaveBeenCalledTimes(1);
+ expect(actions.clearRecentSearches).toHaveBeenCalledTimes(1);
+ });
});
});
});
@@ -287,7 +298,11 @@ describe('ErrorTrackingList', () => {
describe('and the user is on the first page', () => {
beforeEach(() => {
store.state.list.loading = false;
- mountComponent({ sync: false });
+ mountComponent({
+ stubs: {
+ GlPagination: false,
+ },
+ });
});
it('shows a disabled Prev button', () => {
@@ -299,8 +314,14 @@ describe('ErrorTrackingList', () => {
describe('and the previous button is clicked', () => {
beforeEach(() => {
store.state.list.loading = false;
- mountComponent({ sync: false });
+ mountComponent({
+ stubs: {
+ GlTable: false,
+ GlPagination: false,
+ },
+ });
wrapper.setData({ pageValue: 2 });
+ return wrapper.vm.$nextTick();
});
it('fetches the previous page of results', () => {
@@ -318,7 +339,7 @@ describe('ErrorTrackingList', () => {
describe('and the next page button is clicked', () => {
beforeEach(() => {
store.state.list.loading = false;
- mountComponent({ sync: false });
+ mountComponent();
});
it('fetches the next page of results', () => {
diff --git a/spec/frontend/filtered_search/filtered_search_token_keys_spec.js b/spec/frontend/filtered_search/filtered_search_token_keys_spec.js
index d1fea18dea8..f24d2b118c2 100644
--- a/spec/frontend/filtered_search/filtered_search_token_keys_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_token_keys_spec.js
@@ -124,6 +124,7 @@ describe('Filtered Search Token Keys', () => {
const condition = new FilteredSearchTokenKeys([], [], conditions).searchByConditionKeyValue(
null,
null,
+ null,
);
expect(condition).toBeNull();
@@ -132,6 +133,7 @@ describe('Filtered Search Token Keys', () => {
it('should return condition when found by tokenKey and value', () => {
const result = new FilteredSearchTokenKeys([], [], conditions).searchByConditionKeyValue(
conditions[0].tokenKey,
+ conditions[0].operator,
conditions[0].value,
);
diff --git a/spec/frontend/helpers/stub_children.js b/spec/frontend/helpers/stub_children.js
new file mode 100644
index 00000000000..91171eb3d8c
--- /dev/null
+++ b/spec/frontend/helpers/stub_children.js
@@ -0,0 +1,3 @@
+export default function stubChildren(Component) {
+ return Object.fromEntries(Object.keys(Component.components).map(c => [c, true]));
+}
diff --git a/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js b/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js
index c88a182660d..f1b4c370532 100644
--- a/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js
+++ b/spec/frontend/pages/admin/users/components/user_modal_manager_spec.js
@@ -1,4 +1,4 @@
-import { shallowMount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
import UserModalManager from '~/pages/admin/users/components/user_modal_manager.vue';
import ModalStub from './stubs/modal_stub';
@@ -22,17 +22,13 @@ describe('Users admin page Modal Manager', () => {
let wrapper;
const createComponent = (props = {}) => {
- wrapper = shallowMount(UserModalManager, {
+ wrapper = mount(UserModalManager, {
propsData: {
actionModals,
modalConfiguration,
csrfToken: 'dummyCSRF',
...props,
},
- stubs: {
- dummyComponent1: true,
- dummyComponent2: true,
- },
sync: false,
});
};
diff --git a/spec/javascripts/droplab/drop_down_spec.js b/spec/javascripts/droplab/drop_down_spec.js
index 18ab03653f4..22346c10547 100644
--- a/spec/javascripts/droplab/drop_down_spec.js
+++ b/spec/javascripts/droplab/drop_down_spec.js
@@ -398,14 +398,21 @@ describe('DropLab DropDown', function() {
describe('render', function() {
beforeEach(function() {
- this.list = { querySelector: () => {}, dispatchEvent: () => {} };
- this.dropdown = { renderChildren: () => {}, list: this.list };
this.renderableList = {};
+ this.list = {
+ querySelector: q => {
+ if (q === '.filter-dropdown-loading') {
+ return false;
+ }
+ return this.renderableList;
+ },
+ dispatchEvent: () => {},
+ };
+ this.dropdown = { renderChildren: () => {}, list: this.list };
this.data = [0, 1];
this.customEvent = {};
spyOn(this.dropdown, 'renderChildren').and.callFake(data => data);
- spyOn(this.list, 'querySelector').and.returnValue(this.renderableList);
spyOn(this.list, 'dispatchEvent');
spyOn(this.data, 'map').and.callThrough();
spyOn(window, 'CustomEvent').and.returnValue(this.customEvent);
diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js
index 62d1bd69635..6eda4f391a4 100644
--- a/spec/javascripts/filtered_search/dropdown_utils_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js
@@ -222,7 +222,7 @@ describe('Dropdown Utils', () => {
hasAttribute: () => false,
};
- DropdownUtils.setDataValueIfSelected(null, selected);
+ DropdownUtils.setDataValueIfSelected(null, '=', selected);
expect(FilteredSearchDropdownManager.addWordToInput.calls.count()).toEqual(1);
});
@@ -233,9 +233,11 @@ describe('Dropdown Utils', () => {
hasAttribute: () => false,
};
- const result = DropdownUtils.setDataValueIfSelected(null, selected);
+ const result = DropdownUtils.setDataValueIfSelected(null, '=', selected);
+ const result2 = DropdownUtils.setDataValueIfSelected(null, '!=', selected);
expect(result).toBe(true);
+ expect(result2).toBe(true);
});
it('returns false when dataValue does not exist', () => {
@@ -243,9 +245,11 @@ describe('Dropdown Utils', () => {
getAttribute: () => null,
};
- const result = DropdownUtils.setDataValueIfSelected(null, selected);
+ const result = DropdownUtils.setDataValueIfSelected(null, '=', selected);
+ const result2 = DropdownUtils.setDataValueIfSelected(null, '!=', selected);
expect(result).toBe(false);
+ expect(result2).toBe(false);
});
});
@@ -349,7 +353,7 @@ describe('Dropdown Utils', () => {
beforeEach(() => {
loadFixtures(issueListFixture);
- authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '@user');
+ authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user');
const searchTermToken = FilteredSearchSpecHelper.createSearchVisualToken('search term');
const tokensContainer = document.querySelector('.tokens-container');
@@ -364,7 +368,7 @@ describe('Dropdown Utils', () => {
const searchQuery = DropdownUtils.getSearchQuery();
- expect(searchQuery).toBe(' search term author:original dance');
+ expect(searchQuery).toBe(' search term author:=original dance');
});
});
});
diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js
index 8c5a0961a02..853f6b3b7b8 100644
--- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js
@@ -27,7 +27,7 @@ describe('Filtered Search Dropdown Manager', () => {
describe('input has no existing value', () => {
it('should add just tokenName', () => {
- FilteredSearchDropdownManager.addWordToInput('milestone');
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'milestone' });
const token = document.querySelector('.tokens-container .js-visual-token');
@@ -36,8 +36,8 @@ describe('Filtered Search Dropdown Manager', () => {
expect(getInputValue()).toBe('');
});
- it('should add tokenName and tokenValue', () => {
- FilteredSearchDropdownManager.addWordToInput('label');
+ it('should add tokenName, tokenOperator, and tokenValue', () => {
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label' });
let token = document.querySelector('.tokens-container .js-visual-token');
@@ -45,13 +45,27 @@ describe('Filtered Search Dropdown Manager', () => {
expect(token.querySelector('.name').innerText).toBe('label');
expect(getInputValue()).toBe('');
- FilteredSearchDropdownManager.addWordToInput('label', 'none');
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label', tokenOperator: '=' });
+
+ token = document.querySelector('.tokens-container .js-visual-token');
+
+ expect(token.classList.contains('filtered-search-token')).toEqual(true);
+ expect(token.querySelector('.name').innerText).toBe('label');
+ expect(token.querySelector('.operator').innerText).toBe('=');
+ expect(getInputValue()).toBe('');
+
+ FilteredSearchDropdownManager.addWordToInput({
+ tokenName: 'label',
+ tokenOperator: '=',
+ tokenValue: 'none',
+ });
// We have to get that reference again
// Because FilteredSearchDropdownManager deletes the previous token
token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label');
+ expect(token.querySelector('.operator').innerText).toBe('=');
expect(token.querySelector('.value').innerText).toBe('none');
expect(getInputValue()).toBe('');
});
@@ -60,7 +74,7 @@ describe('Filtered Search Dropdown Manager', () => {
describe('input has existing value', () => {
it('should be able to just add tokenName', () => {
setInputValue('a');
- FilteredSearchDropdownManager.addWordToInput('author');
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author' });
const token = document.querySelector('.tokens-container .js-visual-token');
@@ -70,29 +84,40 @@ describe('Filtered Search Dropdown Manager', () => {
});
it('should replace tokenValue', () => {
- FilteredSearchDropdownManager.addWordToInput('author');
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author' });
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'author', tokenOperator: '=' });
setInputValue('roo');
- FilteredSearchDropdownManager.addWordToInput(null, '@root');
+ FilteredSearchDropdownManager.addWordToInput({
+ tokenName: null,
+ tokenOperator: '=',
+ tokenValue: '@root',
+ });
const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('author');
+ expect(token.querySelector('.operator').innerText).toBe('=');
expect(token.querySelector('.value').innerText).toBe('@root');
expect(getInputValue()).toBe('');
});
it('should add tokenValues containing spaces', () => {
- FilteredSearchDropdownManager.addWordToInput('label');
+ FilteredSearchDropdownManager.addWordToInput({ tokenName: 'label' });
setInputValue('"test ');
- FilteredSearchDropdownManager.addWordToInput('label', '~\'"test me"\'');
+ FilteredSearchDropdownManager.addWordToInput({
+ tokenName: 'label',
+ tokenOperator: '=',
+ tokenValue: '~\'"test me"\'',
+ });
const token = document.querySelector('.tokens-container .js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toBe('label');
+ expect(token.querySelector('.operator').innerText).toBe('=');
expect(token.querySelector('.value').innerText).toBe('~\'"test me"\'');
expect(getInputValue()).toBe('');
});
diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
index e076120f5cc..e5d1d1d690e 100644
--- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
@@ -201,8 +201,8 @@ describe('Filtered Search Manager', function() {
it('removes duplicated tokens', done => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
`);
spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => {
@@ -234,7 +234,7 @@ describe('Filtered Search Manager', function() {
it('should not render placeholder when there are tokens and no input', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'),
);
const event = new Event('input');
@@ -252,7 +252,7 @@ describe('Filtered Search Manager', function() {
describe('tokens and no input', () => {
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'),
);
});
@@ -306,7 +306,7 @@ describe('Filtered Search Manager', function() {
it('removes token even when it is already selected', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
);
tokensContainer.querySelector('.js-visual-token .remove-token').click();
@@ -319,7 +319,7 @@ describe('Filtered Search Manager', function() {
spyOn(FilteredSearchManager.prototype, 'removeSelectedToken').and.callThrough();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none'),
);
tokensContainer.querySelector('.js-visual-token .remove-token').click();
});
@@ -338,7 +338,7 @@ describe('Filtered Search Manager', function() {
beforeEach(() => {
initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
);
});
@@ -424,7 +424,7 @@ describe('Filtered Search Manager', function() {
});
it('Clicking the "x" clear button, clears the input', () => {
- const inputValue = 'label:~bug ';
+ const inputValue = 'label:=~bug';
manager.filteredSearchInput.value = inputValue;
manager.filteredSearchInput.dispatchEvent(new Event('input'));
diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
index 0ee13faf841..fda078bd41c 100644
--- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
@@ -6,9 +6,10 @@ describe('Filtered Search Visual Tokens', () => {
const findElements = tokenElement => {
const tokenNameElement = tokenElement.querySelector('.name');
+ const tokenOperatorElement = tokenElement.querySelector('.operator');
const tokenValueContainer = tokenElement.querySelector('.value-container');
const tokenValueElement = tokenValueContainer.querySelector('.value');
- return { tokenNameElement, tokenValueContainer, tokenValueElement };
+ return { tokenNameElement, tokenOperatorElement, tokenValueContainer, tokenValueElement };
};
let tokensContainer;
@@ -23,8 +24,8 @@ describe('Filtered Search Visual Tokens', () => {
`);
tokensContainer = document.querySelector('.tokens-container');
- authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '@user');
- bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~bug');
+ authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user');
+ bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '=', '~bug');
});
describe('getLastVisualTokenBeforeInput', () => {
@@ -62,7 +63,7 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
`);
const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
@@ -92,7 +93,7 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
`);
const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
@@ -105,7 +106,7 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label')}
${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
`);
const { lastVisualToken, isLastVisualTokenValid } = subject.getLastVisualTokenBeforeInput();
@@ -150,8 +151,8 @@ describe('Filtered Search Visual Tokens', () => {
it('removes the selected class from buttons', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@author')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '%123', true)}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@author')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', '%123', true)}
`);
const selected = tokensContainer.querySelector('.js-visual-token .selected');
@@ -169,7 +170,7 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~awesome')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~awesome')}
`);
});
@@ -206,7 +207,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('removeSelectedToken', () => {
it('does not remove when there are no selected tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none'),
);
expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
@@ -218,7 +219,7 @@ describe('Filtered Search Visual Tokens', () => {
it('removes selected token', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
);
expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
@@ -281,16 +282,22 @@ describe('Filtered Search Visual Tokens', () => {
describe('addVisualTokenElement', () => {
it('renders search visual tokens', () => {
- subject.addVisualTokenElement('search term', null, { isSearchTerm: true });
+ subject.addVisualTokenElement({
+ name: 'search term',
+ operator: '=',
+ value: null,
+ options: { isSearchTerm: true },
+ });
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-term')).toEqual(true);
expect(token.querySelector('.name').innerText).toEqual('search term');
+ expect(token.querySelector('.operator').innerText).toEqual('=');
expect(token.querySelector('.value')).toEqual(null);
});
it('renders filter visual token name', () => {
- subject.addVisualTokenElement('milestone');
+ subject.addVisualTokenElement({ name: 'milestone' });
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('search-token-milestone')).toEqual(true);
@@ -299,22 +306,23 @@ describe('Filtered Search Visual Tokens', () => {
expect(token.querySelector('.value')).toEqual(null);
});
- it('renders filter visual token name and value', () => {
- subject.addVisualTokenElement('label', 'Frontend');
+ it('renders filter visual token name, operator, and value', () => {
+ subject.addVisualTokenElement({ name: 'label', operator: '!=', value: 'Frontend' });
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('search-token-label')).toEqual(true);
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toEqual('label');
+ expect(token.querySelector('.operator').innerText).toEqual('!=');
expect(token.querySelector('.value').innerText).toEqual('Frontend');
});
it('inserts visual token before input', () => {
tokensContainer.appendChild(
- FilteredSearchSpecHelper.createFilterVisualToken('assignee', '@root'),
+ FilteredSearchSpecHelper.createFilterVisualToken('assignee', '=', '@root'),
);
- subject.addVisualTokenElement('label', 'Frontend');
+ subject.addVisualTokenElement({ name: 'label', operator: '!=', value: 'Frontend' });
const tokens = tokensContainer.querySelectorAll('.js-visual-token');
const labelToken = tokens[0];
const assigneeToken = tokens[1];
@@ -323,18 +331,20 @@ describe('Filtered Search Visual Tokens', () => {
expect(labelToken.classList.contains('filtered-search-token')).toEqual(true);
expect(labelToken.querySelector('.name').innerText).toEqual('label');
expect(labelToken.querySelector('.value').innerText).toEqual('Frontend');
+ expect(labelToken.querySelector('.operator').innerText).toEqual('!=');
expect(assigneeToken.classList.contains('search-token-assignee')).toEqual(true);
expect(assigneeToken.classList.contains('filtered-search-token')).toEqual(true);
expect(assigneeToken.querySelector('.name').innerText).toEqual('assignee');
expect(assigneeToken.querySelector('.value').innerText).toEqual('@root');
+ expect(assigneeToken.querySelector('.operator').innerText).toEqual('=');
});
});
describe('addValueToPreviousVisualTokenElement', () => {
it('does not add when previous visual token element has no value', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root'),
);
const original = tokensContainer.innerHTML;
@@ -345,7 +355,7 @@ describe('Filtered Search Visual Tokens', () => {
it('does not add when previous visual token element is a search', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
`);
@@ -357,7 +367,7 @@ describe('Filtered Search Visual Tokens', () => {
it('adds value to previous visual filter token', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label'),
+ FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label', '='),
);
const original = tokensContainer.innerHTML;
@@ -377,25 +387,28 @@ describe('Filtered Search Visual Tokens', () => {
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toEqual('milestone');
+ expect(token.querySelector('.operator')).toEqual(null);
expect(token.querySelector('.value')).toEqual(null);
});
it('creates visual token with just tokenValue', () => {
- subject.addFilterVisualToken('milestone');
+ subject.addFilterVisualToken('milestone', '=');
subject.addFilterVisualToken('%8.17');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toEqual('milestone');
+ expect(token.querySelector('.operator').innerText).toEqual('=');
expect(token.querySelector('.value').innerText).toEqual('%8.17');
});
it('creates full visual token', () => {
- subject.addFilterVisualToken('assignee', '@john');
+ subject.addFilterVisualToken('assignee', '=', '@john');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
expect(token.querySelector('.name').innerText).toEqual('assignee');
+ expect(token.querySelector('.operator').innerText).toEqual('=');
expect(token.querySelector('.value').innerText).toEqual('@john');
});
});
@@ -412,7 +425,7 @@ describe('Filtered Search Visual Tokens', () => {
it('appends to previous search visual token if previous token was a search token', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '=', '@root')}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
`);
@@ -467,7 +480,11 @@ describe('Filtered Search Visual Tokens', () => {
describe('removeLastTokenPartial', () => {
it('should remove the last token value if it exists', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~"Community Contribution"'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML(
+ 'label',
+ '=',
+ '~"Community Contribution"',
+ ),
);
expect(tokensContainer.querySelector('.js-visual-token .value')).not.toEqual(null);
@@ -507,7 +524,7 @@ describe('Filtered Search Visual Tokens', () => {
it('adds search visual token if previous visual token is valid', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('assignee', 'none'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('assignee', '=', 'none'),
);
const input = document.querySelector('.filtered-search');
@@ -523,7 +540,7 @@ describe('Filtered Search Visual Tokens', () => {
it('adds value to previous visual token element if previous visual token is invalid', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('assignee'),
+ FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('assignee', '='),
);
const input = document.querySelector('.filtered-search');
@@ -534,6 +551,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(input.value).toEqual('');
expect(updatedToken.querySelector('.name').innerText).toEqual('assignee');
+ expect(updatedToken.querySelector('.operator').innerText).toEqual('=');
expect(updatedToken.querySelector('.value').innerText).toEqual('@john');
});
});
@@ -544,9 +562,9 @@ describe('Filtered Search Visual Tokens', () => {
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'upcoming')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'upcoming')}
`);
input = document.querySelector('.filtered-search');
@@ -614,7 +632,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('moveInputTotheRight', () => {
it('does nothing if the input is already the right most element', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none'),
+ FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none'),
);
spyOn(subject, 'tokenizeInput').and.callFake(() => {});
@@ -628,12 +646,12 @@ describe('Filtered Search Visual Tokens', () => {
it("tokenize's input", () => {
tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label')}
+ ${FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label', '=')}
${FilteredSearchSpecHelper.createInputHTML()}
${bugLabelToken.outerHTML}
`;
- document.querySelector('.filtered-search').value = 'none';
+ tokensContainer.querySelector('.filtered-search').value = 'none';
subject.moveInputToTheRight();
const value = tokensContainer.querySelector('.js-visual-token .value');
@@ -643,7 +661,7 @@ describe('Filtered Search Visual Tokens', () => {
it('converts input into search term token if last token is valid', () => {
tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
${FilteredSearchSpecHelper.createInputHTML()}
${bugLabelToken.outerHTML}
`;
@@ -658,7 +676,7 @@ describe('Filtered Search Visual Tokens', () => {
it('moves the input to the right most element', () => {
tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
${FilteredSearchSpecHelper.createInputHTML()}
${bugLabelToken.outerHTML}
`;
@@ -670,8 +688,8 @@ describe('Filtered Search Visual Tokens', () => {
it('tokenizes input even if input is the right most element', () => {
tokensContainer.innerHTML = `
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
- ${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label')}
+ ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', 'none')}
+ ${FilteredSearchSpecHelper.createNameOperatorFilterVisualTokenHTML('label')}
${FilteredSearchSpecHelper.createInputHTML('', '~bug')}
`;
diff --git a/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js b/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js
index e33a6c002e5..c7be900ba2c 100644
--- a/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js
+++ b/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js
@@ -138,6 +138,7 @@ describe('Issues Filtered Search Token Keys', () => {
const conditions = IssuableFilteredSearchTokenKeys.getConditions();
const result = IssuableFilteredSearchTokenKeys.searchByConditionKeyValue(
conditions[0].tokenKey,
+ conditions[0].operator,
conditions[0].value,
);
diff --git a/spec/javascripts/filtered_search/visual_token_value_spec.js b/spec/javascripts/filtered_search/visual_token_value_spec.js
index 5863005de1e..a039e280028 100644
--- a/spec/javascripts/filtered_search/visual_token_value_spec.js
+++ b/spec/javascripts/filtered_search/visual_token_value_spec.js
@@ -10,9 +10,11 @@ describe('Filtered Search Visual Tokens', () => {
const tokenNameElement = tokenElement.querySelector('.name');
const tokenValueContainer = tokenElement.querySelector('.value-container');
const tokenValueElement = tokenValueContainer.querySelector('.value');
+ const tokenOperatorElement = tokenElement.querySelector('.operator');
const tokenType = tokenNameElement.innerText.toLowerCase();
const tokenValue = tokenValueElement.innerText;
- const subject = new VisualTokenValue(tokenValue, tokenType);
+ const tokenOperator = tokenOperatorElement.innerText;
+ const subject = new VisualTokenValue(tokenValue, tokenType, tokenOperator);
return { subject, tokenValueContainer, tokenValueElement };
};
@@ -28,8 +30,8 @@ describe('Filtered Search Visual Tokens', () => {
`);
tokensContainer = document.querySelector('.tokens-container');
- authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '@user');
- bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~bug');
+ authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user');
+ bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '=', '~bug');
});
describe('updateUserTokenAppearance', () => {
@@ -140,10 +142,12 @@ describe('Filtered Search Visual Tokens', () => {
const missingLabelToken = FilteredSearchSpecHelper.createFilterVisualToken(
'label',
+ '=',
'~doesnotexist',
);
const spaceLabelToken = FilteredSearchSpecHelper.createFilterVisualToken(
'label',
+ '=',
'~"some space"',
);
diff --git a/spec/javascripts/helpers/filtered_search_spec_helper.js b/spec/javascripts/helpers/filtered_search_spec_helper.js
index fd06bb1f324..ceb7982bbc3 100644
--- a/spec/javascripts/helpers/filtered_search_spec_helper.js
+++ b/spec/javascripts/helpers/filtered_search_spec_helper.js
@@ -1,15 +1,17 @@
export default class FilteredSearchSpecHelper {
- static createFilterVisualTokenHTML(name, value, isSelected) {
- return FilteredSearchSpecHelper.createFilterVisualToken(name, value, isSelected).outerHTML;
+ static createFilterVisualTokenHTML(name, operator, value, isSelected) {
+ return FilteredSearchSpecHelper.createFilterVisualToken(name, operator, value, isSelected)
+ .outerHTML;
}
- static createFilterVisualToken(name, value, isSelected = false) {
+ static createFilterVisualToken(name, operator, value, isSelected = false) {
const li = document.createElement('li');
li.classList.add('js-visual-token', 'filtered-search-token', `search-token-${name}`);
li.innerHTML = `
<div class="selectable ${isSelected ? 'selected' : ''}" role="button">
<div class="name">${name}</div>
+ <div class="operator">${operator}</div>
<div class="value-container">
<div class="value">${value}</div>
<div class="remove-token" role="button">
@@ -30,6 +32,15 @@ export default class FilteredSearchSpecHelper {
`;
}
+ static createNameOperatorFilterVisualTokenHTML(name, operator) {
+ return `
+ <li class="js-visual-token filtered-search-token">
+ <div class="name">${name}</div>
+ <div class="operator">${operator}</div>
+ </li>
+ `;
+ }
+
static createSearchVisualToken(name) {
const li = document.createElement('li');
li.classList.add('js-visual-token', 'filtered-search-term');
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 0dd2ebdb70d..8ddb4c23b81 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -8,6 +8,7 @@ issues:
- milestone
- notes
- resource_label_events
+- resource_weight_events
- sentry_issue
- label_links
- labels
diff --git a/spec/models/resource_weight_event_spec.rb b/spec/models/resource_weight_event_spec.rb
new file mode 100644
index 00000000000..2f00204512e
--- /dev/null
+++ b/spec/models/resource_weight_event_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ResourceWeightEvent, type: :model do
+ let_it_be(:user1) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+
+ let_it_be(:issue1) { create(:issue, author: user1) }
+ let_it_be(:issue2) { create(:issue, author: user1) }
+ let_it_be(:issue3) { create(:issue, author: user2) }
+
+ describe 'validations' do
+ it { is_expected.not_to allow_value(nil).for(:user) }
+ it { is_expected.not_to allow_value(nil).for(:issue) }
+ it { is_expected.to allow_value(nil).for(:weight) }
+ end
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:issue) }
+ end
+
+ describe '.by_issue' do
+ let_it_be(:event1) { create(:resource_weight_event, issue: issue1) }
+ let_it_be(:event2) { create(:resource_weight_event, issue: issue2) }
+ let_it_be(:event3) { create(:resource_weight_event, issue: issue1) }
+
+ it 'returns the expected records for an issue with events' do
+ events = ResourceWeightEvent.by_issue(issue1)
+
+ expect(events).to contain_exactly(event1, event3)
+ end
+
+ it 'returns the expected records for an issue with no events' do
+ events = ResourceWeightEvent.by_issue(issue3)
+
+ expect(events).to be_empty
+ end
+ end
+
+ describe '.created_after' do
+ let!(:created_at1) { 1.day.ago }
+ let!(:created_at2) { 2.days.ago }
+ let!(:created_at3) { 3.days.ago }
+
+ let!(:event1) { create(:resource_weight_event, issue: issue1, created_at: created_at1) }
+ let!(:event2) { create(:resource_weight_event, issue: issue2, created_at: created_at2) }
+ let!(:event3) { create(:resource_weight_event, issue: issue2, created_at: created_at3) }
+
+ it 'returns the expected events' do
+ events = ResourceWeightEvent.created_after(created_at3)
+
+ expect(events).to contain_exactly(event1, event2)
+ end
+
+ it 'returns no events if time is after last record time' do
+ events = ResourceWeightEvent.created_after(1.minute.ago)
+
+ expect(events).to be_empty
+ end
+ end
+
+ describe '#discussion_id' do
+ let_it_be(:event) { create(:resource_weight_event, issue: issue1, created_at: Time.utc(2019, 12, 30)) }
+
+ it 'returns the expected id' do
+ allow(Digest::SHA1).to receive(:hexdigest)
+ .with("ResourceWeightEvent-2019-12-30 00:00:00 UTC-#{user1.id}")
+ .and_return('73d167c478')
+
+ expect(event.discussion_id).to eq('73d167c478')
+ end
+ end
+end
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index 017e94d04f1..0635c318942 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -183,29 +183,81 @@ describe Ci::BuildRunnerPresenter do
let(:pipeline) { merge_request.all_pipelines.first }
let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
- it 'returns the correct refspecs' do
- is_expected
- .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head')
- end
-
- context 'when GIT_DEPTH is zero' do
+ context 'when depend_on_persistent_pipeline_ref feature flag is enabled' do
before do
- create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 0, pipeline: build.pipeline)
+ stub_feature_flags(ci_force_exposing_merge_request_refs: false)
+ pipeline.persistent_ref.create
end
it 'returns the correct refspecs' do
is_expected
- .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head',
- '+refs/heads/*:refs/remotes/origin/*',
- '+refs/tags/*:refs/tags/*')
+ .to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}")
+ end
+
+ context 'when ci_force_exposing_merge_request_refs feature flag is enabled' do
+ before do
+ stub_feature_flags(ci_force_exposing_merge_request_refs: true)
+ end
+
+ it 'returns the correct refspecs' do
+ is_expected
+ .to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ '+refs/merge-requests/1/head:refs/merge-requests/1/head')
+ end
+ end
+
+ context 'when GIT_DEPTH is zero' do
+ before do
+ create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 0, pipeline: build.pipeline)
+ end
+
+ it 'returns the correct refspecs' do
+ is_expected
+ .to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ '+refs/heads/*:refs/remotes/origin/*',
+ '+refs/tags/*:refs/tags/*')
+ end
+ end
+
+ context 'when pipeline is legacy detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
+
+ it 'returns the correct refspecs' do
+ is_expected.to contain_exactly("+refs/pipelines/#{pipeline.id}:refs/pipelines/#{pipeline.id}",
+ "+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ end
end
end
- context 'when pipeline is legacy detached merge request pipeline' do
- let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
+ context 'when depend_on_persistent_pipeline_ref feature flag is disabled' do
+ before do
+ stub_feature_flags(depend_on_persistent_pipeline_ref: false)
+ end
it 'returns the correct refspecs' do
- is_expected.to contain_exactly("+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ is_expected
+ .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head')
+ end
+
+ context 'when GIT_DEPTH is zero' do
+ before do
+ create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 0, pipeline: build.pipeline)
+ end
+
+ it 'returns the correct refspecs' do
+ is_expected
+ .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head',
+ '+refs/heads/*:refs/remotes/origin/*',
+ '+refs/tags/*:refs/tags/*')
+ end
+ end
+
+ context 'when pipeline is legacy detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
+
+ it 'returns the correct refspecs' do
+ is_expected.to contain_exactly("+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}")
+ end
end
end
end
diff --git a/spec/rubocop/cop/migration/add_column_with_default_spec.rb b/spec/rubocop/cop/migration/add_column_with_default_spec.rb
index d309a960e2f..f3518f2f058 100644
--- a/spec/rubocop/cop/migration/add_column_with_default_spec.rb
+++ b/spec/rubocop/cop/migration/add_column_with_default_spec.rb
@@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::AddColumnWithDefault do
it 'does not register any offenses' do
expect_no_offenses(<<~RUBY)
def up
- add_reference(:projects, :users)
+ add_column_with_default(:ci_build_needs, :artifacts, :boolean, default: true, allow_null: false)
end
RUBY
end
diff --git a/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb
new file mode 100644
index 00000000000..41902bc1da1
--- /dev/null
+++ b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ResourceEvents::SyntheticLabelNotesBuilderService do
+ describe '#execute' do
+ let!(:user) { create(:user) }
+
+ let!(:issue) { create(:issue, author: user) }
+
+ let!(:event1) { create(:resource_label_event, issue: issue) }
+ let!(:event2) { create(:resource_label_event, issue: issue) }
+ let!(:event3) { create(:resource_label_event, issue: issue) }
+
+ it 'returns the expected synthetic notes' do
+ notes = ResourceEvents::SyntheticLabelNotesBuilderService.new(issue, user).execute
+
+ expect(notes.size).to eq(3)
+ end
+ end
+end
diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb
index 350c8a29e87..c8b7a9251a9 100644
--- a/spec/support/helpers/filtered_search_helpers.rb
+++ b/spec/support/helpers/filtered_search_helpers.rb
@@ -26,7 +26,7 @@ module FilteredSearchHelpers
# Select a label clicking in the search dropdown instead
# of entering label names on the input.
def select_label_on_dropdown(label_title)
- input_filtered_search("label:", submit: false)
+ input_filtered_search("label=", submit: false)
within('#js-dropdown-label') do
wait_for_requests
@@ -71,7 +71,7 @@ module FilteredSearchHelpers
end
def init_label_search
- filtered_search.set('label:')
+ filtered_search.set('label=')
# This ensures the dropdown is shown
expect(find('#js-dropdown-label')).not_to have_css('.filter-dropdown-loading')
end
@@ -90,6 +90,7 @@ module FilteredSearchHelpers
el = token_elements[index]
expect(el.find('.name')).to have_content(token[:name])
+ expect(el.find('.operator')).to have_content(token[:operator]) if token[:operator].present?
expect(el.find('.value')).to have_content(token[:value]) if token[:value].present?
# gl-emoji content is blank when the emoji unicode is not supported
@@ -101,8 +102,8 @@ module FilteredSearchHelpers
end
end
- def create_token(token_name, token_value = nil, symbol = nil)
- { name: token_name, value: "#{symbol}#{token_value}" }
+ def create_token(token_name, token_value = nil, symbol = nil, token_operator = '=')
+ { name: token_name, operator: token_operator, value: "#{symbol}#{token_value}" }
end
def author_token(author_name = nil)
@@ -113,9 +114,9 @@ module FilteredSearchHelpers
create_token('Assignee', assignee_name)
end
- def milestone_token(milestone_name = nil, has_symbol = true)
+ def milestone_token(milestone_name = nil, has_symbol = true, operator = '=')
symbol = has_symbol ? '%' : nil
- create_token('Milestone', milestone_name, symbol)
+ create_token('Milestone', milestone_name, symbol, operator)
end
def release_token(release_tag = nil)
diff --git a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
index 63ed37cde03..3da80541072 100644
--- a/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
+++ b/spec/support/shared_examples/features/issuables_user_dropdown_behaviors_shared_examples.rb
@@ -13,7 +13,7 @@ shared_examples 'issuable user dropdown behaviors' do
it 'only includes members of the project/group' do
visit issuables_path
- filtered_search.set("#{dropdown}:")
+ filtered_search.set("#{dropdown}=")
expect(find("#js-dropdown-#{dropdown} .filter-dropdown")).to have_content(user_in_dropdown.name)
expect(find("#js-dropdown-#{dropdown} .filter-dropdown")).not_to have_content(user_not_in_dropdown.name)