2017-02-03 04:58:45 -05:00
|
|
|
|
/* eslint no-param-reassign: "off" */
|
|
|
|
|
|
2018-03-09 15:18:59 -05:00
|
|
|
|
import $ from 'jquery';
|
2017-05-16 14:42:06 -04:00
|
|
|
|
import GfmAutoComplete from '~/gfm_auto_complete';
|
|
|
|
|
|
2017-05-16 17:01:51 -04:00
|
|
|
|
import 'vendor/jquery.caret';
|
|
|
|
|
import 'vendor/jquery.atwho';
|
2017-01-18 07:17:24 -05:00
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
describe('GfmAutoComplete', function() {
|
2017-05-16 14:42:06 -04:00
|
|
|
|
const gfmAutoCompleteCallbacks = GfmAutoComplete.prototype.getDefaultCallbacks.call({
|
|
|
|
|
fetchData: () => {},
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
describe('DefaultOptions.sorter', function() {
|
|
|
|
|
describe('assets loading', function() {
|
|
|
|
|
beforeEach(function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
spyOn(GfmAutoComplete, 'isLoading').and.returnValue(true);
|
|
|
|
|
|
|
|
|
|
this.atwhoInstance = { setting: {} };
|
|
|
|
|
this.items = [];
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
this.sorterValue = gfmAutoCompleteCallbacks.sorter.call(this.atwhoInstance, '', this.items);
|
2017-01-18 07:17:24 -05:00
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should disable highlightFirst', function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
expect(this.atwhoInstance.setting.highlightFirst).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should return the passed unfiltered items', function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
expect(this.sorterValue).toEqual(this.items);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
describe('assets finished loading', function() {
|
|
|
|
|
beforeEach(function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
spyOn(GfmAutoComplete, 'isLoading').and.returnValue(false);
|
|
|
|
|
spyOn($.fn.atwho.default.callbacks, 'sorter');
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should enable highlightFirst if alwaysHighlightFirst is set', function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
const atwhoInstance = { setting: { alwaysHighlightFirst: true } };
|
|
|
|
|
|
2017-05-16 14:42:06 -04:00
|
|
|
|
gfmAutoCompleteCallbacks.sorter.call(atwhoInstance);
|
2017-01-18 07:17:24 -05:00
|
|
|
|
|
|
|
|
|
expect(atwhoInstance.setting.highlightFirst).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should enable highlightFirst if a query is present', function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
const atwhoInstance = { setting: {} };
|
|
|
|
|
|
2017-05-16 14:42:06 -04:00
|
|
|
|
gfmAutoCompleteCallbacks.sorter.call(atwhoInstance, 'query');
|
2017-01-18 07:17:24 -05:00
|
|
|
|
|
|
|
|
|
expect(atwhoInstance.setting.highlightFirst).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should call the default atwho sorter', function() {
|
2017-01-18 07:17:24 -05:00
|
|
|
|
const atwhoInstance = { setting: {} };
|
|
|
|
|
|
|
|
|
|
const query = 'query';
|
|
|
|
|
const items = [];
|
|
|
|
|
const searchKey = 'searchKey';
|
|
|
|
|
|
2017-05-16 14:42:06 -04:00
|
|
|
|
gfmAutoCompleteCallbacks.sorter.call(atwhoInstance, query, items, searchKey);
|
2017-01-18 07:17:24 -05:00
|
|
|
|
|
|
|
|
|
expect($.fn.atwho.default.callbacks.sorter).toHaveBeenCalledWith(query, items, searchKey);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2017-01-20 12:38:06 -05:00
|
|
|
|
|
2017-11-13 09:30:22 -05:00
|
|
|
|
describe('DefaultOptions.beforeInsert', () => {
|
2018-10-17 03:13:26 -04:00
|
|
|
|
const beforeInsert = (context, value) =>
|
|
|
|
|
gfmAutoCompleteCallbacks.beforeInsert.call(context, value);
|
2017-11-13 09:30:22 -05:00
|
|
|
|
|
|
|
|
|
const atwhoInstance = { setting: { skipSpecialCharacterTest: false } };
|
|
|
|
|
|
|
|
|
|
it('should not quote if value only contains alphanumeric charecters', () => {
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '@user1')).toBe('@user1');
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~label1')).toBe('~label1');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should quote if value contains any non-alphanumeric characters', () => {
|
2018-03-28 10:45:16 -04:00
|
|
|
|
expect(beforeInsert(atwhoInstance, '~label-20')).toBe('~"label\\-20"');
|
2017-11-13 09:30:22 -05:00
|
|
|
|
expect(beforeInsert(atwhoInstance, '~label 20')).toBe('~"label 20"');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should quote integer labels', () => {
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~1234')).toBe('~"1234"');
|
|
|
|
|
});
|
2018-03-28 10:45:16 -04:00
|
|
|
|
|
|
|
|
|
it('should escape Markdown emphasis characters, except in the first character', () => {
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '@_group')).toEqual('@\\_group');
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~_bug')).toEqual('~\\_bug');
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~a `bug`')).toEqual('~"a \\`bug\\`"');
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~a ~bug')).toEqual('~"a \\~bug"');
|
|
|
|
|
expect(beforeInsert(atwhoInstance, '~a **bug')).toEqual('~"a \\*\\*bug"');
|
|
|
|
|
});
|
2017-11-13 09:30:22 -05:00
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
describe('DefaultOptions.matcher', function() {
|
|
|
|
|
const defaultMatcher = (context, flag, subtext) =>
|
|
|
|
|
gfmAutoCompleteCallbacks.matcher.call(context, flag, subtext);
|
2017-02-03 04:58:45 -05:00
|
|
|
|
|
2018-10-05 05:42:38 -04:00
|
|
|
|
const flagsUseDefaultMatcher = ['@', '#', '!', '~', '%', '$'];
|
2017-02-03 04:58:45 -05:00
|
|
|
|
const otherFlags = ['/', ':'];
|
|
|
|
|
const flags = flagsUseDefaultMatcher.concat(otherFlags);
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
const flagsHash = flags.reduce((hash, el) => {
|
|
|
|
|
hash[el] = null;
|
|
|
|
|
return hash;
|
|
|
|
|
}, {});
|
2017-02-03 04:58:45 -05:00
|
|
|
|
const atwhoInstance = { setting: {}, app: { controllers: flagsHash } };
|
|
|
|
|
|
|
|
|
|
const minLen = 1;
|
|
|
|
|
const maxLen = 20;
|
|
|
|
|
const argumentSize = [minLen, maxLen / 2, maxLen];
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
const allowedSymbols = [
|
|
|
|
|
'',
|
|
|
|
|
'a',
|
|
|
|
|
'n',
|
|
|
|
|
'z',
|
|
|
|
|
'A',
|
|
|
|
|
'Z',
|
|
|
|
|
'N',
|
|
|
|
|
'0',
|
|
|
|
|
'5',
|
|
|
|
|
'9',
|
|
|
|
|
'А',
|
|
|
|
|
'а',
|
|
|
|
|
'Я',
|
|
|
|
|
'я',
|
|
|
|
|
'.',
|
|
|
|
|
"'",
|
|
|
|
|
'+',
|
|
|
|
|
'-',
|
|
|
|
|
'_',
|
|
|
|
|
];
|
2017-02-03 04:58:45 -05:00
|
|
|
|
const jointAllowedSymbols = allowedSymbols.join('');
|
|
|
|
|
|
|
|
|
|
describe('should match regular symbols', () => {
|
2018-10-17 03:13:26 -04:00
|
|
|
|
flagsUseDefaultMatcher.forEach(flag => {
|
|
|
|
|
allowedSymbols.forEach(symbol => {
|
|
|
|
|
argumentSize.forEach(size => {
|
2017-02-03 04:58:45 -05:00
|
|
|
|
const query = new Array(size + 1).join(symbol);
|
|
|
|
|
const subtext = flag + query;
|
|
|
|
|
|
|
|
|
|
it(`matches argument "${flag}" with query "${subtext}"`, () => {
|
|
|
|
|
expect(defaultMatcher(atwhoInstance, flag, subtext)).toBe(query);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it(`matches combination of allowed symbols for flag "${flag}"`, () => {
|
|
|
|
|
const subtext = flag + jointAllowedSymbols;
|
|
|
|
|
|
|
|
|
|
expect(defaultMatcher(atwhoInstance, flag, subtext)).toBe(jointAllowedSymbols);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('should not match special sequences', () => {
|
2018-02-01 05:35:03 -05:00
|
|
|
|
const shouldNotBeFollowedBy = flags.concat(['\x00', '\x10', '\x3f', '\n', ' ']);
|
|
|
|
|
const shouldNotBePrependedBy = ['`'];
|
2017-02-03 04:58:45 -05:00
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
flagsUseDefaultMatcher.forEach(atSign => {
|
|
|
|
|
shouldNotBeFollowedBy.forEach(followedSymbol => {
|
2017-02-03 04:58:45 -05:00
|
|
|
|
const seq = atSign + followedSymbol;
|
2017-12-20 06:39:40 -05:00
|
|
|
|
|
2018-09-11 17:03:05 -04:00
|
|
|
|
it(`should not match ${JSON.stringify(seq)}`, () => {
|
2017-12-20 06:39:40 -05:00
|
|
|
|
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
shouldNotBePrependedBy.forEach(prependedSymbol => {
|
2017-12-20 06:39:40 -05:00
|
|
|
|
const seq = prependedSymbol + atSign;
|
2017-02-03 04:58:45 -05:00
|
|
|
|
|
|
|
|
|
it(`should not match "${seq}"`, () => {
|
|
|
|
|
expect(defaultMatcher(atwhoInstance, atSign, seq)).toBe(null);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
describe('isLoading', function() {
|
|
|
|
|
it('should be true with loading data object item', function() {
|
2017-01-20 12:38:06 -05:00
|
|
|
|
expect(GfmAutoComplete.isLoading({ name: 'loading' })).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should be true with loading data array', function() {
|
2017-01-20 12:38:06 -05:00
|
|
|
|
expect(GfmAutoComplete.isLoading(['loading'])).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should be true with loading data object array', function() {
|
2017-01-20 12:38:06 -05:00
|
|
|
|
expect(GfmAutoComplete.isLoading([{ name: 'loading' }])).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should be false with actual array data', function() {
|
|
|
|
|
expect(
|
|
|
|
|
GfmAutoComplete.isLoading([{ title: 'Foo' }, { title: 'Bar' }, { title: 'Qux' }]),
|
|
|
|
|
).toBe(false);
|
2017-01-20 12:38:06 -05:00
|
|
|
|
});
|
|
|
|
|
|
2018-10-17 03:13:26 -04:00
|
|
|
|
it('should be false with actual data item', function() {
|
2017-01-20 12:38:06 -05:00
|
|
|
|
expect(GfmAutoComplete.isLoading({ title: 'Foo' })).toBe(false);
|
|
|
|
|
});
|
|
|
|
|
});
|
2018-12-21 03:49:44 -05:00
|
|
|
|
|
|
|
|
|
describe('Issues.insertTemplateFunction', function() {
|
|
|
|
|
it('should return default template', function() {
|
|
|
|
|
expect(GfmAutoComplete.Issues.insertTemplateFunction({ id: 5, title: 'Some Issue' })).toBe(
|
|
|
|
|
'${atwho-at}${id}', // eslint-disable-line no-template-curly-in-string
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should return reference when reference is set', function() {
|
|
|
|
|
expect(
|
|
|
|
|
GfmAutoComplete.Issues.insertTemplateFunction({
|
|
|
|
|
id: 5,
|
|
|
|
|
title: 'Some Issue',
|
|
|
|
|
reference: 'grp/proj#5',
|
|
|
|
|
}),
|
|
|
|
|
).toBe('grp/proj#5');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('Issues.templateFunction', function() {
|
|
|
|
|
it('should return html with id and title', function() {
|
|
|
|
|
expect(GfmAutoComplete.Issues.templateFunction({ id: 5, title: 'Some Issue' })).toBe(
|
|
|
|
|
'<li><small>5</small> Some Issue</li>',
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should replace id with reference if reference is set', function() {
|
|
|
|
|
expect(
|
|
|
|
|
GfmAutoComplete.Issues.templateFunction({
|
|
|
|
|
id: 5,
|
|
|
|
|
title: 'Some Issue',
|
|
|
|
|
reference: 'grp/proj#5',
|
|
|
|
|
}),
|
|
|
|
|
).toBe('<li><small>grp/proj#5</small> Some Issue</li>');
|
|
|
|
|
});
|
|
|
|
|
});
|
2017-01-18 07:17:24 -05:00
|
|
|
|
});
|