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>2021-05-19 18:44:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /spec/frontend/vue_shared/components/filtered_search_bar
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/frontend/vue_shared/components/filtered_search_bar')
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js87
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js38
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js228
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js9
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js3
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/epic_token_spec.js29
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js78
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/weight_token_spec.js37
10 files changed, 468 insertions, 50 deletions
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js
index 9e96c154546..b2ed79cd75a 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js
@@ -1,3 +1,6 @@
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+
+import AccessorUtilities from '~/lib/utils/accessor';
import {
stripQuotes,
uniqueTokens,
@@ -5,6 +8,8 @@ import {
processFilters,
filterToQueryObject,
urlQueryToFilter,
+ getRecentlyUsedTokenValues,
+ setTokenValueToRecentlyUsed,
} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
import {
@@ -14,6 +19,12 @@ import {
tokenValuePlain,
} from './mock_data';
+const mockStorageKey = 'recent-tokens';
+
+function setLocalStorageAvailability(isAvailable) {
+ jest.spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').mockReturnValue(isAvailable);
+}
+
describe('Filtered Search Utils', () => {
describe('stripQuotes', () => {
it.each`
@@ -249,3 +260,79 @@ describe('urlQueryToFilter', () => {
expect(res).toEqual(result);
});
});
+
+describe('getRecentlyUsedTokenValues', () => {
+ useLocalStorageSpy();
+
+ beforeEach(() => {
+ localStorage.removeItem(mockStorageKey);
+ });
+
+ it('returns array containing recently used token values from provided recentTokenValuesStorageKey', () => {
+ setLocalStorageAvailability(true);
+
+ const mockExpectedArray = [{ foo: 'bar' }];
+ localStorage.setItem(mockStorageKey, JSON.stringify(mockExpectedArray));
+
+ expect(getRecentlyUsedTokenValues(mockStorageKey)).toEqual(mockExpectedArray);
+ });
+
+ it('returns empty array when provided recentTokenValuesStorageKey does not have anything in localStorage', () => {
+ setLocalStorageAvailability(true);
+
+ expect(getRecentlyUsedTokenValues(mockStorageKey)).toEqual([]);
+ });
+
+ it('returns empty array when when access to localStorage is not available', () => {
+ setLocalStorageAvailability(false);
+
+ expect(getRecentlyUsedTokenValues(mockStorageKey)).toEqual([]);
+ });
+});
+
+describe('setTokenValueToRecentlyUsed', () => {
+ const mockTokenValue1 = { foo: 'bar' };
+ const mockTokenValue2 = { bar: 'baz' };
+ useLocalStorageSpy();
+
+ beforeEach(() => {
+ localStorage.removeItem(mockStorageKey);
+ });
+
+ it('adds provided tokenValue to localStorage for recentTokenValuesStorageKey', () => {
+ setLocalStorageAvailability(true);
+
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue1);
+
+ expect(JSON.parse(localStorage.getItem(mockStorageKey))).toEqual([mockTokenValue1]);
+ });
+
+ it('adds provided tokenValue to localStorage at the top of existing values (i.e. Stack order)', () => {
+ setLocalStorageAvailability(true);
+
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue1);
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue2);
+
+ expect(JSON.parse(localStorage.getItem(mockStorageKey))).toEqual([
+ mockTokenValue2,
+ mockTokenValue1,
+ ]);
+ });
+
+ it('ensures that provided tokenValue is not added twice', () => {
+ setLocalStorageAvailability(true);
+
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue1);
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue1);
+
+ expect(JSON.parse(localStorage.getItem(mockStorageKey))).toEqual([mockTokenValue1]);
+ });
+
+ it('does not add any value when acess to localStorage is not available', () => {
+ setLocalStorageAvailability(false);
+
+ setTokenValueToRecentlyUsed(mockStorageKey, mockTokenValue1);
+
+ expect(JSON.parse(localStorage.getItem(mockStorageKey))).toBeNull();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
index c24528ba4d2..23e4deab9c1 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js
@@ -1,12 +1,15 @@
import { GlFilteredSearchToken } from '@gitlab/ui';
import { mockLabels } from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data';
import Api from '~/api';
+import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import EpicToken from '~/vue_shared/components/filtered_search_bar/tokens/epic_token.vue';
+import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
+import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
export const mockAuthor1 = {
id: 1,
@@ -37,7 +40,7 @@ export const mockAuthor3 = {
export const mockAuthors = [mockAuthor1, mockAuthor2, mockAuthor3];
-export const mockBranches = [{ name: 'Master' }, { name: 'v1.x' }, { name: 'my-Branch' }];
+export const mockBranches = [{ name: 'Main' }, { name: 'v1.x' }, { name: 'my-Branch' }];
export const mockRegularMilestone = {
id: 1,
@@ -82,7 +85,7 @@ export const mockBranchToken = {
title: 'Source Branch',
unique: true,
token: BranchToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
fetchBranches: Api.branches.bind(Api),
};
@@ -93,11 +96,20 @@ export const mockAuthorToken = {
unique: false,
symbol: '@',
token: AuthorToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
fetchPath: 'gitlab-org/gitlab-test',
fetchAuthors: Api.projectUsers.bind(Api),
};
+export const mockIterationToken = {
+ type: 'iteration',
+ icon: 'iteration',
+ title: 'Iteration',
+ unique: true,
+ token: IterationToken,
+ fetchIterations: () => Promise.resolve(),
+};
+
export const mockLabelToken = {
type: 'label_name',
icon: 'labels',
@@ -105,7 +117,7 @@ export const mockLabelToken = {
unique: false,
symbol: '~',
token: LabelToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
fetchLabels: () => Promise.resolve(mockLabels),
};
@@ -116,7 +128,7 @@ export const mockMilestoneToken = {
unique: true,
symbol: '%',
token: MilestoneToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
fetchMilestones: () => Promise.resolve({ data: mockMilestones }),
};
@@ -127,9 +139,9 @@ export const mockEpicToken = {
unique: true,
symbol: '&',
token: EpicToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
+ idProperty: 'iid',
fetchEpics: () => Promise.resolve({ data: mockEpics }),
- fetchSingleEpic: () => Promise.resolve({ data: mockEpics[0] }),
};
export const mockReactionEmojiToken = {
@@ -138,7 +150,7 @@ export const mockReactionEmojiToken = {
title: 'My-Reaction',
unique: true,
token: EmojiToken,
- operators: [{ value: '=', description: 'is', default: 'true' }],
+ operators: OPERATOR_IS_ONLY,
fetchEmojis: () => Promise.resolve(mockEmojis),
};
@@ -148,13 +160,21 @@ export const mockMembershipToken = {
title: 'Membership',
token: GlFilteredSearchToken,
unique: true,
- operators: [{ value: '=', description: 'is' }],
+ operators: OPERATOR_IS_ONLY,
options: [
{ value: 'exclude', title: 'Direct' },
{ value: 'only', title: 'Inherited' },
],
};
+export const mockWeightToken = {
+ type: 'weight',
+ icon: 'weight',
+ title: 'Weight',
+ unique: true,
+ token: WeightToken,
+};
+
export const mockMembershipTokenOptionsWithoutTitles = {
...mockMembershipToken,
options: [{ value: 'exclude' }, { value: 'only' }],
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js
index 765e576914c..3b50927dcc6 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js
@@ -11,8 +11,8 @@ import { deprecatedCreateFlash as createFlash } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import {
- DEFAULT_LABEL_NONE,
DEFAULT_LABEL_ANY,
+ DEFAULT_NONE_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
@@ -159,7 +159,7 @@ describe('AuthorToken', () => {
});
it('renders provided defaultAuthors as suggestions', async () => {
- const defaultAuthors = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
+ const defaultAuthors = DEFAULT_NONE_ANY;
wrapper = createComponent({
active: true,
config: { ...mockAuthorToken, defaultAuthors },
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
new file mode 100644
index 00000000000..0db47f1f189
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js
@@ -0,0 +1,228 @@
+import { GlFilteredSearchToken } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import {
+ mockRegularLabel,
+ mockLabels,
+} from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data';
+
+import { DEFAULT_LABELS } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ getRecentlyUsedTokenValues,
+ setTokenValueToRecentlyUsed,
+} from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
+
+import { mockLabelToken } from '../mock_data';
+
+jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils');
+
+const mockStorageKey = 'recent-tokens-label_name';
+
+const defaultStubs = {
+ Portal: true,
+ GlFilteredSearchToken: {
+ template: `
+ <div>
+ <slot name="view-token"></slot>
+ <slot name="view"></slot>
+ </div>
+ `,
+ },
+ GlFilteredSearchSuggestionList: {
+ template: '<div></div>',
+ methods: {
+ getValue: () => '=',
+ },
+ },
+};
+
+const defaultSlots = {
+ 'view-token': `
+ <div class="js-view-token">${mockRegularLabel.title}</div>
+ `,
+ view: `
+ <div class="js-view">${mockRegularLabel.title}</div>
+ `,
+};
+
+const mockProps = {
+ tokenConfig: mockLabelToken,
+ tokenValue: { data: '' },
+ tokenActive: false,
+ tokensListLoading: false,
+ tokenValues: [],
+ fnActiveTokenValue: jest.fn(),
+ defaultTokenValues: DEFAULT_LABELS,
+ recentTokenValuesStorageKey: mockStorageKey,
+ fnCurrentTokenValue: jest.fn(),
+};
+
+function createComponent({
+ props = { ...mockProps },
+ stubs = defaultStubs,
+ slots = defaultSlots,
+} = {}) {
+ return mount(BaseToken, {
+ propsData: {
+ ...props,
+ },
+ provide: {
+ portalName: 'fake target',
+ alignSuggestions: jest.fn(),
+ suggestionsListClass: 'custom-class',
+ },
+ stubs,
+ slots,
+ });
+}
+
+describe('BaseToken', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent({
+ props: {
+ ...mockProps,
+ tokenValue: { data: `"${mockRegularLabel.title}"` },
+ tokenValues: mockLabels,
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('data', () => {
+ it('calls `getRecentlyUsedTokenValues` to populate `recentTokenValues` when `recentTokenValuesStorageKey` is defined', () => {
+ expect(getRecentlyUsedTokenValues).toHaveBeenCalledWith(mockStorageKey);
+ });
+ });
+
+ describe('computed', () => {
+ describe('currentTokenValue', () => {
+ it('calls `fnCurrentTokenValue` when it is provided', () => {
+ // We're disabling lint to trigger computed prop execution for this test.
+ // eslint-disable-next-line no-unused-vars
+ const { currentTokenValue } = wrapper.vm;
+
+ expect(wrapper.vm.fnCurrentTokenValue).toHaveBeenCalledWith(`"${mockRegularLabel.title}"`);
+ });
+ });
+
+ describe('activeTokenValue', () => {
+ it('calls `fnActiveTokenValue` when it is provided', async () => {
+ wrapper.setProps({
+ fnCurrentTokenValue: undefined,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // We're disabling lint to trigger computed prop execution for this test.
+ // eslint-disable-next-line no-unused-vars
+ const { activeTokenValue } = wrapper.vm;
+
+ expect(wrapper.vm.fnActiveTokenValue).toHaveBeenCalledWith(
+ mockLabels,
+ `"${mockRegularLabel.title.toLowerCase()}"`,
+ );
+ });
+ });
+ });
+
+ describe('watch', () => {
+ describe('tokenActive', () => {
+ let wrapperWithTokenActive;
+
+ beforeEach(() => {
+ wrapperWithTokenActive = createComponent({
+ props: {
+ ...mockProps,
+ tokenActive: true,
+ tokenValue: { data: `"${mockRegularLabel.title}"` },
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapperWithTokenActive.destroy();
+ });
+
+ it('emits `fetch-token-values` event on the component when value of this prop is changed to false and `tokenValues` array is empty', async () => {
+ wrapperWithTokenActive.setProps({
+ tokenActive: false,
+ });
+
+ await wrapperWithTokenActive.vm.$nextTick();
+
+ expect(wrapperWithTokenActive.emitted('fetch-token-values')).toBeTruthy();
+ expect(wrapperWithTokenActive.emitted('fetch-token-values')).toEqual([
+ [`"${mockRegularLabel.title}"`],
+ ]);
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('handleTokenValueSelected', () => {
+ it('calls `setTokenValueToRecentlyUsed` when `recentTokenValuesStorageKey` is defined', () => {
+ const mockTokenValue = {
+ id: 1,
+ title: 'Foo',
+ };
+
+ wrapper.vm.handleTokenValueSelected(mockTokenValue);
+
+ expect(setTokenValueToRecentlyUsed).toHaveBeenCalledWith(mockStorageKey, mockTokenValue);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders gl-filtered-search-token component', () => {
+ const wrapperWithNoStubs = createComponent({
+ stubs: {},
+ });
+ const glFilteredSearchToken = wrapperWithNoStubs.find(GlFilteredSearchToken);
+
+ expect(glFilteredSearchToken.exists()).toBe(true);
+ expect(glFilteredSearchToken.props('config')).toBe(mockLabelToken);
+
+ wrapperWithNoStubs.destroy();
+ });
+
+ it('renders `view-token` slot when present', () => {
+ expect(wrapper.find('.js-view-token').exists()).toBe(true);
+ });
+
+ it('renders `view` slot when present', () => {
+ expect(wrapper.find('.js-view').exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ let wrapperWithNoStubs;
+
+ beforeEach(() => {
+ wrapperWithNoStubs = createComponent({
+ stubs: { Portal: true },
+ });
+ });
+
+ afterEach(() => {
+ wrapperWithNoStubs.destroy();
+ });
+
+ it('emits `fetch-token-values` event on component after a delay when component emits `input` event', async () => {
+ jest.useFakeTimers();
+
+ wrapperWithNoStubs.find(GlFilteredSearchToken).vm.$emit('input', { data: 'foo' });
+ await wrapperWithNoStubs.vm.$nextTick();
+
+ jest.runAllTimers();
+
+ expect(wrapperWithNoStubs.emitted('fetch-token-values')).toBeTruthy();
+ expect(wrapperWithNoStubs.emitted('fetch-token-values')[1]).toEqual(['foo']);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
index a20bc4986fc..331c9c2c14d 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js
@@ -10,10 +10,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
-import {
- DEFAULT_LABEL_NONE,
- DEFAULT_LABEL_ANY,
-} from '~/vue_shared/components/filtered_search_bar/constants';
+import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
import BranchToken from '~/vue_shared/components/filtered_search_bar/tokens/branch_token.vue';
import { mockBranches, mockBranchToken } from '../mock_data';
@@ -77,7 +74,7 @@ describe('BranchToken', () => {
describe('currentValue', () => {
it('returns lowercase string for `value.data`', () => {
- expect(wrapper.vm.currentValue).toBe('master');
+ expect(wrapper.vm.currentValue).toBe('main');
});
});
@@ -137,7 +134,7 @@ describe('BranchToken', () => {
});
describe('template', () => {
- const defaultBranches = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
+ const defaultBranches = DEFAULT_NONE_ANY;
async function showSuggestions() {
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
const suggestionsSegment = tokenSegments.at(2);
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
index 231f2f01428..fb48aea8e4f 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js
@@ -13,6 +13,7 @@ import axios from '~/lib/utils/axios_utils';
import {
DEFAULT_LABEL_NONE,
DEFAULT_LABEL_ANY,
+ DEFAULT_NONE_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
@@ -137,7 +138,7 @@ describe('EmojiToken', () => {
});
describe('template', () => {
- const defaultEmojis = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
+ const defaultEmojis = DEFAULT_NONE_ANY;
beforeEach(async () => {
wrapper = createComponent({
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/epic_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/epic_token_spec.js
index 0c3f9e1363f..addc058f658 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/epic_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/epic_token_spec.js
@@ -68,21 +68,6 @@ describe('EpicToken', () => {
await wrapper.vm.$nextTick();
});
- describe('currentValue', () => {
- it.each`
- data | id
- ${`${mockEpics[0].title}::&${mockEpics[0].iid}`} | ${mockEpics[0].iid}
- ${mockEpics[0].iid} | ${mockEpics[0].iid}
- ${'foobar'} | ${'foobar'}
- `('$data returns $id', async ({ data, id }) => {
- wrapper.setProps({ value: { data } });
-
- await wrapper.vm.$nextTick();
-
- expect(wrapper.vm.currentValue).toBe(id);
- });
- });
-
describe('activeEpic', () => {
it('returns object for currently present `value.data`', async () => {
wrapper.setProps({
@@ -140,20 +125,6 @@ describe('EpicToken', () => {
expect(wrapper.vm.loading).toBe(false);
});
});
-
- describe('fetchSingleEpic', () => {
- it('calls `config.fetchSingleEpic` with provided iid param', async () => {
- jest.spyOn(wrapper.vm.config, 'fetchSingleEpic');
-
- wrapper.vm.fetchSingleEpic(1);
-
- expect(wrapper.vm.config.fetchSingleEpic).toHaveBeenCalledWith(1);
-
- await waitForPromises();
-
- expect(wrapper.vm.epics).toEqual([mockEpics[0]]);
- });
- });
});
describe('template', () => {
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js
new file mode 100644
index 00000000000..ca5dc984ae0
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/iteration_token_spec.js
@@ -0,0 +1,78 @@
+import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import createFlash from '~/flash';
+import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
+import { mockIterationToken } from '../mock_data';
+
+jest.mock('~/flash');
+
+describe('IterationToken', () => {
+ const title = 'gitlab-org: #1';
+ let wrapper;
+
+ const createComponent = ({ config = mockIterationToken, value = { data: '' } } = {}) =>
+ mount(IterationToken, {
+ propsData: {
+ config,
+ value,
+ },
+ provide: {
+ portalName: 'fake target',
+ alignSuggestions: function fakeAlignSuggestions() {},
+ suggestionsListClass: 'custom-class',
+ },
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders iteration value', async () => {
+ wrapper = createComponent({ value: { data: title } });
+
+ await wrapper.vm.$nextTick();
+
+ const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+
+ expect(tokenSegments).toHaveLength(3); // `Iteration` `=` `gitlab-org: #1`
+ expect(tokenSegments.at(2).text()).toBe(title);
+ });
+
+ it('fetches initial values', () => {
+ const fetchIterationsSpy = jest.fn().mockResolvedValue();
+
+ wrapper = createComponent({
+ config: { ...mockIterationToken, fetchIterations: fetchIterationsSpy },
+ value: { data: title },
+ });
+
+ expect(fetchIterationsSpy).toHaveBeenCalledWith(title);
+ });
+
+ it('fetches iterations on user input', () => {
+ const search = 'hello';
+ const fetchIterationsSpy = jest.fn().mockResolvedValue();
+
+ wrapper = createComponent({
+ config: { ...mockIterationToken, fetchIterations: fetchIterationsSpy },
+ });
+
+ wrapper.findComponent(GlFilteredSearchToken).vm.$emit('input', { data: search });
+
+ expect(fetchIterationsSpy).toHaveBeenCalledWith(search);
+ });
+
+ it('renders error message when request fails', async () => {
+ const fetchIterationsSpy = jest.fn().mockRejectedValue();
+
+ wrapper = createComponent({
+ config: { ...mockIterationToken, fetchIterations: fetchIterationsSpy },
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'There was a problem fetching iterations.',
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
index 8528c062426..57514a0c499 100644
--- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js
@@ -16,8 +16,7 @@ import axios from '~/lib/utils/axios_utils';
import {
DEFAULT_LABELS,
- DEFAULT_LABEL_NONE,
- DEFAULT_LABEL_ANY,
+ DEFAULT_NONE_ANY,
} from '~/vue_shared/components/filtered_search_bar/constants';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
@@ -176,7 +175,7 @@ describe('LabelToken', () => {
});
describe('template', () => {
- const defaultLabels = [DEFAULT_LABEL_NONE, DEFAULT_LABEL_ANY];
+ const defaultLabels = DEFAULT_NONE_ANY;
beforeEach(async () => {
wrapper = createComponent({ value: { data: `"${mockRegularLabel.title}"` } });
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/weight_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/weight_token_spec.js
new file mode 100644
index 00000000000..9a72be636cd
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/weight_token_spec.js
@@ -0,0 +1,37 @@
+import { GlFilteredSearchTokenSegment } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue';
+import { mockWeightToken } from '../mock_data';
+
+jest.mock('~/flash');
+
+describe('WeightToken', () => {
+ const weight = '3';
+ let wrapper;
+
+ const createComponent = ({ config = mockWeightToken, value = { data: '' } } = {}) =>
+ mount(WeightToken, {
+ propsData: {
+ config,
+ value,
+ },
+ provide: {
+ portalName: 'fake target',
+ alignSuggestions: function fakeAlignSuggestions() {},
+ suggestionsListClass: 'custom-class',
+ },
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders weight value', () => {
+ wrapper = createComponent({ value: { data: weight } });
+
+ const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
+
+ expect(tokenSegments).toHaveLength(3); // `Weight` `=` `3`
+ expect(tokenSegments.at(2).text()).toBe(weight);
+ });
+});