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
e197f27f
Commit
e197f27f
authored
Dec 17, 2016
by
Clement Ho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor and use regex for string processing
parent
0e40c952
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
189 additions
and
536 deletions
+189
-536
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
+21
-37
app/assets/javascripts/filtered_search/dropdown_user.js.es6
app/assets/javascripts/filtered_search/dropdown_user.js.es6
+3
-6
app/assets/javascripts/filtered_search/dropdown_utils.js.es6
app/assets/javascripts/filtered_search/dropdown_utils.js.es6
+16
-14
app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
...vascripts/filtered_search/filtered_search_dropdown.js.es6
+1
-1
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
...s/filtered_search/filtered_search_dropdown_manager.js.es6
+20
-14
app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
...avascripts/filtered_search/filtered_search_manager.js.es6
+3
-11
app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
...ascripts/filtered_search/filtered_search_tokenizer.js.es6
+26
-152
spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
+5
-20
spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6
...tered_search/filtered_search_dropdown_manager_spec.js.es6
+1
-21
spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6
...pts/filtered_search/filtered_search_tokenizer_spec.js.es6
+93
-260
No files found.
app/assets/javascripts/filtered_search/dropdown_hint.js.es6
View file @
e197f27f
...
...
@@ -3,31 +3,13 @@
/* global droplabFilter */
(() => {
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>',
}];
class DropdownHint extends gl.FilteredSearchDropdown {
constructor(droplab, dropdown, input) {
super(droplab, dropdown, input);
this.config = {
droplabFilter: {
template: 'hint',
filterFunction: gl.DropdownUtils.filter
Method
,
filterFunction: gl.DropdownUtils.filter
Hint
,
},
};
}
...
...
@@ -43,8 +25,7 @@
const tag = selected.querySelector('.js-filter-tag').innerText.trim();
if (tag.length) {
gl.FilteredSearchDropdownManager
.addWordToInput(this.getSelectedTextWithoutEscaping(token));
gl.FilteredSearchDropdownManager.addWordToInput(token);
}
this.dismissDropdown();
this.dispatchInputEvent();
...
...
@@ -52,24 +33,27 @@
}
}
getSelectedTextWithoutEscaping(selectedToken) {
const lastWord = this.input.value.split(' ').last();
const lastWordIndex = selectedToken.indexOf(lastWord);
return lastWordIndex === -1 ? selectedToken : selectedToken.slice(lastWord.length);
}
renderContent() {
this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config);
// Clone dropdownData to prevent it from being
// changed due to pass by reference
const data = [];
dropdownData.forEach((item) => {
data.push(Object.assign({}, item));
});
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>',
}];
this.droplab.setData(this.hookId, data);
this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config);
this.droplab.setData(this.hookId, dropdownData);
}
init() {
...
...
app/assets/javascripts/filtered_search/dropdown_user.js.es6
View file @
e197f27f
...
...
@@ -37,13 +37,10 @@
}
getSearchInput() {
const query = this.input.value;
const { value } = gl.FilteredSearchTokenizer.getLastTokenObject(query);
const valueWithoutColon = value.slice(1);
const hasPrefix = valueWithoutColon[0] === '@';
const valueWithoutPrefix = valueWithoutColon.slice(1);
const query = this.input.value.trim();
const { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
return
hasPrefix ? valueWithoutPrefix : valueWithoutColon
;
return
lastToken.value || ''
;
}
init() {
...
...
app/assets/javascripts/filtered_search/dropdown_utils.js.es6
View file @
e197f27f
...
...
@@ -22,30 +22,32 @@
static filterWithSymbol(filterSymbol, item, query) {
const updatedItem = item;
const { value } = gl.FilteredSearchTokenizer.getLastTokenObject(query);
const valueWithoutColon = value.slice(1).toLowerCase();
const prefix = valueWithoutColon[0];
const valueWithoutPrefix = valueWithoutColon.slice(1);
const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(query);
const title = updatedItem.title.toLowerCase();
if (lastToken !== searchToken) {
const value = lastToken.value.toLowerCase();
const title = updatedItem.title.toLowerCase();
// Eg. filterSymbol = ~ for labels
const matchWithoutPrefix =
prefix === filterSymbol && title.indexOf(valueWithoutPrefix) !== -1;
const match = title.indexOf(valueWithoutColon) !== -1;
// Eg. filterSymbol = ~ for labels
const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
const match = title.indexOf(`${lastToken.symbol}${value}`) !== -1;
updatedItem.droplab_hidden = !match && !matchWithoutSymbol;
} else {
updatedItem.droplab_hidden = false;
}
updatedItem.droplab_hidden = !match && !matchWithoutPrefix;
return updatedItem;
}
static filter
Method
(item, query) {
static filter
Hint
(item, query) {
const updatedItem = item;
const {
value } = gl.FilteredSearchTokenizer.getLastTokenObject
(query);
const {
lastToken } = gl.FilteredSearchTokenizer.processTokens
(query);
if (
value === ''
) {
if (
!lastToken
) {
updatedItem.droplab_hidden = false;
} else {
updatedItem.droplab_hidden = updatedItem.hint.indexOf(
value
) === -1;
updatedItem.droplab_hidden = updatedItem.hint.indexOf(
lastToken.toLowerCase()
) === -1;
}
return updatedItem;
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
View file @
e197f27f
...
...
@@ -29,7 +29,7 @@
itemClicked(e, getValueFunction) {
const { selected } = e.detail;
if (selected.tagName === 'LI') {
if (selected.tagName === 'LI'
&& selected.innerHTML
) {
const dataValueSet = gl.DropdownUtils.setDataValueIfSelected(selected);
if (!dataValueSet) {
...
...
app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
View file @
e197f27f
...
...
@@ -57,17 +57,25 @@
static addWordToInput(word, addSpace = false) {
const input = document.querySelector('.filtered-search');
input.value = input.value.trim();
const value = input.value;
const hasExistingValue = value.length !== 0;
const { lastToken } = gl.FilteredSearchTokenizer.processTokens(value);
const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(value);
// Find out what part of the token value the user has typed
// and remove it from input before appending the selected token value
if (lastToken !== searchToken) {
const lastTokenString = `${lastToken.symbol}${lastToken.value}`;
if ({}.hasOwnProperty.call(lastToken, 'key')) {
// Spaces inside the token means that the token value will be escaped by quotes
const hasQuotes = lastToken
.value
.indexOf(' ') !== -1;
const hasQuotes = lastToken
String
.indexOf(' ') !== -1;
// Add 2 length to account for the length of the front and back quotes
const lengthToRemove = hasQuotes ? lastToken
.value.length + 2 : lastToken.value
.length;
const lengthToRemove = hasQuotes ? lastToken
String.length + 2 : lastTokenString
.length;
input.value = value.slice(0, -1 * (lengthToRemove));
} else if (searchToken !== '' && word.indexOf(searchToken) !== -1) {
input.value = value.slice(0, -1 * searchToken.length);
}
input.value += hasExistingValue && addSpace ? ` ${word}` : word;
...
...
@@ -129,27 +137,25 @@
const match = gl.FilteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key
&&
{}.hasOwnProperty.call(this.mapping, match.key)
;
&&
this.mapping[match.key]
;
const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint';
if (shouldOpenFilterDropdown || shouldOpenHintDropdown) {
// `hint` is not listed as a tokenKey (since it is not a real `filter`)
const key = match && {}.hasOwnProperty.call(match, 'key') ? match.key : 'hint';
const key = match && match.key ? match.key : 'hint';
this.load(key, firstLoad);
}
gl.droplab = this.droplab;
}
setDropdown() {
const { lastToken } = this.tokenizer.processTokens(this.filteredSearchInput.value);
const { lastToken, searchToken } = this.tokenizer
.processTokens(this.filteredSearchInput.value);
if (
typeof lastToken === 'string'
) {
if (
lastToken === searchToken
) {
// Token is not fully initialized yet because it has no value
// Eg. token = 'label:'
const
{ tokenKey } = this.tokenizer.parseToken(lastToken
);
this.loadDropdown(
tokenKey
);
} else if (
{}.hasOwnProperty.call(lastToken, 'key')
) {
const
split = lastToken.split(':'
);
this.loadDropdown(
split.length > 1 ? split[0] : ''
);
} else if (
lastToken
) {
// Token has been initialized into an object because it has a value
this.loadDropdown(lastToken.key);
} else {
...
...
app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
View file @
e197f27f
...
...
@@ -136,21 +136,13 @@
const condition = gl.FilteredSearchTokenKeys
.searchByConditionKeyValue(token.key, token.value.toLowerCase());
const { param } = gl.FilteredSearchTokenKeys.searchByKey(token.key);
const keyParam = param ? `${token.key}_${param}` : token.key;
let tokenPath = '';
let keyParam = token.key;
if (param) {
keyParam += `_${param}`;
}
if (token.wildcard && condition) {
if (condition) {
tokenPath = condition.url;
} else if (token.wildcard) {
// wildcard means that the token does not have a symbol
tokenPath = `${keyParam}=${encodeURIComponent(token.value)}`;
} else {
// Remove the token symbol
tokenPath = `${keyParam}=${encodeURIComponent(token.value.slice(1))}`;
tokenPath = `${keyParam}=${encodeURIComponent(token.value)}`;
}
paths.push(tokenPath);
...
...
app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
View file @
e197f27f
(() => {
class FilteredSearchTokenizer {
static parseToken(input) {
const colonIndex = input.indexOf(':');
let tokenKey;
let tokenValue;
let tokenSymbol;
if (colonIndex !== -1) {
tokenKey = input.slice(0, colonIndex).toLowerCase();
tokenValue = input.slice(colonIndex + 1);
tokenSymbol = tokenValue[0];
}
return {
tokenKey,
tokenValue,
tokenSymbol,
};
}
static getLastTokenObject(input) {
const token = FilteredSearchTokenizer.getLastToken(input);
const colonIndex = token.indexOf(':');
const key = colonIndex !== -1 ? token.slice(0, colonIndex) : '';
const value = colonIndex !== -1 ? token.slice(colonIndex) : token;
return {
key,
value,
};
}
static getLastToken(input) {
let completeToken = false;
let completeQuotation = true;
let lastQuotation = '';
let i = input.length;
const doubleQuote = '"';
const singleQuote = '\'';
while (!completeToken && i >= 0) {
const isDoubleQuote = input[i] === doubleQuote;
const isSingleQuote = input[i] === singleQuote;
// If the second quotation is found
if ((lastQuotation === doubleQuote && isDoubleQuote) ||
(lastQuotation === singleQuote && isSingleQuote)) {
completeQuotation = true;
}
// Save the first quotation
if ((isDoubleQuote && lastQuotation === '') ||
(isSingleQuote && lastQuotation === '')) {
lastQuotation = input[i];
completeQuotation = false;
}
if (completeQuotation && input[i] === ' ') {
completeToken = true;
} else {
i -= 1;
}
}
// Adjust by 1 because of empty space
return input.slice(i + 1);
}
static processTokens(input) {
const tokenRegex = /(\w+):([~%@]?)(?:"(.*?)"|'(.*?)'|(\S+))/g;
const tokens = [];
let searchToken = '';
let lastToken = '';
const inputs = input.split(' ');
let searchTerms = '';
let lastQuotation = '';
let incompleteToken = false;
// Iterate through each word (broken up by spaces)
inputs.forEach((i) => {
if (incompleteToken) {
// Continue previous token as it had an escaped
// quote in the beginning
const prevToken = tokens.last();
prevToken.value += ` ${i}`;
// Remove last quotation from the value
const lastQuotationRegex = new RegExp(lastQuotation, 'g');
prevToken.value = prevToken.value.replace(lastQuotationRegex, '');
tokens[tokens.length - 1] = prevToken;
// Check to see if this quotation completes the token value
if (i.indexOf(lastQuotation) !== -1) {
lastToken = tokens.last();
incompleteToken = !incompleteToken;
}
return;
}
const colonIndex = i.indexOf(':');
if (colonIndex !== -1) {
const { tokenKey, tokenValue, tokenSymbol } = gl.FilteredSearchTokenizer.parseToken(i);
const keyMatch = gl.FilteredSearchTokenKeys.searchByKey(tokenKey);
const symbolMatch = gl.FilteredSearchTokenKeys.searchBySymbol(tokenSymbol);
const doubleQuoteOccurrences = tokenValue.split('"').length - 1;
const singleQuoteOccurrences = tokenValue.split('\'').length - 1;
const doubleQuoteIndex = tokenValue.indexOf('"');
const singleQuoteIndex = tokenValue.indexOf('\'');
const doubleQuoteExist = doubleQuoteIndex !== -1;
const singleQuoteExist = singleQuoteIndex !== -1;
const doubleQuoteExistOnly = doubleQuoteExist && !singleQuoteExist;
const doubleQuoteIsBeforeSingleQuote =
doubleQuoteExist && singleQuoteExist && doubleQuoteIndex < singleQuoteIndex;
const singleQuoteExistOnly = singleQuoteExist && !doubleQuoteExist;
const singleQuoteIsBeforeDoubleQuote =
doubleQuoteExist && singleQuoteExist && singleQuoteIndex < doubleQuoteIndex;
if ((doubleQuoteExistOnly || doubleQuoteIsBeforeSingleQuote)
&& doubleQuoteOccurrences % 2 !== 0) {
// " is found and is in front of ' (if any)
lastQuotation = '"';
incompleteToken = true;
} else if ((singleQuoteExistOnly || singleQuoteIsBeforeDoubleQuote)
&& singleQuoteOccurrences % 2 !== 0) {
// ' is found and is in front of " (if any)
lastQuotation = '\'';
incompleteToken = true;
}
if (keyMatch && tokenValue.length > 0) {
tokens.push({
key: keyMatch.key,
value: tokenValue,
wildcard: !symbolMatch,
});
lastToken = tokens.last();
return;
}
let lastToken = null;
const searchToken = input.replace(tokenRegex, (match, key, symbol, v1, v2, v3) => {
let tokenValue = v1 || v2 || v3;
let tokenSymbol = symbol;
if (tokenValue === '~' || tokenValue === '%' || tokenValue === '@') {
tokenSymbol = tokenValue;
tokenValue = '';
}
// Add space for next term
searchTerms += `${i} `;
lastToken = i;
}, this);
searchToken = searchTerms.trim();
tokens.push({
key,
value: tokenValue || '',
symbol: tokenSymbol || '',
});
return '';
}).replace(/\s{2,}/g, ' ').trim() || '';
if (tokens.length > 0) {
const last = tokens[tokens.length - 1];
const lastString = `${last.key}:${last.symbol}${last.value}`;
lastToken = input.lastIndexOf(lastString) ===
input.length - lastString.length ? last : searchToken;
} else {
lastToken = searchToken;
}
return {
tokens,
searchToken,
lastToken,
searchToken,
};
}
}
...
...
spec/javascripts/filtered_search/dropdown_utils_spec.js.es6
View file @
e197f27f
...
...
@@ -34,11 +34,6 @@
title: '@root',
};
beforeEach(() => {
spyOn(gl.FilteredSearchTokenizer, 'getLastTokenObject')
.and.callFake(query => ({ value: query }));
});
it('should filter without symbol', () => {
const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':roo');
expect(updatedItem.droplab_hidden).toBe(false);
...
...
@@ -49,37 +44,27 @@
expect(updatedItem.droplab_hidden).toBe(false);
});
it('should filter with invalid symbol', () => {
const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':#');
expect(updatedItem.droplab_hidden).toBe(true);
});
it('should filter with colon', () => {
const updatedItem = gl.DropdownUtils.filterWithSymbol('@', item, ':');
expect(updatedItem.droplab_hidden).toBe(false);
});
});
describe('filterMethod', () => {
beforeEach(() => {
spyOn(gl.FilteredSearchTokenizer, 'getLastTokenObject')
.and.callFake(query => ({ value: query }));
});
it('should filter by hint', () => {
let updatedItem = gl.DropdownUtils.filterMethod({
describe('filterHint', () => {
it('should filter', () => {
let updatedItem = gl.DropdownUtils.filterHint({
hint: 'label',
}, 'l');
expect(updatedItem.droplab_hidden).toBe(false);
updatedItem = gl.DropdownUtils.filter
Method
({
updatedItem = gl.DropdownUtils.filter
Hint
({
hint: 'label',
}, 'o');
expect(updatedItem.droplab_hidden).toBe(true);
});
it('should return droplab_hidden false when item has no hint', () => {
const updatedItem = gl.DropdownUtils.filter
Method
({}, '');
const updatedItem = gl.DropdownUtils.filter
Hint
({}, '');
expect(updatedItem.droplab_hidden).toBe(false);
});
});
...
...
spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6
View file @
e197f27f
...
...
@@ -21,13 +21,6 @@
});
describe('input has no existing value', () => {
beforeEach(() => {
spyOn(gl.FilteredSearchTokenizer, 'processTokens')
.and.callFake(() => ({
lastToken: {},
}));
});
it('should add word', () => {
gl.FilteredSearchDropdownManager.addWordToInput('firstWord');
expect(getInputValue()).toBe('firstWord');
...
...
@@ -61,26 +54,13 @@
value: 'roo',
};
spyOn(gl.FilteredSearchTokenizer, 'processTokens').and.callFake(() => ({
lastToken,
}));
document.querySelector('.filtered-search').value = `${lastToken.key}:${lastToken.value}`;
gl.FilteredSearchDropdownManager.addWordToInput('root');
expect(getInputValue()).toBe('author:root');
});
it('should only add the remaining characters of the word (contains space)', () => {
const lastToken = {
key: 'label',
value: 'test me',
};
spyOn(gl.FilteredSearchTokenizer, 'processTokens').and.callFake(() => ({
lastToken,
}));
document.querySelector('.filtered-search').value = `${lastToken.key}:"${lastToken.value}"`;
document.querySelector('.filtered-search').value = 'label:~"test';
gl.FilteredSearchDropdownManager.addWordToInput('~\'"test me"\'');
expect(getInputValue()).toBe('label:~\'"test me"\'');
});
...
...
spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6
View file @
e197f27f
...
...
@@ -4,267 +4,100 @@
(() => {
describe('Filtered Search Tokenizer', () => {
describe('parseToken', () => {
it('should return key, value and symbol', () => {
const { tokenKey, tokenValue, tokenSymbol } = gl.FilteredSearchTokenizer
.parseToken('author:@user');
expect(tokenKey).toBe('author');
expect(tokenValue).toBe('@user');
expect(tokenSymbol).toBe('@');
});
it('should return value with spaces', () => {
const { tokenKey, tokenValue, tokenSymbol } = gl.FilteredSearchTokenizer
.parseToken('label:~"test me"');
expect(tokenKey).toBe('label');
expect(tokenValue).toBe('~"test me"');
expect(tokenSymbol).toBe('~');
});
});
describe('getLastTokenObject', () => {
beforeEach(() => {
spyOn(gl.FilteredSearchTokenizer, 'getLastToken').and.callFake(input => input);
});
it('should return key and value', () => {
const { key, value } = gl.FilteredSearchTokenizer.getLastTokenObject('author:@root');
expect(key).toBe('author');
expect(value).toBe(':@root');
});
describe('string without colon', () => {
let lastTokenObject;
beforeEach(() => {
lastTokenObject = gl.FilteredSearchTokenizer.getLastTokenObject('author');
});
it('should return key as an empty string', () => {
expect(lastTokenObject.key).toBe('');
});
it('should return input as value', () => {
expect(lastTokenObject.value).toBe('author');
});
});
});
describe('getLastToken', () => {
it('returns entire string when there is only one word', () => {
const lastToken = gl.FilteredSearchTokenizer.getLastToken('input');
expect(lastToken).toBe('input');
});
it('returns last word when there are multiple words', () => {
const lastToken = gl.FilteredSearchTokenizer.getLastToken('this is a few words');
expect(lastToken).toBe('words');
});
it('returns last token when there are multiple tokens', () => {
const lastToken = gl.FilteredSearchTokenizer
.getLastToken('label:fun author:root milestone:2.0');
expect(lastToken).toBe('milestone:2.0');
});
it('returns last token containing spaces escaped by double quotes', () => {
const lastToken = gl.FilteredSearchTokenizer
.getLastToken('label:fun author:root milestone:2.0 label:~"Feature Proposal"');
expect(lastToken).toBe('label:~"Feature Proposal"');
});
it('returns last token containing spaces escaped by single quotes', () => {
const lastToken = gl.FilteredSearchTokenizer
.getLastToken('label:fun author:root milestone:2.0 label:~\'Feature Proposal\'');
expect(lastToken).toBe('label:~\'Feature Proposal\'');
});
it('returns last token containing special characters', () => {
const lastToken = gl.FilteredSearchTokenizer
.getLastToken('label:fun author:root milestone:2.0 label:~!@#$%^&*()');
expect(lastToken).toBe('label:~!@#$%^&*()');
});
});
describe('processTokens', () => {
describe('input does not contain any tokens', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer.processTokens('searchTerm');
});
it('returns input as searchToken', () => {
expect(results.searchToken).toBe('searchTerm');
});
it('returns tokens as an empty array', () => {
expect(results.tokens.length).toBe(0);
});
it('returns lastToken equal to searchToken', () => {
expect(results.lastToken).toBe(results.searchToken);
});
});
describe('input contains only tokens', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer
.processTokens('author:@root label:~"Very Important" milestone:%v1.0 assignee:none');
});
it('returns searchToken as an empty string', () => {
expect(results.searchToken).toBe('');
});
it('returns tokens array of size equal to the number of tokens in input', () => {
expect(results.tokens.length).toBe(4);
});
it('returns tokens array that matches the tokens found in input', () => {
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('@root');
expect(results.tokens[0].wildcard).toBe(false);
expect(results.tokens[1].key).toBe('label');
expect(results.tokens[1].value).toBe('~Very Important');
expect(results.tokens[1].wildcard).toBe(false);
expect(results.tokens[2].key).toBe('milestone');
expect(results.tokens[2].value).toBe('%v1.0');
expect(results.tokens[2].wildcard).toBe(false);
expect(results.tokens[3].key).toBe('assignee');
expect(results.tokens[3].value).toBe('none');
expect(results.tokens[3].wildcard).toBe(true);
});
it('returns lastToken equal to the last object in the tokens array', () => {
expect(results.tokens[3]).toBe(results.lastToken);
});
});
describe('input starts with search value and ends with tokens', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer
.processTokens('searchTerm anotherSearchTerm milestone:none');
});
it('returns searchToken', () => {
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
});
it('returns correct number of tokens', () => {
expect(results.tokens.length).toBe(1);
});
it('returns correct tokens', () => {
expect(results.tokens[0].key).toBe('milestone');
expect(results.tokens[0].value).toBe('none');
expect(results.tokens[0].wildcard).toBe(true);
});
it('returns lastToken', () => {
expect(results.tokens[0]).toBe(results.lastToken);
});
});
describe('input starts with token and ends with search value', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer
.processTokens('assignee:@user searchTerm');
});
it('returns searchToken', () => {
expect(results.searchToken).toBe('searchTerm');
});
it('returns correct number of tokens', () => {
expect(results.tokens.length).toBe(1);
});
it('returns correct tokens', () => {
expect(results.tokens[0].key).toBe('assignee');
expect(results.tokens[0].value).toBe('@user');
expect(results.tokens[0].wildcard).toBe(false);
});
it('returns lastToken as the searchTerm', () => {
expect(results.lastToken).toBe(results.searchToken);
});
});
describe('input contains search value wrapped between tokens', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer
.processTokens('author:@root label:~"Won\'t fix" searchTerm anotherSearchTerm milestone:none');
});
it('returns searchToken', () => {
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
});
it('returns correct number of tokens', () => {
expect(results.tokens.length).toBe(3);
});
it('returns tokens array in the order it was processed', () => {
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('@root');
expect(results.tokens[0].wildcard).toBe(false);
expect(results.tokens[1].key).toBe('label');
expect(results.tokens[1].value).toBe('~Won\'t fix');
expect(results.tokens[1].wildcard).toBe(false);
expect(results.tokens[2].key).toBe('milestone');
expect(results.tokens[2].value).toBe('none');
expect(results.tokens[2].wildcard).toBe(true);
});
it('returns lastToken', () => {
expect(results.tokens[2]).toBe(results.lastToken);
});
});
describe('input search value is spaced in between tokens', () => {
let results;
beforeEach(() => {
results = gl.FilteredSearchTokenizer
.processTokens('author:@root searchTerm assignee:none anotherSearchTerm label:~Doing');
});
it('returns searchToken', () => {
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
});
it('returns correct number of tokens', () => {
expect(results.tokens.length).toBe(3);
});
it('returns tokens array in the order it was processed', () => {
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('@root');
expect(results.tokens[0].wildcard).toBe(false);
expect(results.tokens[1].key).toBe('assignee');
expect(results.tokens[1].value).toBe('none');
expect(results.tokens[1].wildcard).toBe(true);
expect(results.tokens[2].key).toBe('label');
expect(results.tokens[2].value).toBe('~Doing');
expect(results.tokens[2].wildcard).toBe(false);
});
it('returns lastToken', () => {
expect(results.tokens[2]).toBe(results.lastToken);
});
it('returns for input containing only search value', () => {
const results = gl.FilteredSearchTokenizer.processTokens('searchTerm');
expect(results.searchToken).toBe('searchTerm');
expect(results.tokens.length).toBe(0);
expect(results.lastToken).toBe(results.searchToken);
});
it('returns for input containing only tokens', () => {
const results = gl.FilteredSearchTokenizer
.processTokens('author:@root label:~"Very Important" milestone:%v1.0 assignee:none');
expect(results.searchToken).toBe('');
expect(results.tokens.length).toBe(4);
expect(results.tokens[3]).toBe(results.lastToken);
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('root');
expect(results.tokens[0].symbol).toBe('@');
expect(results.tokens[1].key).toBe('label');
expect(results.tokens[1].value).toBe('Very Important');
expect(results.tokens[1].symbol).toBe('~');
expect(results.tokens[2].key).toBe('milestone');
expect(results.tokens[2].value).toBe('v1.0');
expect(results.tokens[2].symbol).toBe('%');
expect(results.tokens[3].key).toBe('assignee');
expect(results.tokens[3].value).toBe('none');
expect(results.tokens[3].symbol).toBe('');
});
it('returns for input starting with search value and ending with tokens', () => {
const results = gl.FilteredSearchTokenizer
.processTokens('searchTerm anotherSearchTerm milestone:none');
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
expect(results.tokens.length).toBe(1);
expect(results.tokens[0]).toBe(results.lastToken);
expect(results.tokens[0].key).toBe('milestone');
expect(results.tokens[0].value).toBe('none');
expect(results.tokens[0].symbol).toBe('');
});
it('returns for input starting with tokens and ending with search value', () => {
const results = gl.FilteredSearchTokenizer
.processTokens('assignee:@user searchTerm');
expect(results.searchToken).toBe('searchTerm');
expect(results.tokens.length).toBe(1);
expect(results.tokens[0].key).toBe('assignee');
expect(results.tokens[0].value).toBe('user');
expect(results.tokens[0].symbol).toBe('@');
expect(results.lastToken).toBe(results.searchToken);
});
it('returns for input containing search value wrapped between tokens', () => {
const results = gl.FilteredSearchTokenizer
.processTokens('author:@root label:~"Won\'t fix" searchTerm anotherSearchTerm milestone:none');
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
expect(results.tokens.length).toBe(3);
expect(results.tokens[2]).toBe(results.lastToken);
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('root');
expect(results.tokens[0].symbol).toBe('@');
expect(results.tokens[1].key).toBe('label');
expect(results.tokens[1].value).toBe('Won\'t fix');
expect(results.tokens[1].symbol).toBe('~');
expect(results.tokens[2].key).toBe('milestone');
expect(results.tokens[2].value).toBe('none');
expect(results.tokens[2].symbol).toBe('');
});
it('returns for input containing search value in between tokens', () => {
const results = gl.FilteredSearchTokenizer
.processTokens('author:@root searchTerm assignee:none anotherSearchTerm label:~Doing');
expect(results.searchToken).toBe('searchTerm anotherSearchTerm');
expect(results.tokens.length).toBe(3);
expect(results.tokens[2]).toBe(results.lastToken);
expect(results.tokens[0].key).toBe('author');
expect(results.tokens[0].value).toBe('root');
expect(results.tokens[0].symbol).toBe('@');
expect(results.tokens[1].key).toBe('assignee');
expect(results.tokens[1].value).toBe('none');
expect(results.tokens[1].symbol).toBe('');
expect(results.tokens[2].key).toBe('label');
expect(results.tokens[2].value).toBe('Doing');
expect(results.tokens[2].symbol).toBe('~');
});
});
});
...
...
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