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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-07 21:07:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-07 21:07:33 +0300
commit1bdc6c89c32a7380a81598629b9ad05ba9a2a94f (patch)
tree778f1dc16130b3138ab3b641e664038648046a40 /spec/frontend
parent9a940dabf04df126e7978c0ab4b8770b86dcaaa8 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/content_editor/components/content_editor_spec.js14
-rw-r--r--spec/frontend/content_editor/components/suggestions_dropdown_spec.js188
-rw-r--r--spec/frontend/content_editor/services/__snapshots__/data_source_factory_spec.js.snap256
-rw-r--r--spec/frontend/content_editor/services/autocomplete_mock_data.js967
-rw-r--r--spec/frontend/content_editor/services/data_source_factory_spec.js202
-rw-r--r--spec/frontend/gfm_auto_complete_spec.js8
-rw-r--r--spec/frontend/groups/service/archived_projects_service_spec.js2
7 files changed, 1599 insertions, 38 deletions
diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js
index 816c9458201..bbc0203344c 100644
--- a/spec/frontend/content_editor/components/content_editor_spec.js
+++ b/spec/frontend/content_editor/components/content_editor_spec.js
@@ -1,6 +1,8 @@
import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
import { EditorContent, Editor } from '@tiptap/vue-2';
import { nextTick } from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from 'axios';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ContentEditor from '~/content_editor/components/content_editor.vue';
import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue';
@@ -16,11 +18,10 @@ import waitForPromises from 'helpers/wait_for_promises';
import { KEYDOWN_EVENT } from '~/content_editor/constants';
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
-jest.mock('~/emoji');
-
describe('ContentEditor', () => {
let wrapper;
let renderMarkdown;
+ let mock;
const uploadsPath = '/uploads';
const findEditorElement = () => wrapper.findByTestId('content-editor');
@@ -32,6 +33,7 @@ describe('ContentEditor', () => {
wrapper = shallowMountExtended(ContentEditor, {
propsData: {
renderMarkdown,
+ markdownDocsPath: '/docs/markdown',
uploadsPath,
markdown,
autofocus,
@@ -49,9 +51,17 @@ describe('ContentEditor', () => {
};
beforeEach(() => {
+ mock = new MockAdapter(axios);
+ // ignore /-/emojis requests
+ mock.onGet().reply(200, []);
+
renderMarkdown = jest.fn();
});
+ afterEach(() => {
+ mock.restore();
+ });
+
it('triggers initialized event', () => {
createWrapper();
diff --git a/spec/frontend/content_editor/components/suggestions_dropdown_spec.js b/spec/frontend/content_editor/components/suggestions_dropdown_spec.js
index ee3ad59bf9a..b17a1b5fc11 100644
--- a/spec/frontend/content_editor/components/suggestions_dropdown_spec.js
+++ b/spec/frontend/content_editor/components/suggestions_dropdown_spec.js
@@ -1,5 +1,6 @@
-import { GlAvatarLabeled, GlLoadingIcon } from '@gitlab/ui';
+import { GlAvatar, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import SuggestionsDropdown from '~/content_editor/components/suggestions_dropdown.vue';
@@ -14,11 +15,17 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
command: jest.fn(),
...propsData,
},
+ stubs: ['gl-emoji'],
}),
);
};
- const exampleUser = { username: 'root', avatar_url: 'root_avatar.png', type: 'User' };
+ const exampleUser = {
+ username: 'root',
+ avatar_url: 'root_avatar.png',
+ type: 'User',
+ name: 'Administrator',
+ };
const exampleIssue = { iid: 123, title: 'Test Issue' };
const exampleMergeRequest = { iid: 224, title: 'Test MR' };
const exampleMilestone1 = { iid: 21, title: '13' };
@@ -61,11 +68,14 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
title: 'Project creation QueryRecorder logs',
};
const exampleEmoji = {
- c: 'people',
- e: '😃',
- d: 'smiling face with open mouth',
- u: '6.0',
- name: 'smiley',
+ emoji: {
+ c: 'people',
+ e: '😃',
+ d: 'smiling face with open mouth',
+ u: '6.0',
+ name: 'smiley',
+ },
+ fieldValue: 'smiley',
};
const insertedEmojiProps = {
@@ -95,6 +105,68 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(loading);
});
+ it('selects first item if query is not empty and items are available', async () => {
+ buildWrapper({
+ propsData: {
+ char: '@',
+ nodeType: 'reference',
+ nodeProps: {
+ referenceType: 'member',
+ },
+ items: [exampleUser],
+ query: 'ro',
+ },
+ });
+
+ await nextTick();
+
+ expect(
+ wrapper.findByTestId('content-editor-suggestions-dropdown').find('li').classes(),
+ ).toContain('focused');
+ });
+
+ describe('when query is defined', () => {
+ it.each`
+ nodeType | referenceType | reference | query | expectedHTML
+ ${'reference'} | ${'user'} | ${exampleUser} | ${'r'} | ${'<strong class="gl-text-body!">r</strong>oot'}
+ ${'reference'} | ${'user'} | ${exampleUser} | ${'r'} | ${'Administ<strong class="gl-text-body!">r</strong>ator'}
+ ${'reference'} | ${'issue'} | ${exampleIssue} | ${'test'} | ${'<strong class="gl-text-body!">Test</strong> Issue'}
+ ${'reference'} | ${'issue'} | ${exampleIssue} | ${'12'} | ${'<strong class="gl-text-body!">12</strong>3'}
+ ${'reference'} | ${'merge_request'} | ${exampleMergeRequest} | ${'test'} | ${'<strong class="gl-text-body!">Test</strong> MR'}
+ ${'reference'} | ${'merge_request'} | ${exampleMergeRequest} | ${'22'} | ${'<strong class="gl-text-body!">22</strong>4'}
+ ${'reference'} | ${'epic'} | ${exampleEpic} | ${'rem'} | ${'❓ <strong class="gl-text-body!">Rem</strong>ote Development | Solution validation'}
+ ${'reference'} | ${'epic'} | ${exampleEpic} | ${'88'} | ${'gitlab-org&amp;<strong class="gl-text-body!">88</strong>84'}
+ ${'reference'} | ${'milestone'} | ${exampleMilestone1} | ${'1'} | ${'<strong class="gl-text-body!">1</strong>3'}
+ ${'reference'} | ${'command'} | ${exampleCommand} | ${'due'} | ${'<strong class="gl-text-body!">due</strong>'}
+ ${'reference'} | ${'command'} | ${exampleCommand} | ${'due'} | ${'Set <strong class="gl-text-body!">due</strong> date'}
+ ${'reference'} | ${'label'} | ${exampleLabel1} | ${'c'} | ${'<strong class="gl-text-body!">C</strong>reate'}
+ ${'reference'} | ${'vulnerability'} | ${exampleVulnerability} | ${'network'} | ${'System procs <strong class="gl-text-body!">network</strong> activity'}
+ ${'reference'} | ${'vulnerability'} | ${exampleVulnerability} | ${'85'} | ${'60<strong class="gl-text-body!">85</strong>0147'}
+ ${'reference'} | ${'snippet'} | ${exampleSnippet} | ${'project'} | ${'<strong class="gl-text-body!">Project</strong> creation QueryRecorder logs'}
+ ${'reference'} | ${'snippet'} | ${exampleSnippet} | ${'242'} | ${'<strong class="gl-text-body!">242</strong>0859'}
+ ${'emoji'} | ${'emoji'} | ${exampleEmoji} | ${'sm'} | ${'<strong class="gl-text-body!">sm</strong>iley'}
+ `(
+ 'highlights query as bolded in $referenceType text',
+ ({ nodeType, referenceType, reference, query, expectedHTML }) => {
+ buildWrapper({
+ propsData: {
+ char: '@',
+ nodeType,
+ nodeProps: {
+ referenceType,
+ },
+ items: [reference],
+ query,
+ },
+ });
+
+ expect(wrapper.findByTestId('content-editor-suggestions-dropdown').html()).toContain(
+ expectedHTML,
+ );
+ },
+ );
+ });
+
describe('on item select', () => {
it.each`
nodeType | referenceType | char | reference | insertedText | insertedProps
@@ -146,7 +218,7 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
});
describe('rendering user references', () => {
- it('displays avatar labeled component', () => {
+ it('displays avatar component', () => {
buildWrapper({
propsData: {
char: '@',
@@ -157,13 +229,11 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
},
});
- expect(wrapper.findComponent(GlAvatarLabeled).attributes()).toEqual(
- expect.objectContaining({
- label: exampleUser.username,
- shape: 'circle',
- src: exampleUser.avatar_url,
- }),
- );
+ expect(wrapper.findComponent(GlAvatar).attributes()).toMatchObject({
+ entityname: exampleUser.username,
+ shape: 'circle',
+ src: exampleUser.avatar_url,
+ });
});
describe.each`
@@ -273,20 +343,46 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
it('displays emoji', () => {
const testEmojis = [
{
- c: 'people',
- e: '😄',
- d: 'smiling face with open mouth and smiling eyes',
- u: '6.0',
- name: 'smile',
+ emoji: {
+ c: 'people',
+ e: '😄',
+ d: 'smiling face with open mouth and smiling eyes',
+ u: '6.0',
+ name: 'smile',
+ },
+ fieldValue: 'smile',
+ },
+ {
+ emoji: {
+ c: 'people',
+ e: '😸',
+ d: 'grinning cat face with smiling eyes',
+ u: '6.0',
+ name: 'smile_cat',
+ },
+ fieldValue: 'smile_cat',
+ },
+ {
+ emoji: {
+ c: 'people',
+ e: '😃',
+ d: 'smiling face with open mouth',
+ u: '6.0',
+ name: 'smiley',
+ },
+ fieldValue: 'smiley',
},
{
- c: 'people',
- e: '😸',
- d: 'grinning cat face with smiling eyes',
- u: '6.0',
- name: 'smile_cat',
+ emoji: {
+ c: 'custom',
+ e: null,
+ d: 'party-parrot',
+ u: 'custom',
+ name: 'party-parrot',
+ src: 'https://cultofthepartyparrot.com/parrots/hd/parrot.gif',
+ },
+ fieldValue: 'party-parrot',
},
- { c: 'people', e: '😃', d: 'smiling face with open mouth', u: '6.0', name: 'smiley' },
];
buildWrapper({
@@ -298,11 +394,41 @@ describe('~/content_editor/components/suggestions_dropdown', () => {
},
});
- testEmojis.forEach((testEmoji) => {
- expect(wrapper.text()).toContain(testEmoji.e);
- expect(wrapper.text()).toContain(testEmoji.d);
- expect(wrapper.text()).toContain(testEmoji.name);
- });
+ expect(wrapper.findAllComponents('gl-emoji-stub').at(0).html()).toMatchInlineSnapshot(`
+ <gl-emoji-stub
+ data-name="smile"
+ data-unicode-version="6.0"
+ title="smiling face with open mouth and smiling eyes"
+ >
+ 😄
+ </gl-emoji-stub>
+ `);
+ expect(wrapper.findAllComponents('gl-emoji-stub').at(1).html()).toMatchInlineSnapshot(`
+ <gl-emoji-stub
+ data-name="smile_cat"
+ data-unicode-version="6.0"
+ title="grinning cat face with smiling eyes"
+ >
+ 😸
+ </gl-emoji-stub>
+ `);
+ expect(wrapper.findAllComponents('gl-emoji-stub').at(2).html()).toMatchInlineSnapshot(`
+ <gl-emoji-stub
+ data-name="smiley"
+ data-unicode-version="6.0"
+ title="smiling face with open mouth"
+ >
+ 😃
+ </gl-emoji-stub>
+ `);
+ expect(wrapper.findAllComponents('gl-emoji-stub').at(3).html()).toMatchInlineSnapshot(`
+ <gl-emoji-stub
+ data-fallback-src="https://cultofthepartyparrot.com/parrots/hd/parrot.gif"
+ data-name="party-parrot"
+ data-unicode-version="custom"
+ title="party-parrot"
+ />
+ `);
});
});
});
diff --git a/spec/frontend/content_editor/services/__snapshots__/data_source_factory_spec.js.snap b/spec/frontend/content_editor/services/__snapshots__/data_source_factory_spec.js.snap
new file mode 100644
index 00000000000..2d16c6b1a2f
--- /dev/null
+++ b/spec/frontend/content_editor/services/__snapshots__/data_source_factory_spec.js.snap
@@ -0,0 +1,256 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DataSourceFactory filters items based on command "/assign" for reference type "user" and command 1`] = `
+Array [
+ "florida.schoen",
+ "root",
+ "all",
+ "lakeesha.batz",
+ "laurene_blick",
+ "myrtis",
+ "patty",
+ "Commit451",
+ "flightjs",
+ "gitlab-instance-ade037f9",
+ "gitlab-org",
+ "gnuwget",
+ "h5bp",
+ "jashkenas",
+ "twitter",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/assign_reviewer" for reference type "user" and command 1`] = `
+Array [
+ "florida.schoen",
+ "root",
+ "all",
+ "errol",
+ "evelynn_olson",
+ "Commit451",
+ "flightjs",
+ "gitlab-instance-ade037f9",
+ "gitlab-org",
+ "gnuwget",
+ "h5bp",
+ "jashkenas",
+ "twitter",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/label" for reference type "label" and command 1`] = `
+Array [
+ "Bronce",
+ "Contour",
+ "Corolla",
+ "Cygsync",
+ "Frontier",
+ "Grand Am",
+ "Onesync",
+ "Phone",
+ "Pynefunc",
+ "Trinix",
+ "Trounswood",
+ "group::knowledge",
+ "scoped label",
+ "type::one",
+ "type::two",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/reassign" for reference type "user" and command 1`] = `
+Array [
+ "florida.schoen",
+ "root",
+ "all",
+ "errol",
+ "evelynn_olson",
+ "lakeesha.batz",
+ "laurene_blick",
+ "myrtis",
+ "patty",
+ "Commit451",
+ "flightjs",
+ "gitlab-instance-ade037f9",
+ "gitlab-org",
+ "gnuwget",
+ "h5bp",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/reassign_reviewer" for reference type "user" and command 1`] = `
+Array [
+ "florida.schoen",
+ "root",
+ "all",
+ "errol",
+ "evelynn_olson",
+ "lakeesha.batz",
+ "laurene_blick",
+ "myrtis",
+ "patty",
+ "Commit451",
+ "flightjs",
+ "gitlab-instance-ade037f9",
+ "gitlab-org",
+ "gnuwget",
+ "h5bp",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/relabel" for reference type "label" and command 1`] = `
+Array [
+ "Amsche",
+ "Brioffe",
+ "Bronce",
+ "Bryncefunc",
+ "Contour",
+ "Corolla",
+ "Cygsync",
+ "Frontier",
+ "Ghost",
+ "Grand Am",
+ "Onesync",
+ "Phone",
+ "Pynefunc",
+ "Trinix",
+ "Trounswood",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/unassign" for reference type "user" and command 1`] = `
+Array [
+ "errol",
+ "evelynn_olson",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/unassign_reviewer" for reference type "user" and command 1`] = `
+Array [
+ "lakeesha.batz",
+ "laurene_blick",
+ "myrtis",
+ "patty",
+]
+`;
+
+exports[`DataSourceFactory filters items based on command "/unlabel" for reference type "label" and command 1`] = `
+Array [
+ "Amsche",
+ "Brioffe",
+ "Bryncefunc",
+ "Ghost",
+]
+`;
+
+exports[`DataSourceFactory for reference type "command", searches for "re" correctly 1`] = `
+Array [
+ "relabel",
+ "remove_milestone",
+ "remove_estimate",
+ "remove_time_spent",
+ "relate",
+ "remove_epic",
+ "reassign",
+ "create_merge_request",
+]
+`;
+
+exports[`DataSourceFactory for reference type "epic", searches for "n" correctly 1`] = `
+Array [
+ "Nobis quidem aspernatur reprehenderit sunt ut ipsum tempora sapiente sed iste.",
+ "Minus eius ut omnis quos sunt dicta ex ipsum.",
+ "Quae nostrum possimus rerum aliquam pariatur a eos aut id.",
+ "Dicta incidunt vel dignissimos sint sit esse est quibusdam quidem consequatur.",
+ "Doloremque a quisquam qui culpa numquam doloribus similique iure enim.",
+]
+`;
+
+exports[`DataSourceFactory for reference type "issue", searches for "q" correctly 1`] = `
+Array [
+ "Quasi id et et nihil sint autem.",
+ "Eaque omnis eius quas necessitatibus hic ut et corrupti.",
+ "Aut quisquam magnam eos distinctio incidunt perferendis fugit.",
+ "Dolorem quisquam cupiditate consequatur perspiciatis sequi eligendi ullam.",
+ "Nesciunt quia molestiae in aliquam amet et dolorem.",
+ "Porro tempore qui qui culpa saepe et nam quos.",
+ "Sed sint a est consequatur quae quasi autem debitis alias.",
+ "Molestiae minima maxime optio nihil quam eveniet dolor.",
+ "Et laboriosam aut ratione voluptatem quasi recusandae.",
+ "Et molestiae delectus voluptates velit vero illo aut rerum quo et.",
+]
+`;
+
+exports[`DataSourceFactory for reference type "label", searches for "c" correctly 1`] = `
+Array [
+ "Contour",
+ "Corolla",
+ "Cygsync",
+ "scoped label",
+ "Amsche",
+ "Bronce",
+ "Bryncefunc",
+ "Onesync",
+ "Pynefunc",
+]
+`;
+
+exports[`DataSourceFactory for reference type "merge_request", searches for "n" correctly 1`] = `
+Array [
+ "Blanditiis maxime voluptatem ut pariatur vel autem vero non quod libero.",
+ "Optio nemo qui dolorem sit ipsum qui saepe.",
+ "Draft: Alunny/publish lib",
+ "Draft: Fix event current target",
+ "Draft: Resolve \\"hgvbbvnnb\\"",
+ "Autem eaque et sed provident enim corrupti molestiae.",
+ "Always call registry's trigger method from withRegistration",
+]
+`;
+
+exports[`DataSourceFactory for reference type "milestone", searches for "16" correctly 1`] = `
+Array [
+ "16.7",
+ "16.8",
+ "16.9",
+ "16.10",
+ "16.11",
+ "16.0 (expired)",
+ "16.1 (expired)",
+ "16.2 (expired)",
+ "16.3 (expired)",
+ "16.4 (expired)",
+ "16.5 (expired)",
+ "16.6 (expired)",
+]
+`;
+
+exports[`DataSourceFactory for reference type "snippet", searches for "s" correctly 1`] = `
+Array [
+ "ss",
+ "test snippet",
+ "another test snippet",
+]
+`;
+
+exports[`DataSourceFactory for reference type "user", searches for "r" correctly 1`] = `
+Array [
+ "root",
+ "errol",
+ "lakeesha.batz",
+ "myrtis",
+ "florida.schoen",
+ "laurene_blick",
+ "all",
+ "twitter",
+ "gitlab-org",
+ "evelynn_olson",
+]
+`;
+
+exports[`DataSourceFactory for reference type "vulnerability", searches for "cross" correctly 1`] = `
+Array [
+ "Cross Site Scripting (Persistent)",
+ "Cross Site Scripting (Persistent)",
+ "Cross Site Scripting (Persistent)",
+]
+`;
diff --git a/spec/frontend/content_editor/services/autocomplete_mock_data.js b/spec/frontend/content_editor/services/autocomplete_mock_data.js
new file mode 100644
index 00000000000..c1bf2a6ae5b
--- /dev/null
+++ b/spec/frontend/content_editor/services/autocomplete_mock_data.js
@@ -0,0 +1,967 @@
+export const MOCK_MEMBERS = [
+ {
+ type: 'User',
+ username: 'florida.schoen',
+ name: 'Anglea Durgan',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/ac82b5615d3308ecbcacedad361af8e7?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'root',
+ name: 'Administrator',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ username: 'all',
+ name: 'All Project and Group Members',
+ count: 8,
+ },
+ {
+ type: 'User',
+ username: 'errol',
+ name: "Linnie O'Connell",
+ avatar_url:
+ 'https://www.gravatar.com/avatar/d3d9a468a9884eb217fad5ca5b2b9bd7?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'evelynn_olson',
+ name: 'Dimple Dare',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/bc1e51ee3512c2b4442f51732d655107?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'lakeesha.batz',
+ name: 'Larae Veum',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e5605cb9bbb1a28640d65f25f256e541?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'laurene_blick',
+ name: 'Evelina Murray',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/389768eef61b7b2d125c64ee01c240fb?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'myrtis',
+ name: 'Fernanda Adams',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/719d5569bd31d4a70e350b4205fa2cb5?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'User',
+ username: 'patty',
+ name: 'Emily Toy',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/dca2077b662338808459dc11e70d6688?s=80\u0026d=identicon',
+ availability: null,
+ },
+ {
+ type: 'Group',
+ username: 'Commit451',
+ name: 'Commit451',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'flightjs',
+ name: 'Flightjs',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'gitlab-instance-ade037f9',
+ name: 'GitLab Instance',
+ avatar_url: null,
+ count: 1,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'gitlab-org',
+ name: 'Gitlab Org',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'gnuwget',
+ name: 'Gnuwget',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'h5bp',
+ name: 'H5bp',
+ avatar_url: null,
+ count: 4,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'jashkenas',
+ name: 'Jashkenas',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+ {
+ type: 'Group',
+ username: 'twitter',
+ name: 'Twitter',
+ avatar_url: null,
+ count: 5,
+ mentionsDisabled: null,
+ },
+];
+
+export const MOCK_ASSIGNEES = MOCK_MEMBERS.filter(
+ ({ username }) => username === 'errol' || username === 'evelynn_olson',
+);
+
+export const MOCK_REVIEWERS = MOCK_MEMBERS.filter(
+ ({ username }) =>
+ username === 'lakeesha.batz' ||
+ username === 'laurene_blick' ||
+ username === 'myrtis' ||
+ username === 'patty',
+);
+
+export const MOCK_ISSUES = [
+ {
+ iid: 31,
+ title: 'rdfhdfj',
+ id: null,
+ },
+ {
+ iid: 30,
+ title: 'incident1',
+ id: null,
+ },
+ {
+ iid: 29,
+ title: 'example feature rollout',
+ id: null,
+ },
+ {
+ iid: 28,
+ title: 'sagasg',
+ id: null,
+ },
+ {
+ iid: 26,
+ title: 'Quasi id et et nihil sint autem.',
+ id: null,
+ },
+ {
+ iid: 25,
+ title: 'Dolorem quisquam cupiditate consequatur perspiciatis sequi eligendi ullam.',
+ id: null,
+ },
+ {
+ iid: 24,
+ title: 'Et molestiae delectus voluptates velit vero illo aut rerum quo et.',
+ id: null,
+ },
+ {
+ iid: 23,
+ title: 'Nesciunt quia molestiae in aliquam amet et dolorem.',
+ id: null,
+ },
+ {
+ iid: 22,
+ title: 'Sint asperiores unde vel autem delectus ullam dolor nihil et.',
+ id: null,
+ },
+ {
+ iid: 21,
+ title: 'Eaque omnis eius quas necessitatibus hic ut et corrupti.',
+ id: null,
+ },
+ {
+ iid: 20,
+ title: 'Porro tempore qui qui culpa saepe et nam quos.',
+ id: null,
+ },
+ {
+ iid: 19,
+ title: 'Molestiae minima maxime optio nihil quam eveniet dolor.',
+ id: null,
+ },
+ {
+ iid: 18,
+ title: 'Sed sint a est consequatur quae quasi autem debitis alias.',
+ id: null,
+ },
+ {
+ iid: 6,
+ title: 'Et laboriosam aut ratione voluptatem quasi recusandae.',
+ id: null,
+ },
+ {
+ iid: 2,
+ title: 'Aut quisquam magnam eos distinctio incidunt perferendis fugit.',
+ id: null,
+ },
+];
+
+export const MOCK_EPICS = [
+ {
+ iid: 6,
+ title: 'sgs',
+ reference: 'flightjs\u00266',
+ },
+ {
+ iid: 5,
+ title: 'Doloremque a quisquam qui culpa numquam doloribus similique iure enim.',
+ reference: 'flightjs\u00265',
+ },
+ {
+ iid: 4,
+ title: 'Minus eius ut omnis quos sunt dicta ex ipsum.',
+ reference: 'flightjs\u00264',
+ },
+ {
+ iid: 3,
+ title: 'Quae nostrum possimus rerum aliquam pariatur a eos aut id.',
+ reference: 'flightjs\u00263',
+ },
+ {
+ iid: 2,
+ title: 'Nobis quidem aspernatur reprehenderit sunt ut ipsum tempora sapiente sed iste.',
+ reference: 'flightjs\u00262',
+ },
+ {
+ iid: 1,
+ title: 'Dicta incidunt vel dignissimos sint sit esse est quibusdam quidem consequatur.',
+ reference: 'flightjs\u00261',
+ },
+];
+
+export const MOCK_MERGE_REQUESTS = [
+ {
+ iid: 12,
+ title: "Always call registry's trigger method from withRegistration",
+ id: null,
+ },
+ {
+ iid: 11,
+ title: 'Draft: Alunny/publish lib',
+ id: null,
+ },
+ {
+ iid: 10,
+ title: 'Draft: Resolve "hgvbbvnnb"',
+ id: null,
+ },
+ {
+ iid: 9,
+ title: 'Draft: Fix event current target',
+ id: null,
+ },
+ {
+ iid: 3,
+ title: 'Autem eaque et sed provident enim corrupti molestiae.',
+ id: null,
+ },
+ {
+ iid: 2,
+ title: 'Blanditiis maxime voluptatem ut pariatur vel autem vero non quod libero.',
+ id: null,
+ },
+ {
+ iid: 1,
+ title: 'Optio nemo qui dolorem sit ipsum qui saepe.',
+ id: null,
+ },
+];
+
+export const MOCK_SNIPPETS = [
+ {
+ id: 24,
+ title: 'ss',
+ },
+ {
+ id: 22,
+ title: 'another test snippet',
+ },
+ {
+ id: 21,
+ title: 'test snippet',
+ },
+];
+
+export const MOCK_LABELS = [
+ {
+ title: 'Amsche',
+ color: '#9964cf',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ set: true,
+ },
+ {
+ title: 'Brioffe',
+ color: '#203e13',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ set: true,
+ },
+ {
+ title: 'Bronce',
+ color: '#c0b7f2',
+ type: 'GroupLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'Bryncefunc',
+ color: '#8baa5e',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ set: true,
+ },
+ {
+ title: 'Contour',
+ color: '#8cf3a3',
+ type: 'ProjectLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'Corolla',
+ color: '#0384f3',
+ type: 'ProjectLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'Cygsync',
+ color: '#1308c3',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'Frontier',
+ color: '#85db43',
+ type: 'ProjectLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'Ghost',
+ color: '#df1bc4',
+ type: 'ProjectLabel',
+ textColor: '#FFFFFF',
+ set: true,
+ },
+ {
+ title: 'Grand Am',
+ color: '#a1d7ee',
+ type: 'ProjectLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'Onesync',
+ color: '#a73ba0',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'Phone',
+ color: '#63dceb',
+ type: 'GroupLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'Pynefunc',
+ color: '#974b19',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'Trinix',
+ color: '#2c894f',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'Trounswood',
+ color: '#ad0370',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'group::knowledge',
+ color: '#8fbc8f',
+ type: 'ProjectLabel',
+ textColor: '#1F1E24',
+ },
+ {
+ title: 'scoped label',
+ color: '#6699cc',
+ type: 'GroupLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'type::one',
+ color: '#9400d3',
+ type: 'ProjectLabel',
+ textColor: '#FFFFFF',
+ },
+ {
+ title: 'type::two',
+ color: '#013220',
+ type: 'ProjectLabel',
+ textColor: '#FFFFFF',
+ },
+];
+
+export const MOCK_MILESTONES = [
+ {
+ iid: 65,
+ title: '15.0',
+ due_date: '2022-05-17',
+ id: null,
+ },
+ {
+ iid: 73,
+ title: '15.1',
+ due_date: '2022-06-17',
+ id: null,
+ },
+ {
+ iid: 74,
+ title: '15.2',
+ due_date: '2022-07-17',
+ id: null,
+ },
+ {
+ iid: 75,
+ title: '15.3',
+ due_date: '2022-08-17',
+ id: null,
+ },
+ {
+ iid: 76,
+ title: '15.4',
+ due_date: '2022-09-17',
+ id: null,
+ },
+ {
+ iid: 77,
+ title: '15.5',
+ due_date: '2022-10-17',
+ id: null,
+ },
+ {
+ iid: 81,
+ title: '15.6',
+ due_date: '2022-11-17',
+ id: null,
+ },
+ {
+ iid: 82,
+ title: '15.7',
+ due_date: '2022-12-17',
+ id: null,
+ },
+ {
+ iid: 83,
+ title: '15.8',
+ due_date: '2023-01-17',
+ id: null,
+ },
+ {
+ iid: 84,
+ title: '15.9',
+ due_date: '2023-02-17',
+ id: null,
+ },
+ {
+ iid: 85,
+ title: '15.10',
+ due_date: '2023-03-17',
+ id: null,
+ },
+ {
+ iid: 86,
+ title: '15.11',
+ due_date: '2023-04-17',
+ id: null,
+ },
+ {
+ iid: 80,
+ title: '16.0',
+ due_date: '2023-05-17',
+ id: null,
+ },
+ {
+ iid: 88,
+ title: '16.1',
+ due_date: '2023-06-17',
+ id: null,
+ },
+ {
+ iid: 89,
+ title: '16.2',
+ due_date: '2023-07-17',
+ id: null,
+ },
+ {
+ iid: 90,
+ title: '16.3',
+ due_date: '2023-08-17',
+ id: null,
+ },
+ {
+ iid: 91,
+ title: '16.4',
+ due_date: '2023-09-17',
+ id: null,
+ },
+ {
+ iid: 92,
+ title: '16.5',
+ due_date: '2023-10-17',
+ id: null,
+ },
+ {
+ iid: 93,
+ title: '16.6',
+ due_date: '2023-11-10',
+ id: null,
+ },
+ {
+ iid: 95,
+ title: '16.7',
+ due_date: '2023-12-15',
+ id: null,
+ },
+ {
+ iid: 94,
+ title: '16.8',
+ due_date: '2024-01-12',
+ id: null,
+ },
+ {
+ iid: 96,
+ title: '16.9',
+ due_date: '2024-02-09',
+ id: null,
+ },
+ {
+ iid: 97,
+ title: '16.10',
+ due_date: '2024-03-15',
+ id: null,
+ },
+ {
+ iid: 98,
+ title: '16.11',
+ due_date: '2024-04-12',
+ id: null,
+ },
+ {
+ iid: 87,
+ title: '17.0',
+ due_date: '2024-05-10',
+ id: null,
+ },
+ {
+ iid: 48,
+ title: 'Next 1-3 releases',
+ due_date: null,
+ id: null,
+ },
+ {
+ iid: 24,
+ title: 'Awaiting further demand',
+ due_date: null,
+ id: null,
+ },
+ {
+ iid: 14,
+ title: 'Backlog',
+ due_date: null,
+ id: null,
+ },
+ {
+ iid: 11,
+ title: 'Next 4-7 releases',
+ due_date: null,
+ id: null,
+ },
+ {
+ iid: 10,
+ title: 'Next 3-4 releases',
+ due_date: null,
+ id: null,
+ },
+ {
+ iid: 6,
+ title: 'Next 7-13 releases',
+ due_date: null,
+ id: null,
+ },
+];
+
+export const MOCK_VULNERABILITIES = [
+ {
+ id: 99499903,
+ title: 'Cross Site Scripting (Persistent)',
+ },
+ {
+ id: 99495085,
+ title: 'Possible SQL injection',
+ },
+ {
+ id: 99490610,
+ title: 'GitLab Runner Authentication Token',
+ },
+ {
+ id: 99288920,
+ title: 'Cross Site Scripting (Persistent)',
+ },
+ {
+ id: 99258720,
+ title: 'Cross Site Scripting (Persistent)',
+ },
+];
+
+export const MOCK_COMMANDS = [
+ {
+ name: 'due',
+ aliases: [],
+ description: 'Set due date',
+ warning: '',
+ icon: '',
+ params: ['\u003cin 2 days | this Friday | December 31st\u003e'],
+ },
+ {
+ name: 'duplicate',
+ aliases: [],
+ description: 'Mark this issue as a duplicate of another issue',
+ warning: '',
+ icon: '',
+ params: ['#issue'],
+ },
+ {
+ name: 'clone',
+ aliases: [],
+ description: 'Clone this issue',
+ warning: '',
+ icon: '',
+ params: ['path/to/project [--with_notes]'],
+ },
+ {
+ name: 'move',
+ aliases: [],
+ description: 'Move this issue to another project.',
+ warning: '',
+ icon: '',
+ params: ['path/to/project'],
+ },
+ {
+ name: 'create_merge_request',
+ aliases: [],
+ description: 'Create a merge request',
+ warning: '',
+ icon: '',
+ params: ['\u003cbranch name\u003e'],
+ },
+ {
+ name: 'zoom',
+ aliases: [],
+ description: 'Add Zoom meeting',
+ warning: '',
+ icon: '',
+ params: ['\u003cZoom URL\u003e'],
+ },
+ {
+ name: 'promote_to_incident',
+ aliases: [],
+ description: 'Promote issue to incident',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'close',
+ aliases: [],
+ description: 'Close this issue',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'title',
+ aliases: [],
+ description: 'Change title',
+ warning: '',
+ icon: '',
+ params: ['\u003cNew title\u003e'],
+ },
+ {
+ name: 'label',
+ aliases: ['labels'],
+ description: 'Add labels',
+ warning: '',
+ icon: '',
+ params: ['~label1 ~"label 2"'],
+ },
+ {
+ name: 'unlabel',
+ aliases: ['remove_label'],
+ description: 'Remove all or specific labels',
+ warning: '',
+ icon: '',
+ params: ['~label1 ~"label 2"'],
+ },
+ {
+ name: 'relabel',
+ aliases: [],
+ description: 'Replace all labels',
+ warning: '',
+ icon: '',
+ params: ['~label1 ~"label 2"'],
+ },
+ {
+ name: 'todo',
+ aliases: [],
+ description: 'Add a to do',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'unsubscribe',
+ aliases: [],
+ description: 'Unsubscribe',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'award',
+ aliases: [],
+ description: 'Toggle emoji award',
+ warning: '',
+ icon: '',
+ params: [':emoji:'],
+ },
+ {
+ name: 'shrug',
+ aliases: [],
+ description: 'Append the comment with ¯\\_(ツ)_/¯',
+ warning: '',
+ icon: '',
+ params: ['\u003cComment\u003e'],
+ },
+ {
+ name: 'tableflip',
+ aliases: [],
+ description: 'Append the comment with (╯°□°)╯︵ ┻━┻',
+ warning: '',
+ icon: '',
+ params: ['\u003cComment\u003e'],
+ },
+ {
+ name: 'confidential',
+ aliases: [],
+ description: 'Make issue confidential',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'assign',
+ aliases: [],
+ description: 'Assign',
+ warning: '',
+ icon: '',
+ params: ['@user1 @user2'],
+ },
+ {
+ name: 'unassign',
+ aliases: [],
+ description: 'Remove all or specific assignees',
+ warning: '',
+ icon: '',
+ params: ['@user1 @user2'],
+ },
+ {
+ name: 'milestone',
+ aliases: [],
+ description: 'Set milestone',
+ warning: '',
+ icon: '',
+ params: ['%"milestone"'],
+ },
+ {
+ name: 'remove_milestone',
+ aliases: [],
+ description: 'Remove milestone',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'copy_metadata',
+ aliases: [],
+ description: 'Copy labels and milestone from other issue or merge request in this project',
+ warning: '',
+ icon: '',
+ params: ['#issue | !merge_request'],
+ },
+ {
+ name: 'estimate',
+ aliases: ['estimate_time'],
+ description: 'Set time estimate',
+ warning: '',
+ icon: '',
+ params: ['\u003c1w 3d 2h 14m\u003e'],
+ },
+ {
+ name: 'spend',
+ aliases: ['spent', 'spend_time'],
+ description: 'Add or subtract spent time',
+ warning: '',
+ icon: '',
+ params: ['\u003ctime(1h30m | -1h30m)\u003e \u003cdate(YYYY-MM-DD)\u003e'],
+ },
+ {
+ name: 'remove_estimate',
+ aliases: ['remove_time_estimate'],
+ description: 'Remove time estimate',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'remove_time_spent',
+ aliases: [],
+ description: 'Remove spent time',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'lock',
+ aliases: [],
+ description: 'Lock the discussion',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'cc',
+ aliases: [],
+ description: 'CC',
+ warning: '',
+ icon: '',
+ params: ['@user'],
+ },
+ {
+ name: 'relate',
+ aliases: [],
+ description: 'Mark this issue as related to another issue',
+ warning: '',
+ icon: '',
+ params: ['\u003c#issue | group/project#issue | issue URL\u003e'],
+ },
+ {
+ name: 'unlink',
+ aliases: [],
+ description: 'Remove link with another issue',
+ warning: '',
+ icon: '',
+ params: ['\u003c#issue | group/project#issue | issue URL\u003e'],
+ },
+ {
+ name: 'epic',
+ aliases: [],
+ description: 'Add to epic',
+ warning: '',
+ icon: '',
+ params: ['\u003c\u0026epic | group\u0026epic | Epic URL\u003e'],
+ },
+ {
+ name: 'remove_epic',
+ aliases: [],
+ description: 'Remove from epic',
+ warning: '',
+ icon: '',
+ params: [],
+ },
+ {
+ name: 'promote',
+ aliases: [],
+ description: 'Promote issue to an epic',
+ warning: '',
+ icon: 'confidential',
+ params: [],
+ },
+ {
+ name: 'iteration',
+ aliases: [],
+ description: 'Set iteration',
+ warning: '',
+ icon: '',
+ params: ['*iteration:"iteration name" | *iteration:\u003cID\u003e'],
+ },
+ {
+ name: 'health_status',
+ aliases: [],
+ description: 'Set health status',
+ warning: '',
+ icon: '',
+ params: ['\u003con_track|needs_attention|at_risk\u003e'],
+ },
+ {
+ name: 'reassign',
+ aliases: [],
+ description: 'Change assignees',
+ warning: '',
+ icon: '',
+ params: ['@user1 @user2'],
+ },
+ {
+ name: 'weight',
+ aliases: [],
+ description: 'Set weight',
+ warning: '',
+ icon: '',
+ params: ['0, 1, 2, …'],
+ },
+ {
+ name: 'blocks',
+ aliases: [],
+ description: 'Specifies that this issue blocks other issues',
+ warning: '',
+ icon: '',
+ params: ['\u003c#issue | group/project#issue | issue URL\u003e'],
+ },
+ {
+ name: 'blocked_by',
+ aliases: [],
+ description: 'Mark this issue as blocked by other issues',
+ warning: '',
+ icon: '',
+ params: ['\u003c#issue | group/project#issue | issue URL\u003e'],
+ },
+];
diff --git a/spec/frontend/content_editor/services/data_source_factory_spec.js b/spec/frontend/content_editor/services/data_source_factory_spec.js
new file mode 100644
index 00000000000..d540f11711d
--- /dev/null
+++ b/spec/frontend/content_editor/services/data_source_factory_spec.js
@@ -0,0 +1,202 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import DataSourceFactory, {
+ defaultSorter,
+ customSorter,
+ createDataSource,
+} from '~/content_editor/services/data_source_factory';
+import {
+ MOCK_MEMBERS,
+ MOCK_COMMANDS,
+ MOCK_EPICS,
+ MOCK_ISSUES,
+ MOCK_LABELS,
+ MOCK_MILESTONES,
+ MOCK_SNIPPETS,
+ MOCK_VULNERABILITIES,
+ MOCK_MERGE_REQUESTS,
+ MOCK_ASSIGNEES,
+ MOCK_REVIEWERS,
+} from './autocomplete_mock_data';
+
+jest.mock('~/emoji');
+
+describe('defaultSorter', () => {
+ it('returns items as is if query is empty', () => {
+ const items = [{ name: 'abc' }, { name: 'bcd' }, { name: 'cde' }];
+ const sorter = defaultSorter(['name']);
+ expect(sorter(items, '')).toEqual(items);
+ });
+
+ it('sorts items based on query match', () => {
+ const items = [{ name: 'abc' }, { name: 'bcd' }, { name: 'cde' }];
+ const sorter = defaultSorter(['name']);
+ expect(sorter(items, 'b')).toEqual([{ name: 'bcd' }, { name: 'abc' }, { name: 'cde' }]);
+ });
+
+ it('sorts items based on query match in multiple fields', () => {
+ const items = [
+ { name: 'wabc', description: 'xyz' },
+ { name: 'bcd', description: 'wxy' },
+ { name: 'cde', description: 'vwx' },
+ ];
+ const sorter = defaultSorter(['name', 'description']);
+ expect(sorter(items, 'w')).toEqual([
+ { name: 'wabc', description: 'xyz' },
+ { name: 'bcd', description: 'wxy' },
+ { name: 'cde', description: 'vwx' },
+ ]);
+ });
+});
+
+describe('customSorter', () => {
+ it('sorts items based on custom sorter function', () => {
+ const items = [3, 1, 2];
+ const sorter = customSorter((a, b) => a - b);
+ expect(sorter(items)).toEqual([1, 2, 3]);
+ });
+});
+
+describe('createDataSource', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('fetches data from source and filters based on query', async () => {
+ const data = [
+ { name: 'abc', description: 'xyz' },
+ { name: 'bcd', description: 'wxy' },
+ { name: 'cde', description: 'vwx' },
+ ];
+ mock.onGet('/source').reply(200, data);
+
+ const dataSource = createDataSource({
+ source: '/source',
+ searchFields: ['name', 'description'],
+ });
+
+ const results = await dataSource.search('b');
+ expect(results).toEqual([
+ { name: 'bcd', description: 'wxy' },
+ { name: 'abc', description: 'xyz' },
+ ]);
+ });
+
+ it('handles source fetch errors', async () => {
+ mock.onGet('/source').reply(500);
+
+ const dataSource = createDataSource({
+ source: '/source',
+ searchFields: ['name', 'description'],
+ sorter: (items) => items,
+ });
+
+ const results = await dataSource.search('b');
+ expect(results).toEqual([]);
+ });
+});
+
+describe('DataSourceFactory', () => {
+ let mock;
+ let autocompleteHelper;
+ let dateNowOld;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ const dataSourceUrls = {
+ members: '/members',
+ issues: '/issues',
+ snippets: '/snippets',
+ labels: '/labels',
+ epics: '/epics',
+ milestones: '/milestones',
+ mergeRequests: '/mergeRequests',
+ vulnerabilities: '/vulnerabilities',
+ commands: '/commands',
+ };
+
+ mock.onGet('/members').reply(200, MOCK_MEMBERS);
+ mock.onGet('/issues').reply(200, MOCK_ISSUES);
+ mock.onGet('/snippets').reply(200, MOCK_SNIPPETS);
+ mock.onGet('/labels').reply(200, MOCK_LABELS);
+ mock.onGet('/epics').reply(200, MOCK_EPICS);
+ mock.onGet('/milestones').reply(200, MOCK_MILESTONES);
+ mock.onGet('/mergeRequests').reply(200, MOCK_MERGE_REQUESTS);
+ mock.onGet('/vulnerabilities').reply(200, MOCK_VULNERABILITIES);
+ mock.onGet('/commands').reply(200, MOCK_COMMANDS);
+
+ const sidebarMediator = {
+ store: {
+ assignees: MOCK_ASSIGNEES,
+ reviewers: MOCK_REVIEWERS,
+ },
+ };
+
+ autocompleteHelper = new DataSourceFactory({
+ dataSourceUrls,
+ sidebarMediator,
+ });
+
+ dateNowOld = Date.now();
+
+ jest.spyOn(Date, 'now').mockImplementation(() => new Date('2023-11-14').getTime());
+ });
+
+ afterEach(() => {
+ mock.restore();
+
+ jest.spyOn(Date, 'now').mockImplementation(() => dateNowOld);
+ });
+
+ it.each`
+ referenceType | query
+ ${'user'} | ${'r'}
+ ${'issue'} | ${'q'}
+ ${'snippet'} | ${'s'}
+ ${'label'} | ${'c'}
+ ${'epic'} | ${'n'}
+ ${'milestone'} | ${'16'}
+ ${'merge_request'} | ${'n'}
+ ${'vulnerability'} | ${'cross'}
+ ${'command'} | ${'re'}
+ `(
+ 'for reference type "$referenceType", searches for "$query" correctly',
+ async ({ referenceType, query }) => {
+ const dataSource = autocompleteHelper.getDataSource(referenceType);
+ const results = await dataSource.search(query);
+
+ expect(
+ results.map(({ title, name, username }) => username || name || title),
+ ).toMatchSnapshot();
+ },
+ );
+
+ it.each`
+ referenceType | command
+ ${'label'} | ${'/label'}
+ ${'label'} | ${'/unlabel'}
+ ${'label'} | ${'/relabel'}
+ ${'user'} | ${'/assign'}
+ ${'user'} | ${'/reassign'}
+ ${'user'} | ${'/unassign'}
+ ${'user'} | ${'/assign_reviewer'}
+ ${'user'} | ${'/unassign_reviewer'}
+ ${'user'} | ${'/reassign_reviewer'}
+ `(
+ 'filters items based on command "$command" for reference type "$referenceType" and command',
+ async ({ referenceType, command }) => {
+ const dataSource = autocompleteHelper.getDataSource(referenceType, { command });
+ const results = await dataSource.search();
+
+ expect(
+ results.map(({ username, name, title }) => username || name || title),
+ ).toMatchSnapshot();
+ },
+ );
+});
diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js
index 6cea75036bc..2d7841771a1 100644
--- a/spec/frontend/gfm_auto_complete_spec.js
+++ b/spec/frontend/gfm_auto_complete_spec.js
@@ -547,7 +547,7 @@ describe('GfmAutoComplete', () => {
expect(membersBeforeSave([{ ...mockGroup, avatar_url: null }])).toEqual([
{
username: 'my-group',
- avatarTag: '<div class="avatar rect-avatar center avatar-inline s26">M</div>',
+ avatarTag: '<div class="avatar rect-avatar avatar-inline s24 gl-mr-2">M</div>',
title: 'My Group (2)',
search: 'MyGroup my-group',
icon: '',
@@ -560,7 +560,7 @@ describe('GfmAutoComplete', () => {
{
username: 'my-group',
avatarTag:
- '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>',
+ '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline s24 gl-mr-2"/>',
title: 'My Group (2)',
search: 'MyGroup my-group',
icon: '',
@@ -573,7 +573,7 @@ describe('GfmAutoComplete', () => {
{
username: 'my-group',
avatarTag:
- '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>',
+ '<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline s24 gl-mr-2"/>',
title: 'My Group',
search: 'MyGroup my-group',
icon:
@@ -591,7 +591,7 @@ describe('GfmAutoComplete', () => {
{
username: 'my-user',
avatarTag:
- '<img src="./users.jpg" alt="my-user" class="avatar avatar-inline center s26"/>',
+ '<img src="./users.jpg" alt="my-user" class="avatar avatar-inline s24 gl-mr-2"/>',
title: 'My User',
search: 'MyUser my-user',
icon: '',
diff --git a/spec/frontend/groups/service/archived_projects_service_spec.js b/spec/frontend/groups/service/archived_projects_service_spec.js
index 6bc46e4799c..988fb5553ba 100644
--- a/spec/frontend/groups/service/archived_projects_service_spec.js
+++ b/spec/frontend/groups/service/archived_projects_service_spec.js
@@ -30,7 +30,7 @@ describe('ArchivedProjectsService', () => {
markdown_description: project.description_html,
visibility: project.visibility,
avatar_url: project.avatar_url,
- relative_path: `/${project.path_with_namespace}`,
+ relative_path: `${gon.relative_url_root}/${project.path_with_namespace}`,
edit_path: null,
leave_path: null,
can_edit: false,