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:
Diffstat (limited to 'spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js')
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js225
1 files changed, 221 insertions, 4 deletions
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
index dd9bf2ff598..af8a2a496ea 100644
--- 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
@@ -1,12 +1,24 @@
-import { GlFilteredSearchToken, GlLoadingIcon } from '@gitlab/ui';
+import {
+ GlFilteredSearchToken,
+ GlLoadingIcon,
+ GlFilteredSearchSuggestion,
+ GlDropdownSectionHeader,
+ GlDropdownDivider,
+ GlDropdownText,
+} from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
mockRegularLabel,
mockLabels,
} from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data';
-import { DEFAULT_NONE_ANY } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ DEFAULT_NONE_ANY,
+ OPERATOR_IS,
+ OPERATOR_IS_NOT,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import {
getRecentlyUsedSuggestions,
setTokenValueToRecentlyUsed,
@@ -32,6 +44,7 @@ const defaultStubs = {
<div>
<slot name="view-token"></slot>
<slot name="view"></slot>
+ <slot name="suggestions"></slot>
</div>
`,
},
@@ -43,6 +56,7 @@ const defaultStubs = {
},
};
+const mockSuggestionListTestId = 'suggestion-list';
const defaultSlots = {
'view-token': `
<div class="js-view-token">${mockRegularLabel.title}</div>
@@ -52,6 +66,10 @@ const defaultSlots = {
`,
};
+const defaultScopedSlots = {
+ 'suggestions-list': `<div data-testid="${mockSuggestionListTestId}" :data-suggestions="JSON.stringify(props.suggestions)"></div>`,
+};
+
const mockProps = {
config: { ...mockLabelToken, recentSuggestionsStorageKey: mockStorageKey },
value: { data: '' },
@@ -62,8 +80,15 @@ const mockProps = {
getActiveTokenValue: (labels, data) => labels.find((label) => label.title === data),
};
-function createComponent({ props = {}, stubs = defaultStubs, slots = defaultSlots } = {}) {
- return mount(BaseToken, {
+function createComponent({
+ props = {},
+ data = {},
+ stubs = defaultStubs,
+ slots = defaultSlots,
+ scopedSlots = defaultScopedSlots,
+ mountFn = mount,
+} = {}) {
+ return mountFn(BaseToken, {
propsData: {
...mockProps,
...props,
@@ -72,9 +97,17 @@ function createComponent({ props = {}, stubs = defaultStubs, slots = defaultSlot
portalName: 'fake target',
alignSuggestions: jest.fn(),
suggestionsListClass: () => 'custom-class',
+ filteredSearchSuggestionListInstance: {
+ register: jest.fn(),
+ unregister: jest.fn(),
+ },
+ },
+ data() {
+ return data;
},
stubs,
slots,
+ scopedSlots,
});
}
@@ -82,6 +115,9 @@ describe('BaseToken', () => {
let wrapper;
const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
+ const findMockSuggestionList = () => wrapper.findByTestId(mockSuggestionListTestId);
+ const getMockSuggestionListSuggestions = () =>
+ JSON.parse(findMockSuggestionList().attributes('data-suggestions'));
afterEach(() => {
wrapper.destroy();
@@ -136,6 +172,187 @@ describe('BaseToken', () => {
});
});
+ describe('suggestions', () => {
+ describe('with suggestions disabled', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ props: {
+ config: {
+ suggestionsDisabled: true,
+ },
+ suggestions: [{ id: 'Foo' }],
+ },
+ mountFn: shallowMountExtended,
+ });
+ });
+
+ it('does not render suggestions', () => {
+ expect(findMockSuggestionList().exists()).toBe(false);
+ });
+ });
+
+ describe('with available suggestions', () => {
+ let mockSuggestions;
+
+ describe.each`
+ hasSuggestions | searchKey | shouldRenderSuggestions
+ ${true} | ${null} | ${true}
+ ${true} | ${'foo'} | ${true}
+ ${false} | ${null} | ${false}
+ `(
+ `when hasSuggestions is $hasSuggestions`,
+ ({ hasSuggestions, searchKey, shouldRenderSuggestions }) => {
+ beforeEach(async () => {
+ mockSuggestions = hasSuggestions ? [{ id: 'Foo' }] : [];
+ const props = { defaultSuggestions: [], suggestions: mockSuggestions };
+
+ getRecentlyUsedSuggestions.mockReturnValue([]);
+ wrapper = createComponent({ props, mountFn: shallowMountExtended, stubs: {} });
+ findGlFilteredSearchToken().vm.$emit('input', { data: searchKey });
+
+ await nextTick();
+ });
+
+ it(`${shouldRenderSuggestions ? 'should' : 'should not'} render suggestions`, () => {
+ expect(findMockSuggestionList().exists()).toBe(shouldRenderSuggestions);
+
+ if (shouldRenderSuggestions) {
+ expect(getMockSuggestionListSuggestions()).toEqual(mockSuggestions);
+ }
+ });
+ },
+ );
+ });
+
+ describe('with preloaded suggestions', () => {
+ const mockPreloadedSuggestions = [{ id: 'Foo' }, { id: 'Bar' }];
+
+ describe.each`
+ searchKey | shouldRenderPreloadedSuggestions
+ ${null} | ${true}
+ ${'foo'} | ${false}
+ `('when searchKey is $searchKey', ({ shouldRenderPreloadedSuggestions, searchKey }) => {
+ beforeEach(async () => {
+ const props = { preloadedSuggestions: mockPreloadedSuggestions };
+ wrapper = createComponent({ props, mountFn: shallowMountExtended, stubs: {} });
+ findGlFilteredSearchToken().vm.$emit('input', { data: searchKey });
+
+ await nextTick();
+ });
+
+ it(`${
+ shouldRenderPreloadedSuggestions ? 'should' : 'should not'
+ } render preloaded suggestions`, () => {
+ expect(findMockSuggestionList().exists()).toBe(shouldRenderPreloadedSuggestions);
+
+ if (shouldRenderPreloadedSuggestions) {
+ expect(getMockSuggestionListSuggestions()).toEqual(mockPreloadedSuggestions);
+ }
+ });
+ });
+ });
+
+ describe('with recent suggestions', () => {
+ let mockSuggestions;
+
+ describe.each`
+ searchKey | recentEnabled | shouldRenderRecentSuggestions
+ ${null} | ${true} | ${true}
+ ${'foo'} | ${true} | ${false}
+ ${null} | ${false} | ${false}
+ `(
+ 'when searchKey is $searchKey and recentEnabled is $recentEnabled',
+ ({ shouldRenderRecentSuggestions, recentEnabled, searchKey }) => {
+ beforeEach(async () => {
+ const props = { value: { data: '', operator: '=' }, defaultSuggestions: [] };
+
+ if (recentEnabled) {
+ mockSuggestions = [{ id: 'Foo' }, { id: 'Bar' }];
+ getRecentlyUsedSuggestions.mockReturnValue(mockSuggestions);
+ }
+
+ props.config = { recentSuggestionsStorageKey: recentEnabled ? mockStorageKey : null };
+
+ wrapper = createComponent({ props, mountFn: shallowMountExtended, stubs: {} });
+ findGlFilteredSearchToken().vm.$emit('input', { data: searchKey });
+
+ await nextTick();
+ });
+
+ it(`${
+ shouldRenderRecentSuggestions ? 'should' : 'should not'
+ } render recent suggestions`, () => {
+ expect(findMockSuggestionList().exists()).toBe(shouldRenderRecentSuggestions);
+ expect(wrapper.findComponent(GlDropdownSectionHeader).exists()).toBe(
+ shouldRenderRecentSuggestions,
+ );
+ expect(wrapper.findComponent(GlDropdownDivider).exists()).toBe(
+ shouldRenderRecentSuggestions,
+ );
+
+ if (shouldRenderRecentSuggestions) {
+ expect(getMockSuggestionListSuggestions()).toEqual(mockSuggestions);
+ }
+ });
+ },
+ );
+ });
+
+ describe('with default suggestions', () => {
+ describe.each`
+ operator | shouldRenderFilteredSearchSuggestion
+ ${OPERATOR_IS} | ${true}
+ ${OPERATOR_IS_NOT} | ${false}
+ `('when operator is $operator', ({ shouldRenderFilteredSearchSuggestion, operator }) => {
+ beforeEach(() => {
+ const props = {
+ defaultSuggestions: DEFAULT_NONE_ANY,
+ value: { data: '', operator },
+ };
+
+ wrapper = createComponent({ props, mountFn: shallowMountExtended });
+ });
+
+ it(`${
+ shouldRenderFilteredSearchSuggestion ? 'should' : 'should not'
+ } render GlFilteredSearchSuggestion`, () => {
+ const filteredSearchSuggestions = wrapper.findAllComponents(GlFilteredSearchSuggestion)
+ .wrappers;
+
+ if (shouldRenderFilteredSearchSuggestion) {
+ expect(filteredSearchSuggestions.map((c) => c.props())).toMatchObject(
+ DEFAULT_NONE_ANY.map((opt) => ({ value: opt.value })),
+ );
+ } else {
+ expect(filteredSearchSuggestions).toHaveLength(0);
+ }
+ });
+ });
+ });
+
+ describe('with no suggestions', () => {
+ it.each`
+ data | expected
+ ${{ searchKey: 'search' }} | ${'No matches found'}
+ ${{ hasFetched: true }} | ${'No suggestions found'}
+ `('shows $expected text', ({ data, expected }) => {
+ wrapper = createComponent({
+ props: {
+ config: { recentSuggestionsStorageKey: null },
+ defaultSuggestions: [],
+ preloadedSuggestions: [],
+ suggestions: [],
+ suggestionsLoading: false,
+ },
+ data,
+ mountFn: shallowMountExtended,
+ });
+
+ expect(wrapper.findComponent(GlDropdownText).text()).toBe(expected);
+ });
+ });
+ });
+
describe('methods', () => {
describe('handleTokenValueSelected', () => {
const mockTokenValue = mockLabels[0];