Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorTim Zallmann <tzallmann@gitlab.com>2017-06-02 19:40:57 +0300
committerTim Zallmann <tzallmann@gitlab.com>2017-06-02 19:40:57 +0300
commit51c196160adfbdb723fa6295cddf74a5ce033d6b (patch)
tree12734e5ca046497e7676079230eb2123c434fd6e /spec
parentb1f860818fd1db049ae44f4e9ea1aef93e1e2ea1 (diff)
parent0583916d2d9ad19ae342a13ff2a31c9e3bb76547 (diff)
Merge branch 'winh-styled-people-search-bar' into 'master'
Style people in issuable search bar Closes #30468 See merge request !11402
Diffstat (limited to 'spec')
-rw-r--r--spec/features/boards/modal_filter_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb4
-rw-r--r--spec/javascripts/filtered_search/dropdown_utils_spec.js29
-rw-r--r--spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js406
-rw-r--r--spec/javascripts/fixtures/issues.rb11
-rw-r--r--spec/javascripts/helpers/filtered_search_spec_helper.js13
7 files changed, 342 insertions, 127 deletions
diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb
index ce132bfd979..b6de6143354 100644
--- a/spec/features/boards/modal_filter_spec.rb
+++ b/spec/features/boards/modal_filter_spec.rb
@@ -89,7 +89,7 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
page.within('.add-issues-modal') do
wait_for_requests
- expect(page).to have_selector('.js-visual-token', text: user2.username)
+ expect(page).to have_selector('.js-visual-token', text: user2.name)
expect(page).to have_selector('.card', count: 1)
end
end
@@ -125,7 +125,7 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
page.within('.add-issues-modal') do
wait_for_requests
- expect(page).to have_selector('.js-visual-token', text: user2.username)
+ expect(page).to have_selector('.js-visual-token', text: user2.name)
expect(page).to have_selector('.card', count: 1)
end
end
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 7958ad7e24f..e5e4ba06b5a 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -6,7 +6,7 @@ describe 'Filter issues', js: true, feature: true do
let!(:group) { create(:group) }
let!(:project) { create(:project, group: group) }
- let!(:user) { create(:user, username: 'joe') }
+ let!(:user) { create(:user, username: 'joe', name: 'Joe') }
let!(:user2) { create(:user, username: 'jane') }
let!(:label) { create(:label, project: project) }
let!(:wontfix) { create(:label, project: project, title: "Won't fix") }
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index 96e87c82d2c..dbbafc9e004 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
describe 'Visual tokens', js: true, feature: true do
include FilteredSearchHelpers
+ include WaitForRequests
let!(:project) { create(:empty_project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
@@ -70,7 +71,8 @@ describe 'Visual tokens', js: true, feature: true do
end
it 'changes value in visual token' do
- expect(first('.tokens-container .filtered-search-token .value').text).to eq("@#{user_rock.username}")
+ wait_for_requests
+ expect(first('.tokens-container .filtered-search-token .value').text).to eq("#{user_rock.name}")
end
it 'moves input to the right' do
diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js
index bb02abdeea2..f55726379f3 100644
--- a/spec/javascripts/filtered_search/dropdown_utils_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js
@@ -2,8 +2,12 @@ import '~/extensions/array';
import '~/filtered_search/dropdown_utils';
import '~/filtered_search/filtered_search_tokenizer';
import '~/filtered_search/filtered_search_dropdown_manager';
+import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper';
describe('Dropdown Utils', () => {
+ const issueListFixture = 'issues/issue_list.html.raw';
+ preloadFixtures(issueListFixture);
+
describe('getEscapedText', () => {
it('should return same word when it has no space', () => {
const escaped = gl.DropdownUtils.getEscapedText('textWithoutSpace');
@@ -314,4 +318,29 @@ describe('Dropdown Utils', () => {
});
});
});
+
+ describe('getSearchQuery', () => {
+ let authorToken;
+
+ beforeEach(() => {
+ loadFixtures(issueListFixture);
+
+ authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '@user');
+ const searchTermToken = FilteredSearchSpecHelper.createSearchVisualToken('search term');
+
+ const tokensContainer = document.querySelector('.tokens-container');
+ tokensContainer.appendChild(searchTermToken);
+ tokensContainer.appendChild(authorToken);
+ });
+
+ it('uses original value if present', () => {
+ const originalValue = 'original dance';
+ const valueContainer = authorToken.querySelector('.value-container');
+ valueContainer.dataset.originalValue = originalValue;
+
+ const searchQuery = gl.DropdownUtils.getSearchQuery();
+
+ expect(searchQuery).toBe(' search term author:original dance');
+ });
+ });
});
diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
index c5fa2b17106..fa4343ffbc8 100644
--- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
@@ -1,10 +1,22 @@
import AjaxCache from '~/lib/utils/ajax_cache';
+import UsersCache from '~/lib/utils/users_cache';
import '~/filtered_search/filtered_search_visual_tokens';
import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper';
describe('Filtered Search Visual Tokens', () => {
+ const subject = gl.FilteredSearchVisualTokens;
+
+ const findElements = (tokenElement) => {
+ const tokenNameElement = tokenElement.querySelector('.name');
+ const tokenValueContainer = tokenElement.querySelector('.value-container');
+ const tokenValueElement = tokenValueContainer.querySelector('.value');
+ return { tokenNameElement, tokenValueContainer, tokenValueElement };
+ };
+
let tokensContainer;
+ let authorToken;
+ let bugLabelToken;
beforeEach(() => {
setFixtures(`
@@ -13,12 +25,15 @@ describe('Filtered Search Visual Tokens', () => {
</ul>
`);
tokensContainer = document.querySelector('.tokens-container');
+
+ authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '@user');
+ bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~bug');
});
describe('getLastVisualTokenBeforeInput', () => {
it('returns when there are no visual tokens', () => {
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
expect(lastVisualToken).toEqual(null);
expect(isLastVisualTokenValid).toEqual(true);
@@ -27,11 +42,11 @@ describe('Filtered Search Visual Tokens', () => {
describe('input is the last item in tokensContainer', () => {
it('returns when there is one visual token', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug'),
+ bugLabelToken.outerHTML,
);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
expect(isLastVisualTokenValid).toEqual(true);
@@ -43,7 +58,7 @@ describe('Filtered Search Visual Tokens', () => {
);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
expect(isLastVisualTokenValid).toEqual(false);
@@ -51,13 +66,13 @@ describe('Filtered Search Visual Tokens', () => {
it('returns when there are multiple visual tokens', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
`);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
const items = document.querySelectorAll('.tokens-container .js-visual-token');
expect(lastVisualToken.isEqualNode(items[items.length - 1])).toEqual(true);
@@ -66,13 +81,13 @@ describe('Filtered Search Visual Tokens', () => {
it('returns when there are multiple visual tokens and an incomplete visual token', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('assignee')}
`);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
const items = document.querySelectorAll('.tokens-container .js-visual-token');
expect(lastVisualToken.isEqualNode(items[items.length - 1])).toEqual(true);
@@ -83,13 +98,13 @@ describe('Filtered Search Visual Tokens', () => {
describe('input is a middle item in tokensContainer', () => {
it('returns last token before input', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createInputHTML()}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('author', '@root')}
`);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
expect(isLastVisualTokenValid).toEqual(true);
@@ -103,7 +118,7 @@ describe('Filtered Search Visual Tokens', () => {
`);
const { lastVisualToken, isLastVisualTokenValid }
- = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ = subject.getLastVisualTokenBeforeInput();
expect(lastVisualToken).toEqual(document.querySelector('.filtered-search-token'));
expect(isLastVisualTokenValid).toEqual(false);
@@ -114,7 +129,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('unselectTokens', () => {
it('does nothing when there are no tokens', () => {
const beforeHTML = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.unselectTokens();
+ subject.unselectTokens();
expect(tokensContainer.innerHTML).toEqual(beforeHTML);
});
@@ -128,7 +143,7 @@ describe('Filtered Search Visual Tokens', () => {
const selected = tokensContainer.querySelector('.js-visual-token .selected');
expect(selected.classList.contains('selected')).toEqual(true);
- gl.FilteredSearchVisualTokens.unselectTokens();
+ subject.unselectTokens();
expect(selected.classList.contains('selected')).toEqual(false);
});
@@ -137,7 +152,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('selectToken', () => {
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~awesome')}
`);
@@ -147,7 +162,7 @@ describe('Filtered Search Visual Tokens', () => {
const firstTokenButton = tokensContainer.querySelector('.js-visual-token .selectable');
firstTokenButton.classList.add('selected');
- gl.FilteredSearchVisualTokens.selectToken(firstTokenButton);
+ subject.selectToken(firstTokenButton);
expect(firstTokenButton.classList.contains('selected')).toEqual(false);
});
@@ -156,7 +171,7 @@ describe('Filtered Search Visual Tokens', () => {
it('adds selected class', () => {
const firstTokenButton = tokensContainer.querySelector('.js-visual-token .selectable');
- gl.FilteredSearchVisualTokens.selectToken(firstTokenButton);
+ subject.selectToken(firstTokenButton);
expect(firstTokenButton.classList.contains('selected')).toEqual(true);
});
@@ -165,7 +180,7 @@ describe('Filtered Search Visual Tokens', () => {
const tokenButtons = tokensContainer.querySelectorAll('.js-visual-token .selectable');
tokenButtons[1].classList.add('selected');
- gl.FilteredSearchVisualTokens.selectToken(tokenButtons[0]);
+ subject.selectToken(tokenButtons[0]);
expect(tokenButtons[0].classList.contains('selected')).toEqual(true);
expect(tokenButtons[1].classList.contains('selected')).toEqual(false);
@@ -181,7 +196,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.removeSelectedToken();
+ subject.removeSelectedToken();
expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
});
@@ -193,7 +208,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokensContainer.querySelector('.js-visual-token .selectable')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.removeSelectedToken();
+ subject.removeSelectedToken();
expect(tokensContainer.querySelector('.js-visual-token .selectable')).toEqual(null);
});
@@ -205,7 +220,7 @@ describe('Filtered Search Visual Tokens', () => {
beforeEach(() => {
setFixtures(`
<div class="test-area">
- ${gl.FilteredSearchVisualTokens.createVisualTokenElementHTML()}
+ ${subject.createVisualTokenElementHTML()}
</div>
`);
@@ -245,7 +260,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('addVisualTokenElement', () => {
it('renders search visual tokens', () => {
- gl.FilteredSearchVisualTokens.addVisualTokenElement('search term', null, true);
+ subject.addVisualTokenElement('search term', null, true);
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-term')).toEqual(true);
@@ -254,7 +269,7 @@ describe('Filtered Search Visual Tokens', () => {
});
it('renders filter visual token name', () => {
- gl.FilteredSearchVisualTokens.addVisualTokenElement('milestone');
+ subject.addVisualTokenElement('milestone');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
@@ -263,7 +278,7 @@ describe('Filtered Search Visual Tokens', () => {
});
it('renders filter visual token name and value', () => {
- gl.FilteredSearchVisualTokens.addVisualTokenElement('label', 'Frontend');
+ subject.addVisualTokenElement('label', 'Frontend');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
@@ -274,7 +289,7 @@ describe('Filtered Search Visual Tokens', () => {
it('inserts visual token before input', () => {
tokensContainer.appendChild(FilteredSearchSpecHelper.createFilterVisualToken('assignee', '@root'));
- gl.FilteredSearchVisualTokens.addVisualTokenElement('label', 'Frontend');
+ subject.addVisualTokenElement('label', 'Frontend');
const tokens = tokensContainer.querySelectorAll('.js-visual-token');
const labelToken = tokens[0];
const assigneeToken = tokens[1];
@@ -296,7 +311,7 @@ describe('Filtered Search Visual Tokens', () => {
);
const original = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.addValueToPreviousVisualTokenElement('value');
+ subject.addValueToPreviousVisualTokenElement('value');
expect(original).toEqual(tokensContainer.innerHTML);
});
@@ -308,7 +323,7 @@ describe('Filtered Search Visual Tokens', () => {
`);
const original = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.addValueToPreviousVisualTokenElement('value');
+ subject.addValueToPreviousVisualTokenElement('value');
expect(original).toEqual(tokensContainer.innerHTML);
});
@@ -319,7 +334,7 @@ describe('Filtered Search Visual Tokens', () => {
);
const original = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.addValueToPreviousVisualTokenElement('value');
+ subject.addValueToPreviousVisualTokenElement('value');
const updatedToken = tokensContainer.querySelector('.js-visual-token');
expect(updatedToken.querySelector('.name').innerText).toEqual('label');
@@ -330,7 +345,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('addFilterVisualToken', () => {
it('creates visual token with just tokenName', () => {
- gl.FilteredSearchVisualTokens.addFilterVisualToken('milestone');
+ subject.addFilterVisualToken('milestone');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
@@ -339,8 +354,8 @@ describe('Filtered Search Visual Tokens', () => {
});
it('creates visual token with just tokenValue', () => {
- gl.FilteredSearchVisualTokens.addFilterVisualToken('milestone');
- gl.FilteredSearchVisualTokens.addFilterVisualToken('%8.17');
+ subject.addFilterVisualToken('milestone');
+ subject.addFilterVisualToken('%8.17');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
@@ -349,7 +364,7 @@ describe('Filtered Search Visual Tokens', () => {
});
it('creates full visual token', () => {
- gl.FilteredSearchVisualTokens.addFilterVisualToken('assignee', '@john');
+ subject.addFilterVisualToken('assignee', '@john');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-token')).toEqual(true);
@@ -360,7 +375,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('addSearchVisualToken', () => {
it('creates search visual token', () => {
- gl.FilteredSearchVisualTokens.addSearchVisualToken('search term');
+ subject.addSearchVisualToken('search term');
const token = tokensContainer.querySelector('.js-visual-token');
expect(token.classList.contains('filtered-search-term')).toEqual(true);
@@ -374,7 +389,7 @@ describe('Filtered Search Visual Tokens', () => {
${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search term')}
`);
- gl.FilteredSearchVisualTokens.addSearchVisualToken('append this');
+ subject.addSearchVisualToken('append this');
const token = tokensContainer.querySelector('.filtered-search-term');
expect(token.querySelector('.name').innerText).toEqual('search term append this');
@@ -386,10 +401,26 @@ describe('Filtered Search Visual Tokens', () => {
it('should get last token value', () => {
const value = '~bug';
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
- FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', value),
+ bugLabelToken.outerHTML,
+ );
+
+ expect(subject.getLastTokenPartial()).toEqual(value);
+ });
+
+ it('should get last token original value if available', () => {
+ const originalValue = '@user';
+ const valueContainer = authorToken.querySelector('.value-container');
+ valueContainer.dataset.originalValue = originalValue;
+ const avatar = document.createElement('img');
+ const valueElement = valueContainer.querySelector('.value');
+ valueElement.insertAdjacentElement('afterbegin', avatar);
+ tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
+ authorToken.outerHTML,
);
- expect(gl.FilteredSearchVisualTokens.getLastTokenPartial()).toEqual(value);
+ const lastTokenValue = subject.getLastTokenPartial();
+
+ expect(lastTokenValue).toEqual(originalValue);
});
it('should get last token name if there is no value', () => {
@@ -398,11 +429,11 @@ describe('Filtered Search Visual Tokens', () => {
FilteredSearchSpecHelper.createNameFilterVisualTokenHTML(name),
);
- expect(gl.FilteredSearchVisualTokens.getLastTokenPartial()).toEqual(name);
+ expect(subject.getLastTokenPartial()).toEqual(name);
});
it('should return empty when there are no tokens', () => {
- expect(gl.FilteredSearchVisualTokens.getLastTokenPartial()).toEqual('');
+ expect(subject.getLastTokenPartial()).toEqual('');
});
});
@@ -414,7 +445,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokensContainer.querySelector('.js-visual-token .value')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.removeLastTokenPartial();
+ subject.removeLastTokenPartial();
expect(tokensContainer.querySelector('.js-visual-token .value')).toEqual(null);
});
@@ -426,14 +457,14 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokensContainer.querySelector('.js-visual-token .name')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.removeLastTokenPartial();
+ subject.removeLastTokenPartial();
expect(tokensContainer.querySelector('.js-visual-token .name')).toEqual(null);
});
it('should not remove anything when there are no tokens', () => {
const html = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.removeLastTokenPartial();
+ subject.removeLastTokenPartial();
expect(tokensContainer.innerHTML).toEqual(html);
});
@@ -442,7 +473,7 @@ describe('Filtered Search Visual Tokens', () => {
describe('tokenizeInput', () => {
it('does not do anything if there is no input', () => {
const original = tokensContainer.innerHTML;
- gl.FilteredSearchVisualTokens.tokenizeInput();
+ subject.tokenizeInput();
expect(tokensContainer.innerHTML).toEqual(original);
});
@@ -454,7 +485,7 @@ describe('Filtered Search Visual Tokens', () => {
const input = document.querySelector('.filtered-search');
input.value = 'some value';
- gl.FilteredSearchVisualTokens.tokenizeInput();
+ subject.tokenizeInput();
const newToken = tokensContainer.querySelector('.filtered-search-term');
@@ -470,7 +501,7 @@ describe('Filtered Search Visual Tokens', () => {
const input = document.querySelector('.filtered-search');
input.value = '@john';
- gl.FilteredSearchVisualTokens.tokenizeInput();
+ subject.tokenizeInput();
const updatedToken = tokensContainer.querySelector('.filtered-search-token');
@@ -497,29 +528,39 @@ describe('Filtered Search Visual Tokens', () => {
it('tokenize\'s existing input', () => {
input.value = 'some text';
- spyOn(gl.FilteredSearchVisualTokens, 'tokenizeInput').and.callThrough();
+ spyOn(subject, 'tokenizeInput').and.callThrough();
- gl.FilteredSearchVisualTokens.editToken(token);
+ subject.editToken(token);
- expect(gl.FilteredSearchVisualTokens.tokenizeInput).toHaveBeenCalled();
+ expect(subject.tokenizeInput).toHaveBeenCalled();
expect(input.value).not.toEqual('some text');
});
it('moves input to the token position', () => {
expect(tokensContainer.children[3].querySelector('.filtered-search')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.editToken(token);
+ subject.editToken(token);
expect(tokensContainer.children[1].querySelector('.filtered-search')).not.toEqual(null);
expect(tokensContainer.children[3].querySelector('.filtered-search')).toEqual(null);
});
it('input contains the visual token value', () => {
- gl.FilteredSearchVisualTokens.editToken(token);
+ subject.editToken(token);
expect(input.value).toEqual('none');
});
+ it('input contains the original value if present', () => {
+ const originalValue = '@user';
+ const valueContainer = token.querySelector('.value-container');
+ valueContainer.dataset.originalValue = originalValue;
+
+ subject.editToken(token);
+
+ expect(input.value).toEqual(originalValue);
+ });
+
describe('selected token is a search term token', () => {
beforeEach(() => {
token = document.querySelector('.filtered-search-term');
@@ -528,7 +569,7 @@ describe('Filtered Search Visual Tokens', () => {
it('token is removed', () => {
expect(tokensContainer.querySelector('.filtered-search-term')).not.toEqual(null);
- gl.FilteredSearchVisualTokens.editToken(token);
+ subject.editToken(token);
expect(tokensContainer.querySelector('.filtered-search-term')).toEqual(null);
});
@@ -536,7 +577,7 @@ describe('Filtered Search Visual Tokens', () => {
it('input has the same value as removed token', () => {
expect(input.value).toEqual('');
- gl.FilteredSearchVisualTokens.editToken(token);
+ subject.editToken(token);
expect(input.value).toEqual('search');
});
@@ -549,25 +590,25 @@ describe('Filtered Search Visual Tokens', () => {
FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none'),
);
- spyOn(gl.FilteredSearchVisualTokens, 'tokenizeInput').and.callFake(() => {});
- spyOn(gl.FilteredSearchVisualTokens, 'getLastVisualTokenBeforeInput').and.callThrough();
+ spyOn(subject, 'tokenizeInput').and.callFake(() => {});
+ spyOn(subject, 'getLastVisualTokenBeforeInput').and.callThrough();
- gl.FilteredSearchVisualTokens.moveInputToTheRight();
+ subject.moveInputToTheRight();
- expect(gl.FilteredSearchVisualTokens.tokenizeInput).toHaveBeenCalled();
- expect(gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput).not.toHaveBeenCalled();
+ expect(subject.tokenizeInput).toHaveBeenCalled();
+ expect(subject.getLastVisualTokenBeforeInput).not.toHaveBeenCalled();
});
it('tokenize\'s input', () => {
tokensContainer.innerHTML = `
${FilteredSearchSpecHelper.createNameFilterVisualTokenHTML('label')}
${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
`;
document.querySelector('.filtered-search').value = 'none';
- gl.FilteredSearchVisualTokens.moveInputToTheRight();
+ subject.moveInputToTheRight();
const value = tokensContainer.querySelector('.js-visual-token .value');
expect(value.innerText).toEqual('none');
@@ -577,12 +618,12 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = `
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
`;
document.querySelector('.filtered-search').value = 'test';
- gl.FilteredSearchVisualTokens.moveInputToTheRight();
+ subject.moveInputToTheRight();
const searchValue = tokensContainer.querySelector('.filtered-search-term .name');
expect(searchValue.innerText).toEqual('test');
@@ -592,10 +633,10 @@ describe('Filtered Search Visual Tokens', () => {
tokensContainer.innerHTML = `
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
${FilteredSearchSpecHelper.createInputHTML()}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '~bug')}
+ ${bugLabelToken.outerHTML}
`;
- gl.FilteredSearchVisualTokens.moveInputToTheRight();
+ subject.moveInputToTheRight();
expect(tokensContainer.children[2].querySelector('.filtered-search')).not.toEqual(null);
});
@@ -607,7 +648,7 @@ describe('Filtered Search Visual Tokens', () => {
${FilteredSearchSpecHelper.createInputHTML('', '~bug')}
`;
- gl.FilteredSearchVisualTokens.moveInputToTheRight();
+ subject.moveInputToTheRight();
const token = tokensContainer.children[1];
expect(token.querySelector('.value').innerText).toEqual('~bug');
@@ -615,42 +656,144 @@ describe('Filtered Search Visual Tokens', () => {
});
describe('renderVisualTokenValue', () => {
- let searchTokens;
+ const keywordToken = FilteredSearchSpecHelper.createFilterVisualToken('search');
+ const milestoneToken = FilteredSearchSpecHelper.createFilterVisualToken('milestone', 'upcoming');
+
+ let updateLabelTokenColorSpy;
+ let updateUserTokenAppearanceSpy;
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', 'none')}
- ${FilteredSearchSpecHelper.createSearchVisualTokenHTML('search')}
- ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'upcoming')}
+ ${authorToken.outerHTML}
+ ${bugLabelToken.outerHTML}
+ ${keywordToken.outerHTML}
+ ${milestoneToken.outerHTML}
`);
- searchTokens = document.querySelectorAll('.filtered-search-token');
+ spyOn(subject, 'updateLabelTokenColor');
+ updateLabelTokenColorSpy = subject.updateLabelTokenColor;
+
+ spyOn(subject, 'updateUserTokenAppearance');
+ updateUserTokenAppearanceSpy = subject.updateUserTokenAppearance;
});
- it('renders a token value element', () => {
- spyOn(gl.FilteredSearchVisualTokens, 'updateLabelTokenColor');
- const updateLabelTokenColorSpy = gl.FilteredSearchVisualTokens.updateLabelTokenColor;
+ it('renders a author token value element', () => {
+ const { tokenNameElement, tokenValueContainer, tokenValueElement } =
+ findElements(authorToken);
+ const tokenName = tokenNameElement.innerText;
+ const tokenValue = 'new value';
- expect(searchTokens.length).toBe(2);
- Array.prototype.forEach.call(searchTokens, (token) => {
- updateLabelTokenColorSpy.calls.reset();
+ subject.renderVisualTokenValue(authorToken, tokenName, tokenValue);
- const tokenName = token.querySelector('.name').innerText;
- const tokenValue = 'new value';
- gl.FilteredSearchVisualTokens.renderVisualTokenValue(token, tokenName, tokenValue);
+ expect(tokenValueElement.innerText).toBe(tokenValue);
+ expect(updateUserTokenAppearanceSpy.calls.count()).toBe(1);
+ const expectedArgs = [tokenValueContainer, tokenValueElement, tokenValue];
+ expect(updateUserTokenAppearanceSpy.calls.argsFor(0)).toEqual(expectedArgs);
+ expect(updateLabelTokenColorSpy.calls.count()).toBe(0);
+ });
- const tokenValueElement = token.querySelector('.value');
- expect(tokenValueElement.innerText).toBe(tokenValue);
+ it('renders a label token value element', () => {
+ const { tokenNameElement, tokenValueContainer, tokenValueElement } =
+ findElements(bugLabelToken);
+ const tokenName = tokenNameElement.innerText;
+ const tokenValue = 'new value';
- if (tokenName.toLowerCase() === 'label') {
- const tokenValueContainer = token.querySelector('.value-container');
- expect(updateLabelTokenColorSpy.calls.count()).toBe(1);
- const expectedArgs = [tokenValueContainer, tokenValue];
- expect(updateLabelTokenColorSpy.calls.argsFor(0)).toEqual(expectedArgs);
- } else {
- expect(updateLabelTokenColorSpy.calls.count()).toBe(0);
- }
- });
+ subject.renderVisualTokenValue(bugLabelToken, tokenName, tokenValue);
+
+ expect(tokenValueElement.innerText).toBe(tokenValue);
+ expect(updateLabelTokenColorSpy.calls.count()).toBe(1);
+ const expectedArgs = [tokenValueContainer, tokenValue];
+ expect(updateLabelTokenColorSpy.calls.argsFor(0)).toEqual(expectedArgs);
+ expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0);
+ });
+
+ it('renders a milestone token value element', () => {
+ const { tokenNameElement, tokenValueElement } = findElements(milestoneToken);
+ const tokenName = tokenNameElement.innerText;
+ const tokenValue = 'new value';
+
+ subject.renderVisualTokenValue(milestoneToken, tokenName, tokenValue);
+
+ expect(tokenValueElement.innerText).toBe(tokenValue);
+ expect(updateLabelTokenColorSpy.calls.count()).toBe(0);
+ expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0);
+ });
+ });
+
+ describe('updateUserTokenAppearance', () => {
+ let usersCacheSpy;
+
+ beforeEach(() => {
+ spyOn(UsersCache, 'retrieve').and.callFake(username => usersCacheSpy(username));
+ });
+
+ it('ignores special value "none"', (done) => {
+ usersCacheSpy = (username) => {
+ expect(username).toBe('none');
+ done.fail('Should not resolve "none"!');
+ };
+ const { tokenValueContainer, tokenValueElement } = findElements(authorToken);
+
+ subject.updateUserTokenAppearance(tokenValueContainer, tokenValueElement, 'none')
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('ignores error if UsersCache throws', (done) => {
+ spyOn(window, 'Flash');
+ const dummyError = new Error('Earth rotated backwards');
+ const { tokenValueContainer, tokenValueElement } = findElements(authorToken);
+ const tokenValue = tokenValueElement.innerText;
+ usersCacheSpy = (username) => {
+ expect(`@${username}`).toBe(tokenValue);
+ return Promise.reject(dummyError);
+ };
+
+ subject.updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue)
+ .then(() => {
+ expect(window.Flash.calls.count()).toBe(0);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does nothing if user cannot be found', (done) => {
+ const { tokenValueContainer, tokenValueElement } = findElements(authorToken);
+ const tokenValue = tokenValueElement.innerText;
+ usersCacheSpy = (username) => {
+ expect(`@${username}`).toBe(tokenValue);
+ return Promise.resolve(undefined);
+ };
+
+ subject.updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue)
+ .then(() => {
+ expect(tokenValueElement.innerText).toBe(tokenValue);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('replaces author token with avatar and display name', (done) => {
+ const dummyUser = {
+ name: 'Important Person',
+ avatar_url: 'https://host.invalid/mypics/avatar.png',
+ };
+ const { tokenValueContainer, tokenValueElement } = findElements(authorToken);
+ const tokenValue = tokenValueElement.innerText;
+ usersCacheSpy = (username) => {
+ expect(`@${username}`).toBe(tokenValue);
+ return Promise.resolve(dummyUser);
+ };
+
+ subject.updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue)
+ .then(() => {
+ expect(tokenValueContainer.dataset.originalValue).toBe(tokenValue);
+ expect(tokenValueElement.innerText.trim()).toBe(dummyUser.name);
+ const avatar = tokenValueElement.querySelector('img.avatar');
+ expect(avatar.src).toBe(dummyUser.avatar_url);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
@@ -659,21 +802,16 @@ describe('Filtered Search Visual Tokens', () => {
const dummyEndpoint = '/dummy/endpoint';
preloadFixtures(jsonFixtureName);
- const labelData = getJSONFixture(jsonFixtureName);
- const findLabel = tokenValue => labelData.find(
- label => tokenValue === `~${gl.DropdownUtils.getEscapedText(label.title)}`,
- );
- const bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~bug');
+ let labelData;
+
+ beforeAll(() => {
+ labelData = getJSONFixture(jsonFixtureName);
+ });
+
const missingLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~doesnotexist');
const spaceLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '~"some space"');
- const parseColor = (color) => {
- const dummyElement = document.createElement('div');
- dummyElement.style.color = color;
- return dummyElement.style.color;
- };
-
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${bugLabelToken.outerHTML}
@@ -688,28 +826,60 @@ describe('Filtered Search Visual Tokens', () => {
AjaxCache.internalStorage[`${dummyEndpoint}/labels.json`] = labelData;
});
- const testCase = (token, done) => {
- const tokenValueContainer = token.querySelector('.value-container');
- const tokenValue = token.querySelector('.value').innerText;
- const label = findLabel(tokenValue);
+ const parseColor = (color) => {
+ const dummyElement = document.createElement('div');
+ dummyElement.style.color = color;
+ return dummyElement.style.color;
+ };
- gl.FilteredSearchVisualTokens.updateLabelTokenColor(tokenValueContainer, tokenValue)
- .then(() => {
- if (label) {
- expect(tokenValueContainer.getAttribute('style')).not.toBe(null);
- expect(tokenValueContainer.style.backgroundColor).toBe(parseColor(label.color));
- expect(tokenValueContainer.style.color).toBe(parseColor(label.text_color));
- } else {
- expect(token).toBe(missingLabelToken);
- expect(tokenValueContainer.getAttribute('style')).toBe(null);
- }
- })
- .then(done)
- .catch(fail);
+ const expectValueContainerStyle = (tokenValueContainer, label) => {
+ expect(tokenValueContainer.getAttribute('style')).not.toBe(null);
+ expect(tokenValueContainer.style.backgroundColor).toBe(parseColor(label.color));
+ expect(tokenValueContainer.style.color).toBe(parseColor(label.text_color));
};
- it('updates the color of a label token', done => testCase(bugLabelToken, done));
- it('updates the color of a label token with spaces', done => testCase(spaceLabelToken, done));
- it('does not change color of a missing label', done => testCase(missingLabelToken, done));
+ const findLabel = tokenValue => labelData.find(
+ label => tokenValue === `~${gl.DropdownUtils.getEscapedText(label.title)}`,
+ );
+
+ it('updates the color of a label token', (done) => {
+ const { tokenValueContainer, tokenValueElement } = findElements(bugLabelToken);
+ const tokenValue = tokenValueElement.innerText;
+ const matchingLabel = findLabel(tokenValue);
+
+ subject.updateLabelTokenColor(tokenValueContainer, tokenValue)
+ .then(() => {
+ expectValueContainerStyle(tokenValueContainer, matchingLabel);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('updates the color of a label token with spaces', (done) => {
+ const { tokenValueContainer, tokenValueElement } = findElements(spaceLabelToken);
+ const tokenValue = tokenValueElement.innerText;
+ const matchingLabel = findLabel(tokenValue);
+
+ subject.updateLabelTokenColor(tokenValueContainer, tokenValue)
+ .then(() => {
+ expectValueContainerStyle(tokenValueContainer, matchingLabel);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does not change color of a missing label', (done) => {
+ const { tokenValueContainer, tokenValueElement } = findElements(missingLabelToken);
+ const tokenValue = tokenValueElement.innerText;
+ const matchingLabel = findLabel(tokenValue);
+ expect(matchingLabel).toBe(undefined);
+
+ subject.updateLabelTokenColor(tokenValueContainer, tokenValue)
+ .then(() => {
+ expect(tokenValueContainer.getAttribute('style')).toBe(null);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
});
});
diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb
index 88e3f860809..1a30909977e 100644
--- a/spec/javascripts/fixtures/issues.rb
+++ b/spec/javascripts/fixtures/issues.rb
@@ -36,6 +36,17 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller
render_issue(example.description, issue)
end
+ it 'issues/issue_list.html.raw' do |example|
+ create(:issue, project: project)
+
+ get :index,
+ namespace_id: project.namespace.to_param,
+ project_id: project
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+
private
def render_issue(fixture_file_name, issue)
diff --git a/spec/javascripts/helpers/filtered_search_spec_helper.js b/spec/javascripts/helpers/filtered_search_spec_helper.js
index 0d7092a2357..8933dd5def4 100644
--- a/spec/javascripts/helpers/filtered_search_spec_helper.js
+++ b/spec/javascripts/helpers/filtered_search_spec_helper.js
@@ -30,12 +30,15 @@ export default class FilteredSearchSpecHelper {
`;
}
+ static createSearchVisualToken(name) {
+ const li = document.createElement('li');
+ li.classList.add('js-visual-token', 'filtered-search-term');
+ li.innerHTML = `<div class="name">${name}</div>`;
+ return li;
+ }
+
static createSearchVisualTokenHTML(name) {
- return `
- <li class="js-visual-token filtered-search-term">
- <div class="name">${name}</div>
- </li>
- `;
+ return FilteredSearchSpecHelper.createSearchVisualToken(name).outerHTML;
}
static createInputHTML(placeholder = '', value = '') {