diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 18:44:42 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 18:44:42 +0300 |
commit | 4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch) | |
tree | 5423a1c7516cffe36384133ade12572cf709398d /spec/frontend/vue_shared/components/filtered_search_bar | |
parent | e570267f2f6b326480d284e0164a6464ba4081bc (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')
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); + }); +}); |