Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
389dd2af
Commit
389dd2af
authored
Feb 15, 2017
by
Clement Ho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add filtered search to MR page
parent
d4437eee
Changes
24
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
552 additions
and
379 deletions
+552
-379
app/assets/javascripts/dispatcher.js.es6
app/assets/javascripts/dispatcher.js.es6
+1
-1
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
+12
-21
app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
...vascripts/filtered_search/filtered_search_dropdown.js.es6
+16
-10
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
...s/filtered_search/filtered_search_dropdown_manager.js.es6
+16
-7
app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
...avascripts/filtered_search/filtered_search_manager.js.es6
+11
-6
app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
...scripts/filtered_search/filtered_search_token_keys.js.es6
+0
-13
app/assets/javascripts/filtered_search/filtered_search_token_keys_with_weights.js.es6
...red_search/filtered_search_token_keys_with_weights.js.es6
+75
-0
app/assets/javascripts/search_autocomplete.js.es6
app/assets/javascripts/search_autocomplete.js.es6
+2
-2
app/controllers/projects/merge_requests_controller.rb
app/controllers/projects/merge_requests_controller.rb
+10
-0
app/views/projects/merge_requests/index.html.haml
app/views/projects/merge_requests/index.html.haml
+4
-3
app/views/shared/issuable/_search_bar.html.haml
app/views/shared/issuable/_search_bar.html.haml
+18
-17
changelogs/unreleased-ee/add-filtered-search-to-mr-ee.yml
changelogs/unreleased-ee/add-filtered-search-to-mr-ee.yml
+4
-0
features/project/merge_requests.feature
features/project/merge_requests.feature
+0
-7
spec/features/issues/filtered_search/dropdown_label_spec.rb
spec/features/issues/filtered_search/dropdown_label_spec.rb
+2
-6
spec/features/issues/filtered_search/filter_issues_spec.rb
spec/features/issues/filtered_search/filter_issues_spec.rb
+1
-13
spec/features/merge_requests/filter_by_labels_spec.rb
spec/features/merge_requests/filter_by_labels_spec.rb
+21
-65
spec/features/merge_requests/filter_by_milestone_spec.rb
spec/features/merge_requests/filter_by_milestone_spec.rb
+17
-18
spec/features/merge_requests/filter_merge_requests_spec.rb
spec/features/merge_requests/filter_merge_requests_spec.rb
+112
-169
spec/features/merge_requests/reset_filters_spec.rb
spec/features/merge_requests/reset_filters_spec.rb
+12
-17
spec/features/search_spec.rb
spec/features/search_spec.rb
+2
-2
spec/javascripts/filtered_search/filtered_search_token_keys_with_weights_spec.js.es6
...earch/filtered_search_token_keys_with_weights_spec.js.es6
+168
-0
spec/javascripts/search_autocomplete_spec.js
spec/javascripts/search_autocomplete_spec.js
+2
-2
spec/support/filtered_search_helpers.rb
spec/support/filtered_search_helpers.rb
+37
-0
spec/support/merge_request_helpers.rb
spec/support/merge_request_helpers.rb
+9
-0
No files found.
app/assets/javascripts/dispatcher.js.es6
View file @
389dd2af
...
...
@@ -76,7 +76,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
case 'projects:merge_requests:index':
case 'projects:issues:index':
if (gl.FilteredSearchManager) {
new gl.FilteredSearchManager();
new gl.FilteredSearchManager(
page === 'projects:issues:index' ? 'issues' : 'merge_requests'
);
}
Issuable.init();
new gl.IssuableBulkActions({
...
...
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
View file @
389dd2af
...
...
@@ -37,27 +37,18 @@ require('./filtered_search_dropdown');
}
renderContent() {
const dropdownData = [{
icon: 'fa-pencil',
hint: 'author:',
tag: '<@author>',
}, {
icon: 'fa-user',
hint: 'assignee:',
tag: '<@assignee>',
}, {
icon: 'fa-clock-o',
hint: 'milestone:',
tag: '<%milestone>',
}, {
icon: 'fa-tag',
hint: 'label:',
tag: '<~label>',
}, {
icon: 'fa-balance-scale',
hint: 'weight:',
tag: '<weight>',
}];
const dropdownData = [];
[].forEach.call(this.input.parentElement.querySelectorAll('.dropdown-menu'), (dropdownMenu) => {
const { icon, hint, tag } = dropdownMenu.dataset;
if (icon && hint && tag) {
dropdownData.push({
icon: `fa-${icon}`,
hint,
tag: `<${tag}>`,
});
}
});
this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config);
this.droplab.setData(this.hookId, dropdownData);
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
View file @
389dd2af
...
...
@@ -52,8 +52,9 @@
}
renderContent(forceShowList = false) {
if (forceShowList && this.getCurrentHook().list.hidden) {
this.getCurrentHook().list.show();
const currentHook = this.getCurrentHook();
if (forceShowList && currentHook && currentHook.list.hidden) {
currentHook.list.show();
}
}
...
...
@@ -92,11 +93,15 @@
}
hideDropdown() {
this.getCurrentHook().list.hide();
const currentHook = this.getCurrentHook();
if (currentHook) {
currentHook.list.hide();
}
}
resetFilters() {
const hook = this.getCurrentHook();
if (hook) {
const data = hook.list.data;
const results = data.map((o) => {
const updated = o;
...
...
@@ -106,6 +111,7 @@
hook.list.render(results);
}
}
}
window.gl = window.gl || {};
gl.FilteredSearchDropdown = FilteredSearchDropdown;
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
View file @
389dd2af
...
...
@@ -2,10 +2,16 @@
(() => {
class FilteredSearchDropdownManager {
constructor(baseEndpoint = '') {
constructor(baseEndpoint = ''
, page
) {
this.baseEndpoint = baseEndpoint.replace(/\/$/, '');
this.tokenizer = gl.FilteredSearchTokenizer;
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys;
this.filteredSearchInput = document.querySelector('.filtered-search');
this.page = page;
if (this.page === 'issues') {
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeysWithWeights;
}
this.setupMapping();
...
...
@@ -48,17 +54,20 @@
extraArguments: [`${this.baseEndpoint}/labels.json`, '~'],
element: document.querySelector('#js-dropdown-label'),
},
weight: {
reference: null,
gl: 'DropdownNonUser',
element: document.querySelector('#js-dropdown-weight'),
},
hint: {
reference: null,
gl: 'DropdownHint',
element: document.querySelector('#js-dropdown-hint'),
},
};
if (this.page === 'issues') {
this.mapping.weight = {
reference: null,
gl: 'DropdownNonUser',
element: document.querySelector('#js-dropdown-weight'),
};
}
}
static addWordToInput(tokenName, tokenValue = '') {
...
...
@@ -155,7 +164,7 @@
this.droplab = new DropLab();
}
const match =
gl.F
ilteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
const match =
this.f
ilteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key
&& this.mapping[match.key];
const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint';
...
...
app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
View file @
389dd2af
(() => {
class FilteredSearchManager {
constructor() {
constructor(
page
) {
this.filteredSearchInput = document.querySelector('.filtered-search');
this.clearSearchButton = document.querySelector('.clear-search');
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys;
if (page === 'issues') {
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeysWithWeights;
}
if (this.filteredSearchInput) {
this.tokenizer = gl.FilteredSearchTokenizer;
this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || '');
this.dropdownManager = new gl.FilteredSearchDropdownManager(this.filteredSearchInput.getAttribute('data-base-endpoint') || ''
, page
);
this.bindEvents();
this.loadSearchParamsFromURL();
...
...
@@ -118,7 +123,7 @@
const value = split[1];
// Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys
const condition =
gl.F
ilteredSearchTokenKeys.searchByConditionUrl(p);
const condition =
this.f
ilteredSearchTokenKeys.searchByConditionUrl(p);
if (condition) {
inputValues.push(`${condition.tokenKey}:${condition.value}`);
...
...
@@ -126,7 +131,7 @@
// Sanitize value since URL converts spaces into +
// Replace before decode so that we know what was originally + versus the encoded +
const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value;
const match =
gl.F
ilteredSearchTokenKeys.searchByKeyParam(keyParam);
const match =
this.f
ilteredSearchTokenKeys.searchByKeyParam(keyParam);
if (match) {
const indexOf = keyParam.indexOf('_');
...
...
@@ -171,9 +176,9 @@
paths.push(`state=${currentState}`);
tokens.forEach((token) => {
const condition =
gl.F
ilteredSearchTokenKeys
const condition =
this.f
ilteredSearchTokenKeys
.searchByConditionKeyValue(token.key, token.value.toLowerCase());
const { param } =
gl.F
ilteredSearchTokenKeys.searchByKey(token.key) || {};
const { param } =
this.f
ilteredSearchTokenKeys.searchByKey(token.key) || {};
const keyParam = param ? `${token.key}_${param}` : token.key;
let tokenPath = '';
...
...
app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
View file @
389dd2af
...
...
@@ -19,11 +19,6 @@
type: 'array',
param: 'name[]',
symbol: '~',
}, {
key: 'weight',
type: 'string',
param: '',
symbol: '',
}];
const alternativeTokenKeys = [{
...
...
@@ -51,14 +46,6 @@
url: 'label_name[]=No+Label',
tokenKey: 'label',
value: 'none',
}, {
url: 'weight=No+Weight',
tokenKey: 'weight',
value: 'none',
}, {
url: 'weight=Any+Weight',
tokenKey: 'weight',
value: 'any',
}];
class FilteredSearchTokenKeys {
...
...
app/assets/javascripts/filtered_search/filtered_search_token_keys_with_weights.js.es6
0 → 100644
View file @
389dd2af
require('./filtered_search_token_keys');
const weightTokenKey = {
key: 'weight',
type: 'string',
param: '',
symbol: '',
};
const weightConditions = [{
url: 'weight=No+Weight',
tokenKey: 'weight',
value: 'none',
}, {
url: 'weight=Any+Weight',
tokenKey: 'weight',
value: 'any',
}];
class FilteredSearchTokenKeysWithWeights extends gl.FilteredSearchTokenKeys {
static get() {
const tokenKeys = super.get();
tokenKeys.push(weightTokenKey);
return tokenKeys;
}
static getAlternatives() {
return super.getAlternatives();
}
static getConditions() {
const conditions = super.getConditions();
return conditions.concat(weightConditions);
}
static searchByKey(key) {
const tokenKeys = FilteredSearchTokenKeysWithWeights.get();
return tokenKeys.find(tokenKey => tokenKey.key === key) || null;
}
static searchBySymbol(symbol) {
const tokenKeys = FilteredSearchTokenKeysWithWeights.get();
return tokenKeys.find(tokenKey => tokenKey.symbol === symbol) || null;
}
static searchByKeyParam(keyParam) {
const tokenKeys = FilteredSearchTokenKeysWithWeights.get();
const alternativeTokenKeys = FilteredSearchTokenKeysWithWeights.getAlternatives();
const tokenKeysWithAlternative = tokenKeys.concat(alternativeTokenKeys);
return tokenKeysWithAlternative.find((tokenKey) => {
let tokenKeyParam = tokenKey.key;
if (tokenKey.param) {
tokenKeyParam += `_${tokenKey.param}`;
}
return keyParam === tokenKeyParam;
}) || null;
}
static searchByConditionUrl(url) {
const conditions = FilteredSearchTokenKeysWithWeights.getConditions();
return conditions.find(condition => condition.url === url) || null;
}
static searchByConditionKeyValue(key, value) {
const conditions = FilteredSearchTokenKeysWithWeights.getConditions();
return conditions
.find(condition => condition.tokenKey === key && condition.value === value) || null;
}
}
window.gl = window.gl || {};
gl.FilteredSearchTokenKeysWithWeights = FilteredSearchTokenKeysWithWeights;
app/assets/javascripts/search_autocomplete.js.es6
View file @
389dd2af
...
...
@@ -169,10 +169,10 @@
url: issuesPath + "/?author_username=" + userName
}, 'separator', {
text: 'Merge requests assigned to me',
url: mrPath + "/?assignee_
id=" + userId
url: mrPath + "/?assignee_
username=" + userName
}, {
text: "Merge requests I've created",
url: mrPath + "/?author_
id=" + userId
url: mrPath + "/?author_
username=" + userName
}
];
if (!name) {
...
...
app/controllers/projects/merge_requests_controller.rb
View file @
389dd2af
...
...
@@ -53,6 +53,16 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@labels
=
LabelsFinder
.
new
(
current_user
,
labels_params
).
execute
end
@users
=
[]
if
params
[
:assignee_id
].
present?
assignee
=
User
.
find_by_id
(
params
[
:assignee_id
])
@users
.
push
(
assignee
)
if
assignee
end
if
params
[
:author_id
].
present?
author
=
User
.
find_by_id
(
params
[
:author_id
])
@users
.
push
(
author
)
if
author
end
respond_to
do
|
format
|
format
.
html
format
.
json
do
...
...
app/views/projects/merge_requests/index.html.haml
View file @
389dd2af
...
...
@@ -5,18 +5,19 @@
=
render
"projects/issues/head"
=
render
'projects/last_push'
-
content_for
:page_specific_javascripts
do
=
page_specific_javascript_bundle_tag
(
'filtered_search'
)
%div
{
class:
container_class
}
.top-area
=
render
'shared/issuable/nav'
,
type: :merge_requests
.nav-controls
=
render
'shared/issuable/search_form'
,
path:
namespace_project_merge_requests_path
(
@project
.
namespace
,
@project
)
-
merge_project
=
can?
(
current_user
,
:create_merge_request
,
@project
)
?
@project
:
(
current_user
&&
current_user
.
fork_of
(
@project
))
-
if
merge_project
=
link_to
new_namespace_project_merge_request_path
(
merge_project
.
namespace
,
merge_project
),
class:
"btn btn-new"
,
title:
"New Merge Request"
do
New Merge Request
=
render
'shared/issuable/
filte
r'
,
type: :merge_requests
=
render
'shared/issuable/
search_ba
r'
,
type: :merge_requests
.merge-requests-holder
=
render
'merge_requests'
app/views/shared/issuable/_search_bar.html.haml
View file @
389dd2af
...
...
@@ -32,7 +32,7 @@
{{hint}}
%span
.js-filter-tag.dropdown-light-content
{{tag}}
#js-dropdown-author
.dropdown-menu
#js-dropdown-author
.dropdown-menu
{
data:
{
icon:
'pencil'
,
hint:
'author'
,
tag:
'@author'
}
}
%ul
.filter-dropdown
{
'data-dynamic'
=>
true
,
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
%button
.btn.btn-link.dropdown-user
...
...
@@ -42,7 +42,7 @@
{{name}}
%span
.dropdown-light-content
@{{username}}
#js-dropdown-assignee
.dropdown-menu
#js-dropdown-assignee
.dropdown-menu
{
data:
{
icon:
'user'
,
hint:
'assignee'
,
tag:
'@assignee'
}
}
%ul
{
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
{
'data-value'
=>
'none'
}
%button
.btn.btn-link
...
...
@@ -57,7 +57,7 @@
{{name}}
%span
.dropdown-light-content
@{{username}}
#js-dropdown-milestone
.dropdown-menu
{
'data-dropdown'
=>
true
}
#js-dropdown-milestone
.dropdown-menu
{
data:
{
icon:
'clock-o'
,
hint:
'milestone'
,
tag:
'%milestone'
}
}
%ul
{
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
{
'data-value'
=>
'none'
}
%button
.btn.btn-link
...
...
@@ -70,7 +70,7 @@
%li
.filter-dropdown-item
%button
.btn.btn-link.js-data-value
{{title}}
#js-dropdown-label
.dropdown-menu
{
'data-dropdown'
=>
true
}
#js-dropdown-label
.dropdown-menu
{
data:
{
icon:
'tag'
,
hint:
'label'
,
tag:
'~label'
}
}
%ul
{
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
{
'data-value'
=>
'none'
}
%button
.btn.btn-link
...
...
@@ -82,7 +82,8 @@
%span
.dropdown-label-box
{
style:
'
background:
{{
color
}}
'
}
%span
.label-title.js-data-value
{{title}}
#js-dropdown-weight
.dropdown-menu
{
'data-dropdown'
=>
true
}
-
if
type
==
:issues
#js-dropdown-weight
.dropdown-menu
{
data:
{
icon:
'balance-scale'
,
hint:
'weight'
,
tag:
'weight'
}
}
%ul
{
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
{
'data-value'
=>
'none'
}
%button
.btn.btn-link
...
...
changelogs/unreleased-ee/add-filtered-search-to-mr-ee.yml
0 → 100644
View file @
389dd2af
---
title
:
Add filtered search to MR page
merge_request
:
1243
author
:
features/project/merge_requests.feature
View file @
389dd2af
...
...
@@ -299,13 +299,6 @@ Feature: Project Merge Requests
And I preview a description text like "Bug fixed
:
smile
:
"
Then
I should see the Markdown write tab
@javascript
Scenario
:
I
search merge request
Given
I click link
"All"
When
I fill in merge request search with
"Fe"
Then
I should see
"Feature NS-03"
in merge requests
And
I should not see
"Bug NS-04"
in merge requests
@javascript
Scenario
:
I
can unsubscribe from merge request
Given
I visit merge request page
"Bug NS-04"
...
...
spec/features/issues/filtered_search/dropdown_label_spec.rb
View file @
389dd2af
require
'spec_helper'
describe
'Dropdown label'
,
js:
true
,
feature:
true
do
include
FilteredSearchHelpers
let
(
:project
)
{
create
(
:empty_project
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:filtered_search
)
{
find
(
'.filtered-search'
)
}
...
...
@@ -17,12 +19,6 @@ describe 'Dropdown label', js: true, feature: true do
let!
(
:long_label
)
{
create
(
:label
,
project:
project
,
title:
'this is a very long title this is a very long title this is a very long title this is a very long title this is a very long title'
)
}
end
def
init_label_search
filtered_search
.
set
(
'label:'
)
# This ensures the dropdown is shown
expect
(
find
(
js_dropdown_label
)).
not_to
have_css
(
'.filter-dropdown-loading'
)
end
def
search_for_label
(
label
)
init_label_search
filtered_search
.
send_keys
(
label
)
...
...
spec/features/issues/filtered_search/filter_issues_spec.rb
View file @
389dd2af
require
'rails_helper'
describe
'Filter issues'
,
js:
true
,
feature:
true
do
include
FilteredSearchHelpers
include
WaitForAjax
let!
(
:group
)
{
create
(
:group
)
}
...
...
@@ -17,19 +18,6 @@ describe 'Filter issues', js: true, feature: true do
let!
(
:multiple_words_label
)
{
create
(
:label
,
project:
project
,
title:
"Two words"
)
}
let!
(
:closed_issue
)
{
create
(
:issue
,
title:
'bug that is closed'
,
project:
project
,
state: :closed
)
}
let
(
:filtered_search
)
{
find
(
'.filtered-search'
)
}
def
input_filtered_search
(
search_term
,
submit:
true
)
filtered_search
.
set
(
search_term
)
if
submit
filtered_search
.
send_keys
(
:enter
)
end
end
def
expect_filtered_search_input
(
input
)
expect
(
find
(
'.filtered-search'
).
value
).
to
eq
(
input
)
end
def
expect_no_issues_list
page
.
within
'.issues-list'
do
...
...
spec/features/merge_requests/filter_by_labels_spec.rb
View file @
389dd2af
require
'rails_helper'
feature
'Issue filtering by Labels'
,
feature:
true
,
js:
true
do
include
FilteredSearchHelpers
include
MergeRequestHelpers
include
WaitForAjax
let
(
:project
)
{
create
(
:project
,
:public
)
}
...
...
@@ -32,123 +34,77 @@ feature 'Issue filtering by Labels', feature: true, js: true do
context
'filter by label bug'
do
before
do
select_labels
(
'
bug'
)
input_filtered_search
(
'label:~
bug'
)
end
it
'apply the filter'
do
expect
(
page
).
to
have_content
"Bugfix1"
expect
(
page
).
to
have_content
"Bugfix2"
expect
(
page
).
not_to
have_content
"Feature1"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"bug"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"feature"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"enhancement"
find
(
'.js-label-filter-remove'
).
click
wait_for_ajax
expect
(
find
(
'.filtered-labels'
,
visible:
false
)).
to
have_no_content
"bug"
end
end
context
'filter by label feature'
do
before
do
select_labels
(
'
feature'
)
input_filtered_search
(
'label:~
feature'
)
end
it
'applies the filter'
do
expect
(
page
).
to
have_content
"Feature1"
expect
(
page
).
not_to
have_content
"Bugfix2"
expect
(
page
).
not_to
have_content
"Bugfix1"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"feature"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"bug"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"enhancement"
end
end
context
'filter by label enhancement'
do
before
do
select_labels
(
'
enhancement'
)
input_filtered_search
(
'label:~
enhancement'
)
end
it
'applies the filter'
do
expect
(
page
).
to
have_content
"Bugfix2"
expect
(
page
).
not_to
have_content
"Feature1"
expect
(
page
).
not_to
have_content
"Bugfix1"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"enhancement"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"bug"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"feature"
end
end
context
'filter by label enhancement and bug in issues list'
do
before
do
select_labels
(
'bug'
,
'
enhancement'
)
input_filtered_search
(
'label:~bug label:~
enhancement'
)
end
it
'applies the filters'
do
expect
(
page
).
to
have_issuable_counts
(
open:
1
,
closed:
0
,
all:
1
)
expect
(
page
).
to
have_content
"Bugfix2"
expect
(
page
).
not_to
have_content
"Feature1"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"bug"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"enhancement"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"feature"
find
(
'.js-label-filter-remove'
,
match: :first
).
click
wait_for_ajax
expect
(
page
).
to
have_content
"Bugfix2"
expect
(
page
).
not_to
have_content
"Feature1"
expect
(
page
).
not_to
have_content
"Bugfix1"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"bug"
expect
(
find
(
'.filtered-labels'
)).
to
have_content
"enhancement"
expect
(
find
(
'.filtered-labels'
)).
not_to
have_content
"feature"
end
end
context
'
remove filtered labels
'
do
context
'
clear button
'
do
before
do
page
.
within
'.labels-filter'
do
click_button
'Label'
wait_for_ajax
click_link
'bug'
find
(
'.dropdown-menu-close'
).
click
end
page
.
within
'.filtered-labels'
do
expect
(
page
).
to
have_content
'bug'
end
input_filtered_search
(
'label:~bug'
)
end
it
'allows user to remove filtered labels'
do
first
(
'.
js-label-filter-remove
'
).
click
wait_for_ajax
first
(
'.
clear-search
'
).
click
filtered_search
.
send_keys
(
:enter
)
expect
(
find
(
'.filtered-labels'
,
visible:
false
)).
not_to
have_content
'bug'
expect
(
find
(
'.labels-filter'
)).
not_to
have_content
'bug'
expect
(
page
).
to
have_issuable_counts
(
open:
3
,
closed:
0
,
all:
3
)
expect
(
page
).
to
have_content
"Bugfix2"
expect
(
page
).
to
have_content
"Feature1"
expect
(
page
).
to
have_content
"Bugfix1"
end
end
context
'
dropdown filtering
'
do
context
'
filter dropdown
'
do
it
'filters by label name'
do
page
.
within
'.labels-filter'
do
click_button
'Label'
wait_for_ajax
find
(
'.dropdown-input input'
).
set
'bug'
init_label_search
filtered_search
.
send_keys
(
'~bug'
)
page
.
within
'.dropdown-content
'
do
page
.
within
'.filter-dropdown
'
do
expect
(
page
).
not_to
have_content
'enhancement'
expect
(
page
).
to
have_content
'bug'
end
end
end
end
def
select_labels
(
*
labels
)
page
.
find
(
'.js-label-select'
).
click
wait_for_ajax
labels
.
each
do
|
label
|
execute_script
(
"$('.dropdown-menu-labels li:contains(
\"
#{
label
}
\"
) a').click()"
)
end
page
.
first
(
'.labels-filter .dropdown-title .dropdown-menu-close-icon'
).
click
wait_for_ajax
end
end
spec/features/merge_requests/filter_by_milestone_spec.rb
View file @
389dd2af
require
'rails_helper'
feature
'Merge Request filtering by Milestone'
,
feature:
true
do
include
FilteredSearchHelpers
include
MergeRequestHelpers
let
(
:project
)
{
create
(
:project
,
:public
)
}
let!
(
:user
)
{
create
(
:user
)}
let
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
def
filter_by_milestone
(
title
)
find
(
".js-milestone-select"
).
click
find
(
".milestone-filter a"
,
text:
title
).
click
end
before
do
project
.
team
<<
[
user
,
:master
]
login_as
(
user
)
...
...
@@ -15,42 +23,42 @@ feature 'Merge Request filtering by Milestone', feature: true do
create
(
:merge_request
,
:simple
,
source_project:
project
,
milestone:
milestone
)
visit_merge_requests
(
project
)
filter_by_milestone
(
Milestone
::
None
.
title
)
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
context
'filters by upcoming milestone'
,
js:
true
do
it
'does not show
issue
s with no expiry'
do
it
'does not show
merge request
s with no expiry'
do
create
(
:merge_request
,
:with_diffs
,
source_project:
project
)
create
(
:merge_request
,
:simple
,
source_project:
project
,
milestone:
milestone
)
visit_merge_requests
(
project
)
filter_by_milestone
(
Milestone
::
Upcoming
.
title
)
input_filtered_search
(
'milestone:upcoming'
)
expect
(
page
).
to
have_css
(
'.merge-request'
,
count:
0
)
end
it
'shows
issue
s in future'
do
it
'shows
merge request
s in future'
do
milestone
=
create
(
:milestone
,
project:
project
,
due_date:
Date
.
tomorrow
)
create
(
:merge_request
,
:with_diffs
,
source_project:
project
)
create
(
:merge_request
,
:simple
,
source_project:
project
,
milestone:
milestone
)
visit_merge_requests
(
project
)
filter_by_milestone
(
Milestone
::
Upcoming
.
title
)
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
)
end
it
'does not show
issue
s in past'
do
it
'does not show
merge request
s in past'
do
milestone
=
create
(
:milestone
,
project:
project
,
due_date:
Date
.
yesterday
)
create
(
:merge_request
,
:with_diffs
,
source_project:
project
)
create
(
:merge_request
,
:simple
,
source_project:
project
,
milestone:
milestone
)
visit_merge_requests
(
project
)
filter_by_milestone
(
Milestone
::
Upcoming
.
title
)
input_filtered_search
(
'milestone:upcoming'
)
expect
(
page
).
to
have_css
(
'.merge-request'
,
count:
0
)
end
...
...
@@ -61,7 +69,7 @@ feature 'Merge Request filtering by Milestone', feature: true do
create
(
:merge_request
,
:simple
,
source_project:
project
)
visit_merge_requests
(
project
)
filter_by_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
)
...
...
@@ -77,19 +85,10 @@ feature 'Merge Request filtering by Milestone', feature: true do
create
(
:merge_request
,
:simple
,
source_project:
project
)
visit_merge_requests
(
project
)
filter_by_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
)
end
end
def
visit_merge_requests
(
project
)
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
end
def
filter_by_milestone
(
title
)
find
(
".js-milestone-select"
).
click
find
(
".milestone-filter a"
,
text:
title
).
click
end
end
spec/features/merge_requests/filter_merge_requests_spec.rb
View file @
389dd2af
require
'rails_helper'
describe
'Filter merge requests'
,
feature:
true
do
include
FilteredSearchHelpers
include
MergeRequestHelpers
include
WaitForAjax
let!
(
:project
)
{
create
(
:project
)
}
let!
(
:group
)
{
create
(
:group
)
}
let!
(
:user
)
{
create
(
:user
)}
let!
(
:user
)
{
create
(
:user
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let!
(
:label
)
{
create
(
:label
,
project:
project
)
}
let!
(
:wontfix
)
{
create
(
:label
,
project:
project
,
title:
"Won't fix"
)
}
...
...
@@ -15,183 +17,134 @@ describe 'Filter merge requests', feature: true do
group
.
add_developer
(
user
)
login_as
(
user
)
create
(
:merge_request
,
source_project:
project
,
target_project:
project
)
end
describe
'for assignee from mr#index'
do
before
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
end
find
(
'.js-assignee-search'
).
click
describe
'for assignee from mr#index'
do
let
(
:search_query
)
{
"assignee:@
#{
user
.
username
}
"
}
find
(
'.dropdown-menu-user-link'
,
text:
user
.
username
).
click
before
do
input_filtered_search
(
search_query
)
wait_for_ajax
expect_mr_list_count
(
0
)
end
context
'assignee'
,
js:
true
do
it
'updates to current user'
do
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
_filtered_search_input
(
search_query
)
end
it
'does not change when closed link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"Closed"
).
click
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
_filtered_search_input
(
search_query
)
end
it
'does not change when all link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"All"
).
click
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
_filtered_search_input
(
search_query
)
end
end
end
describe
'for milestone from mr#index'
do
before
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
let
(
:search_query
)
{
"milestone:%
#{
milestone
.
title
}
"
}
find
(
'.js-milestone-select'
).
click
find
(
'.milestone-filter .dropdown-content a'
,
text:
milestone
.
title
).
click
before
do
input_filtered_search
(
search_query
)
wait_for_ajax
expect_mr_list_count
(
0
)
end
context
'milestone'
,
js:
true
do
it
'updates to current milestone'
do
expect
(
find
(
'.js-milestone-select .dropdown-toggle-text'
)).
to
have_content
(
milestone
.
title
)
expect
_filtered_search_input
(
search_query
)
end
it
'does not change when closed link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"Closed"
).
click
expect
(
find
(
'.js-milestone-select .dropdown-toggle-text'
)).
to
have_content
(
milestone
.
title
)
expect
_filtered_search_input
(
search_query
)
end
it
'does not change when all link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"All"
).
click
expect
(
find
(
'.js-milestone-select .dropdown-toggle-text'
)).
to
have_content
(
milestone
.
title
)
expect
_filtered_search_input
(
search_query
)
end
end
end
describe
'for label from mr#index'
,
js:
true
do
before
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
find
(
'.js-label-select'
).
click
wait_for_ajax
end
it
'filters by any label'
do
find
(
'.dropdown-menu-labels a'
,
text:
'Any Label'
).
click
page
.
first
(
'.labels-filter .dropdown-title .dropdown-menu-close-icon'
).
click
wait_for_ajax
expect
(
find
(
'.labels-filter'
)).
to
have_content
'Label'
end
it
'filters by no label'
do
find
(
'.dropdown-menu-labels a'
,
text:
'No Label'
).
click
page
.
first
(
'.labels-filter .dropdown-title .dropdown-menu-close-icon'
).
click
wait_for_ajax
input_filtered_search
(
'label:none'
)
page
.
within
'.labels-filter'
do
expect
(
page
).
to
have_content
'Labels'
end
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
'Labels'
)
expect_mr_list_count
(
1
)
expect_filtered_search_input
(
'label:none'
)
end
it
'filters by a label'
do
find
(
'.dropdown-menu-labels a'
,
text:
label
.
title
).
click
page
.
within
'.labels-filter'
do
expect
(
page
).
to
have_content
label
.
title
end
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
label
.
title
)
input_filtered_search
(
"label:~
#{
label
.
title
}
"
)
expect_mr_list_count
(
0
)
expect_filtered_search_input
(
"label:~
#{
label
.
title
}
"
)
end
it
"filters by `won't fix` and another label"
do
page
.
within
'.labels-filter'
do
click_link
wontfix
.
title
expect
(
page
).
to
have_content
wontfix
.
title
click_link
label
.
title
end
input_filtered_search
(
"label:~
\"
#{
wontfix
.
title
}
\"
label:~
#{
label
.
title
}
"
)
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
"
#{
wontfix
.
title
}
+1 more"
)
expect_mr_list_count
(
0
)
expect_filtered_search_input
(
"label:~
\"
#{
wontfix
.
title
}
\"
label:~
#{
label
.
title
}
"
)
end
it
"filters by `won't fix` label followed by another label after page load"
do
page
.
within
'.labels-filter'
do
click_link
wontfix
.
title
expect
(
page
).
to
have_content
wontfix
.
title
end
find
(
'body'
).
click
expect
(
find
(
'.filtered-labels'
)).
to
have_content
(
wontfix
.
title
)
find
(
'.js-label-select'
).
click
wait_for_ajax
find
(
'.dropdown-menu-labels a'
,
text:
label
.
title
).
click
input_filtered_search
(
"label:~
\"
#{
wontfix
.
title
}
\"
"
)
find
(
'body'
).
click
expect_mr_list_count
(
0
)
expect_filtered_search_input
(
"label:~
\"
#{
wontfix
.
title
}
\"
"
)
expect
(
find
(
'.filtered-labels'
)).
to
have_content
(
wontfix
.
title
)
expect
(
find
(
'.filtered-labels'
)).
to
have_content
(
label
.
title
)
input_filtered_search_keys
(
" label:~
#{
label
.
title
}
"
)
find
(
'.js-label-select'
).
click
wait_for_ajax
expect
(
find
(
'.dropdown-menu-labels li'
,
text:
wontfix
.
title
)).
to
have_css
(
'.is-active'
)
expect
(
find
(
'.dropdown-menu-labels li'
,
text:
label
.
title
)).
to
have_css
(
'.is-active'
)
end
expect_filtered_search_input
(
"label:~
\"
#{
wontfix
.
title
}
\"
label:~
#{
label
.
title
}
"
)
it
"selects and unselects `won't fix`"
do
find
(
'.dropdown-menu-labels a'
,
text:
wontfix
.
title
).
click
find
(
'.dropdown-menu-labels a'
,
text:
wontfix
.
title
).
click
# Close label dropdown to load
find
(
'body'
).
click
expect
(
page
).
not_to
have_css
(
'.filtered-labels'
)
expect_mr_list_count
(
0
)
expect_filtered_search_input
(
"label:~
\"
#{
wontfix
.
title
}
\"
label:~
#{
label
.
title
}
"
)
end
end
describe
'for assignee and label from issues#index'
do
before
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
let
(
:search_query
)
{
"assignee:@
#{
user
.
username
}
label:~
#{
label
.
title
}
"
}
find
(
'.js-assignee-search'
).
click
find
(
'.dropdown-menu-user-link'
,
text:
user
.
username
).
click
before
do
input_filtered_search
(
"assignee:@
#{
user
.
username
}
"
)
expect
(
page
).
not_to
have_selector
(
'.mr-list .merge-request'
)
expect_mr_list_count
(
1
)
expect_filtered_search_input
(
"assignee:@
#{
user
.
username
}
"
)
find
(
'.js-label-select'
).
click
input_filtered_search_keys
(
" label:~
#{
label
.
title
}
"
)
find
(
'.dropdown-menu-labels .dropdown-content a'
,
text:
label
.
title
).
click
page
.
first
(
'.labels-filter .dropdown-title .dropdown-menu-close-icon'
).
click
expect_mr_list_count
(
1
)
wait_for_ajax
find
(
"#state-opened[href=
\"
#{
URI
.
parse
(
current_url
).
path
}
?assignee_username=
#{
user
.
username
}
&label_name%5B%5D=
#{
label
.
title
}
&scope=all&state=opened
\"
]"
)
end
context
'assignee and label'
,
js:
true
do
it
'updates to current assignee and label'
do
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
label
.
title
)
expect_filtered_search_input
(
search_query
)
end
it
'does not change when closed link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"Closed"
).
click
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
label
.
title
)
expect_filtered_search_input
(
search_query
)
end
it
'does not change when all link is clicked'
do
find
(
'.issues-state-filters a'
,
text:
"All"
).
click
expect
(
find
(
'.js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
(
find
(
'.js-label-select .dropdown-toggle-text'
)).
to
have_content
(
label
.
title
)
expect_filtered_search_input
(
search_query
)
end
end
end
...
...
@@ -218,15 +171,13 @@ describe 'Filter merge requests', feature: true do
context
'only text'
,
js:
true
do
it
'filters merge requests by searched text'
do
fill_in
'issuable_search'
,
with:
'Bug'
input_filtered_search
(
'bug'
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
end
it
'does not show any merge requests'
do
fill_in
'issuable_search'
,
with:
'testing'
input_filtered_search
(
'testing'
)
page
.
within
'.mr-list'
do
expect
(
page
).
not_to
have_selector
(
'.merge-request'
)
...
...
@@ -234,82 +185,49 @@ describe 'Filter merge requests', feature: true do
end
end
context
'
text and dropdown option
s'
,
js:
true
do
context
'
filters and searche
s'
,
js:
true
do
it
'filters by text and label'
do
fill_in
'issuable_search'
,
with:
'Bug'
input_filtered_search
(
'Bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
2
,
closed:
0
,
all:
2
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
expect_filtered_search_input
(
'Bug'
)
click_button
'Label'
page
.
within
'.labels-filter'
do
click_link
'bug'
end
find
(
'.dropdown-menu-close-icon'
).
click
input_filtered_search_keys
(
' label:~bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
1
,
closed:
0
,
all:
1
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
1
)
end
expect_mr_list_count
(
1
)
end
it
'filters by text and milestone'
do
fill_in
'issuable_search'
,
with:
'Bug'
input_filtered_search
(
'Bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
2
,
closed:
0
,
all:
2
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
expect_filtered_search_input
(
'Bug'
)
click_button
'Milestone'
page
.
within
'.milestone-filter'
do
click_link
'8'
end
input_filtered_search_keys
(
' milestone:%8'
)
expect
(
page
).
to
have_issuable_counts
(
open:
1
,
closed:
0
,
all:
1
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
1
)
end
expect_mr_list_count
(
1
)
end
it
'filters by text and assignee'
do
fill_in
'issuable_search'
,
with:
'Bug'
input_filtered_search
(
'Bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
2
,
closed:
0
,
all:
2
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
expect_filtered_search_input
(
'Bug'
)
click_button
'Assignee'
page
.
within
'.dropdown-menu-assignee'
do
click_link
user
.
name
end
input_filtered_search_keys
(
" assignee:@
#{
user
.
username
}
"
)
expect
(
page
).
to
have_issuable_counts
(
open:
1
,
closed:
0
,
all:
1
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
1
)
end
expect_mr_list_count
(
1
)
end
it
'filters by text and author'
do
fill_in
'issuable_search'
,
with:
'Bug'
input_filtered_search
(
'Bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
2
,
closed:
0
,
all:
2
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
expect_filtered_search_input
(
'Bug'
)
click_button
'Author'
page
.
within
'.dropdown-menu-author'
do
click_link
user
.
name
end
input_filtered_search_keys
(
" author:@
#{
user
.
username
}
"
)
expect
(
page
).
to
have_issuable_counts
(
open:
1
,
closed:
0
,
all:
1
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
1
)
end
expect_mr_list_count
(
1
)
end
end
end
...
...
@@ -328,18 +246,9 @@ describe 'Filter merge requests', feature: true do
end
it
'is able to filter and sort merge requests'
do
click_button
'Label'
wait_for_ajax
page
.
within
'.labels-filter'
do
click_link
'bug'
end
find
(
'.dropdown-menu-close-icon'
).
click
wait_for_ajax
input_filtered_search
(
'label:~bug'
)
expect
(
page
).
to
have_issuable_counts
(
open:
2
,
closed:
0
,
all:
2
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
2
)
end
expect_mr_list_count
(
2
)
click_button
'Last created'
page
.
within
'.dropdown-menu-sort'
do
...
...
@@ -352,4 +261,38 @@ describe 'Filter merge requests', feature: true do
end
end
end
describe
'filter by assignee id'
,
js:
true
do
it
'filter by current user'
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
,
assignee_id:
user
.
id
)
expect_filtered_search_input
(
"assignee:@
#{
user
.
username
}
"
)
end
it
'filter by new user'
do
new_user
=
create
(
:user
)
project
.
add_developer
(
new_user
)
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
,
assignee_id:
new_user
.
id
)
expect_filtered_search_input
(
"assignee:@
#{
new_user
.
username
}
"
)
end
end
describe
'filter by author id'
,
js:
true
do
it
'filter by current user'
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
,
author_id:
user
.
id
)
expect_filtered_search_input
(
"author:@
#{
user
.
username
}
"
)
end
it
'filter by new user'
do
new_user
=
create
(
:user
)
project
.
add_developer
(
new_user
)
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
,
author_id:
new_user
.
id
)
expect_filtered_search_input
(
"author:@
#{
new_user
.
username
}
"
)
end
end
end
spec/features/merge_requests/reset_filters_spec.rb
View file @
389dd2af
require
'rails_helper'
feature
'Issues filter reset button'
,
feature:
true
,
js:
true
do
include
FilteredSearchHelpers
include
MergeRequestHelpers
include
WaitForAjax
include
IssueHelpers
let!
(
:project
)
{
create
(
:project
,
:public
)
}
let!
(
:user
)
{
create
(
:user
)
}
let!
(
:user
)
{
create
(
:user
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let!
(
:bug
)
{
create
(
:label
,
project:
project
,
name:
'bug'
)}
let!
(
:mr1
)
{
create
(
:merge_request
,
title:
"Feature"
,
source_project:
project
,
target_project:
project
,
source_branch:
"Feature"
,
milestone:
milestone
,
author:
user
,
assignee:
user
)
}
let!
(
:mr2
)
{
create
(
:merge_request
,
title:
"Bugfix1"
,
source_project:
project
,
target_project:
project
,
source_branch:
"Bugfix1"
)
}
let
(
:merge_request_css
)
{
'.merge-request'
}
let
(
:clear_search_css
)
{
'.filtered-search-input-container .clear-search'
}
before
do
mr2
.
labels
<<
bug
...
...
@@ -50,7 +53,7 @@ feature 'Issues filter reset button', feature: true, js: true do
context
'when author filter has been applied'
do
it
'resets the author filter'
do
visit_merge_requests
(
project
,
author_
id:
user
.
id
)
visit_merge_requests
(
project
,
author_
username:
user
.
username
)
expect
(
page
).
to
have_css
(
merge_request_css
,
count:
1
)
reset_filters
...
...
@@ -60,7 +63,7 @@ feature 'Issues filter reset button', feature: true, js: true do
context
'when assignee filter has been applied'
do
it
'resets the assignee filter'
do
visit_merge_requests
(
project
,
assignee_
id:
user
.
id
)
visit_merge_requests
(
project
,
assignee_
username:
user
.
username
)
expect
(
page
).
to
have_css
(
merge_request_css
,
count:
1
)
reset_filters
...
...
@@ -70,7 +73,7 @@ feature 'Issues filter reset button', feature: true, js: true do
context
'when all filters have been applied'
do
it
'resets all filters'
do
visit_merge_requests
(
project
,
assignee_
id:
user
.
id
,
author_id:
user
.
id
,
milestone_title:
milestone
.
title
,
label_name:
bug
.
name
,
search:
'Bug'
)
visit_merge_requests
(
project
,
assignee_
username:
user
.
username
,
author_username:
user
.
username
,
milestone_title:
milestone
.
title
,
label_name:
bug
.
name
,
search:
'Bug'
)
expect
(
page
).
to
have_css
(
merge_request_css
,
count:
0
)
reset_filters
...
...
@@ -82,15 +85,7 @@ feature 'Issues filter reset button', feature: true, js: true do
it
'the reset link should not be visible'
do
visit_merge_requests
(
project
)
expect
(
page
).
to
have_css
(
merge_request_css
,
count:
2
)
expect
(
page
).
not_to
have_css
'.reset_filters'
expect
(
page
).
not_to
have_css
(
clear_search_css
)
end
end
def
visit_merge_requests
(
project
,
opts
=
{})
visit
namespace_project_merge_requests_path
project
.
namespace
,
project
,
opts
end
def
reset_filters
find
(
'.reset-filters'
).
click
end
end
spec/features/search_spec.rb
View file @
389dd2af
...
...
@@ -186,7 +186,7 @@ describe "Search", feature: true do
sleep
2
expect
(
page
).
to
have_selector
(
'.merge-requests-holder'
)
expect
(
find
(
'.
js-assignee-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
(
find
(
'.
filtered-search'
).
value
).
to
eq
(
"assignee:@
#{
user
.
username
}
"
)
end
it
'takes user to her MR page when MR authored is clicked'
do
...
...
@@ -194,7 +194,7 @@ describe "Search", feature: true do
sleep
2
expect
(
page
).
to
have_selector
(
'.merge-requests-holder'
)
expect
(
find
(
'.
js-author-search .dropdown-toggle-text'
)).
to
have_content
(
user
.
name
)
expect
(
find
(
'.
filtered-search'
).
value
).
to
eq
(
"author:@
#{
user
.
username
}
"
)
end
end
...
...
spec/javascripts/filtered_search/filtered_search_token_keys_with_weights_spec.js.es6
0 → 100644
View file @
389dd2af
require('~/extensions/array');
require('~/filtered_search/filtered_search_token_keys_with_weights');
(() => {
describe('Filtered Search Token Keys With Weights', () => {
const weightTokenKey = {
key: 'weight',
type: 'string',
param: '',
symbol: '',
};
describe('get', () => {
let tokenKeys;
beforeEach(() => {
tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
});
it('should return tokenKeys', () => {
expect(tokenKeys !== null).toBe(true);
});
it('should return tokenKeys as an array', () => {
expect(tokenKeys instanceof Array).toBe(true);
});
it('should return weightTokenKey as part of tokenKeys', () => {
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
expect(match).toEqual(weightTokenKey);
});
});
describe('getConditions', () => {
let conditions;
beforeEach(() => {
conditions = gl.FilteredSearchTokenKeysWithWeights.getConditions();
});
it('should return conditions', () => {
expect(conditions !== null).toBe(true);
});
it('should return conditions as an array', () => {
expect(conditions instanceof Array).toBe(true);
});
it('should return weightConditions as part of conditions', () => {
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
expect(weightConditions.length).toBe(2);
});
});
describe('searchByKey', () => {
it('should return null when key not found', () => {
const tokenKey = gl.FilteredSearchTokenKeysWithWeights.searchByKey('notakey');
expect(tokenKey === null).toBe(true);
});
it('should return tokenKey when found by key', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const result = gl.FilteredSearchTokenKeysWithWeights.searchByKey(tokenKeys[0].key);
expect(result).toEqual(tokenKeys[0]);
});
it('should return weight tokenKey when found by weight key', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = gl.FilteredSearchTokenKeysWithWeights.searchByKey(weightTokenKey.key);
expect(result).toEqual(match);
});
});
describe('searchBySymbol', () => {
it('should return null when symbol not found', () => {
const tokenKey = gl.FilteredSearchTokenKeysWithWeights.searchBySymbol('notasymbol');
expect(tokenKey === null).toBe(true);
});
it('should return tokenKey when found by symbol', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const result = gl.FilteredSearchTokenKeysWithWeights.searchBySymbol(tokenKeys[0].symbol);
expect(result).toEqual(tokenKeys[0]);
});
it('should return weight tokenKey when found by weight symbol', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = gl.FilteredSearchTokenKeysWithWeights.searchBySymbol(weightTokenKey.symbol);
expect(result).toEqual(match);
});
});
describe('searchByKeyParam', () => {
it('should return null when key param not found', () => {
const tokenKey = gl.FilteredSearchTokenKeysWithWeights.searchByKeyParam('notakeyparam');
expect(tokenKey === null).toBe(true);
});
it('should return tokenKey when found by key param', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
it('should return alternative tokenKey when found by key param', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.getAlternatives();
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
it('should return weight tokenKey when found by weight key param', () => {
const tokenKeys = gl.FilteredSearchTokenKeysWithWeights.get();
const match = tokenKeys.find(tk => tk.key === weightTokenKey.key);
const result = gl.FilteredSearchTokenKeysWithWeights.searchByKeyParam(weightTokenKey.key);
expect(result).toEqual(match);
});
});
describe('searchByConditionUrl', () => {
it('should return null when condition url not found', () => {
const condition = gl.FilteredSearchTokenKeysWithWeights.searchByConditionUrl(null);
expect(condition === null).toBe(true);
});
it('should return condition when found by url', () => {
const conditions = gl.FilteredSearchTokenKeysWithWeights.getConditions();
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByConditionUrl(conditions[0].url);
expect(result).toBe(conditions[0]);
});
it('should return weight condition when found by weight url', () => {
const conditions = gl.FilteredSearchTokenKeysWithWeights.getConditions();
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByConditionUrl(weightConditions[0].url);
expect(result).toBe(weightConditions[0]);
});
});
describe('searchByConditionKeyValue', () => {
it('should return null when condition tokenKey and value not found', () => {
const condition = gl.FilteredSearchTokenKeysWithWeights
.searchByConditionKeyValue(null, null);
expect(condition === null).toBe(true);
});
it('should return condition when found by tokenKey and value', () => {
const conditions = gl.FilteredSearchTokenKeysWithWeights.getConditions();
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByConditionKeyValue(conditions[0].tokenKey, conditions[0].value);
expect(result).toEqual(conditions[0]);
});
it('should return weight condition when found by weight tokenKey and value', () => {
const conditions = gl.FilteredSearchTokenKeysWithWeights.getConditions();
const weightConditions = conditions.filter(c => c.tokenKey === 'weight');
const result = gl.FilteredSearchTokenKeysWithWeights
.searchByConditionKeyValue(weightConditions[0].tokenKey, weightConditions[0].value);
expect(result).toEqual(weightConditions[0]);
});
});
});
})();
spec/javascripts/search_autocomplete_spec.js
View file @
389dd2af
...
...
@@ -89,8 +89,8 @@ require('vendor/fuzzaldrin-plus');
var
a1
,
a2
,
a3
,
a4
,
issuesAssignedToMeLink
,
issuesIHaveCreatedLink
,
mrsAssignedToMeLink
,
mrsIHaveCreatedLink
;
issuesAssignedToMeLink
=
issuesPath
+
"
/?assignee_username=
"
+
userName
;
issuesIHaveCreatedLink
=
issuesPath
+
"
/?author_username=
"
+
userName
;
mrsAssignedToMeLink
=
mrsPath
+
"
/?assignee_
id=
"
+
userId
;
mrsIHaveCreatedLink
=
mrsPath
+
"
/?author_
id=
"
+
userId
;
mrsAssignedToMeLink
=
mrsPath
+
"
/?assignee_
username=
"
+
userName
;
mrsIHaveCreatedLink
=
mrsPath
+
"
/?author_
username=
"
+
userName
;
a1
=
"
a[href='
"
+
issuesAssignedToMeLink
+
"
']
"
;
a2
=
"
a[href='
"
+
issuesIHaveCreatedLink
+
"
']
"
;
a3
=
"
a[href='
"
+
mrsAssignedToMeLink
+
"
']
"
;
...
...
spec/support/filtered_search_helpers.rb
0 → 100644
View file @
389dd2af
module
FilteredSearchHelpers
def
filtered_search
page
.
find
(
'.filtered-search'
)
end
def
input_filtered_search
(
search_term
,
submit:
true
)
filtered_search
.
set
(
search_term
)
if
submit
filtered_search
.
send_keys
(
:enter
)
end
end
def
input_filtered_search_keys
(
search_term
)
filtered_search
.
send_keys
(
search_term
)
filtered_search
.
send_keys
(
:enter
)
end
def
expect_filtered_search_input
(
input
)
expect
(
find
(
'.filtered-search'
).
value
).
to
eq
(
input
)
end
def
clear_search_field
find
(
'.filtered-search-input-container .clear-search'
).
click
end
def
reset_filters
clear_search_field
filtered_search
.
send_keys
(
:enter
)
end
def
init_label_search
filtered_search
.
set
(
'label:'
)
# This ensures the dropdown is shown
expect
(
find
(
'#js-dropdown-label'
)).
not_to
have_css
(
'.filter-dropdown-loading'
)
end
end
spec/support/merge_request_helpers.rb
View file @
389dd2af
...
...
@@ -10,4 +10,13 @@ module MergeRequestHelpers
def
last_merge_request
page
.
all
(
'ul.mr-list > li'
).
last
.
text
end
def
expect_mr_list_count
(
open_count
,
closed_count
=
0
)
all_count
=
open_count
+
closed_count
expect
(
page
).
to
have_issuable_counts
(
open:
open_count
,
closed:
closed_count
,
all:
all_count
)
page
.
within
'.mr-list'
do
expect
(
page
).
to
have_selector
(
'.merge-request'
,
count:
open_count
)
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment