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
db5fdc2d
Commit
db5fdc2d
authored
Feb 22, 2017
by
Alfredo Sumaran
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'add-filtered-search-to-mr-ee' into 'master'
Add filtered search to MR page See merge request !1243
parents
2792a502
389dd2af
Changes
24
Hide 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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
...
...
@@ -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,18 +93,23 @@
}
hideDropdown() {
this.getCurrentHook().list.hide();
const currentHook = this.getCurrentHook();
if (currentHook) {
currentHook.list.hide();
}
}
resetFilters() {
const hook = this.getCurrentHook();
const data = hook.list.data;
const results = data.map((o) => {
const updated = o;
updated.droplab_hidden = false;
return updated;
});
hook.list.render(results);
if (hook) {
const data = hook.list.data;
const results = data.map((o) => {
const updated = o;
updated.droplab_hidden = false;
return updated;
});
hook.list.render(results);
}
}
}
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
View file @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
(() => {
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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
...
...
@@ -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,19 +82,20 @@
%span
.dropdown-label-box
{
style:
'
background:
{{
color
}}
'
}
%span
.label-title.js-data-value
{{title}}
#js-dropdown-weight
.dropdown-menu
{
'data-dropdown'
=>
true
}
%ul
{
'data-dropdown'
=>
true
}
%li
.filter-dropdown-item
{
'data-value'
=>
'none'
}
%button
.btn.btn-link
No Weight
%li
.filter-dropdown-item
{
'data-value'
=>
'any'
}
%button
.btn.btn-link
Any Weight
%li
.divider
%ul
.filter-dropdown
{
'data-dropdown'
=>
true
}
-
Issue
.
weight_filter_options
.
each
do
|
weight
|
%li
.filter-dropdown-item
{
'data-value'
=>
"#{weight}"
}
%button
.btn.btn-link
=
weight
-
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
No Weight
%li
.filter-dropdown-item
{
'data-value'
=>
'any'
}
%button
.btn.btn-link
Any Weight
%li
.divider
%ul
.filter-dropdown
{
'data-dropdown'
=>
true
}
-
Issue
.
weight_filter_options
.
each
do
|
weight
|
%li
.filter-dropdown-item
{
'data-value'
=>
"#{weight}"
}
%button
.btn.btn-link
=
weight
.pull-right
=
render
'shared/sort_dropdown'
,
type:
local_assigns
[
:type
]
...
...
changelogs/unreleased-ee/add-filtered-search-to-mr-ee.yml
0 → 100644
View file @
db5fdc2d
---
title
:
Add filtered search to MR page
merge_request
:
1243
author
:
features/project/merge_requests.feature
View file @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
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 @
db5fdc2d
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 @
db5fdc2d
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'
page
.
within
'.dropdown-content'
do
expect
(
page
).
not_to
have_content
'enhancement'
expect
(
page
).
to
have_content
'bug'
end
end
end
end
init_label_search
filtered_search
.
send_keys
(
'~bug'
)
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()"
)
page
.
within
'.filter-dropdown'
do
expect
(
page
).
not_to
have_content
'enhancement'
expect
(
page
).
to
have_content
'bug'
end
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 @
db5fdc2d
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 @
db5fdc2d
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
)
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
end
describe
'for assignee from mr#index'
do
before
do
visit
namespace_project_merge_requests_path
(
project
.
namespace
,
project
)
let
(
:search_query
)
{
"assignee:@
#{
user
.
username
}
"
}
find
(
'.js-assignee-search'
).
click
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
)
find
(
'.js-milestone-select'
).
click
let
(
:search_query
)
{
"milestone:%
#{
milestone
.
title
}
"
}
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
find
(
'body'
).
click
input_filtered_search
(
"label:~
\"
#{
wontfix
.
title
}
\"
"
)
expect
(
find
(
'.filtered-labels'
)).
to
have_content
(
wontfix
.
title
)
expect
(
find
(
'.filtered-labels'
)).
to
have_content
(
label
.
title
)
expect
_mr_list_count
(
0
)
expect
_filtered_search_input
(
"label:~
\"
#{
wontfix
.
title
}
\"
"
)
find
(
'.js-label-select'
).
click
wait_for_ajax
input_filtered_search_keys
(
" label:~
#{
label
.
title
}
"
)
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
)
find
(
'.js-assignee-search'
).
click
let
(
:search_query
)
{
"assignee:@
#{
user
.
username
}
label:~
#{
label
.
title
}
"
}
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
...
...
@@ -203,11 +156,11 @@ describe 'Filter merge requests', feature: true do
bug_label
=
create
(
:label
,
project:
project
,
title:
'bug'
)
milestone
=
create
(
:milestone
,
title:
"8"
,
project:
project
)
mr
=
create
(
:merge_request
,
title:
"Bug 2"
,
source_project:
project
,
target_project:
project
,
source_branch:
"bug2"
,
mr
=
create
(
:merge_request
,
title:
"Bug 2"
,
source_project:
project
,
target_project:
project
,
source_branch:
"bug2"
,
milestone:
milestone
,
author:
user
,
assignee:
user
)
...
...
@@ -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 @
db5fdc2d
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!
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let!
(
:bug
)
{
create
(
:label
,
project:
project
,
name:
'bug'
)}
let!
(
:project
)
{
create
(
:project
,
:public
)
}
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
(
: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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
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 @
db5fdc2d
...
...
@@ -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 @
db5fdc2d
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 @
db5fdc2d
...
...
@@ -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