Commit ac6a7aa9 authored by Sean Gregory's avatar Sean Gregory Committed by Phil Hughes

Adds tests around "showSuggestions"

Tests showSuggestions from the perspective of the computed booleans
that resolve it.  inlcuded:
* showDefaultSuggestions
* showRecentSuggestions
* showPreloadedSuggestions
* showAvailableSuggestions
parent b1088a03
...@@ -78,7 +78,7 @@ export default { ...@@ -78,7 +78,7 @@ export default {
return { return {
searchKey: '', searchKey: '',
recentSuggestions: this.config.recentSuggestionsStorageKey recentSuggestions: this.config.recentSuggestionsStorageKey
? getRecentlyUsedSuggestions(this.config.recentSuggestionsStorageKey) ? getRecentlyUsedSuggestions(this.config.recentSuggestionsStorageKey) ?? []
: [], : [],
}; };
}, },
......
import { GlFilteredSearchToken, GlLoadingIcon } from '@gitlab/ui'; import {
GlFilteredSearchToken,
GlLoadingIcon,
GlFilteredSearchSuggestion,
GlDropdownSectionHeader,
GlDropdownDivider,
} from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { import {
mockRegularLabel, mockRegularLabel,
mockLabels, mockLabels,
} from 'jest/vue_shared/components/sidebar/labels_select_vue/mock_data'; } 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 { import {
getRecentlyUsedSuggestions, getRecentlyUsedSuggestions,
setTokenValueToRecentlyUsed, setTokenValueToRecentlyUsed,
...@@ -32,6 +43,7 @@ const defaultStubs = { ...@@ -32,6 +43,7 @@ const defaultStubs = {
<div> <div>
<slot name="view-token"></slot> <slot name="view-token"></slot>
<slot name="view"></slot> <slot name="view"></slot>
<slot name="suggestions"></slot>
</div> </div>
`, `,
}, },
...@@ -43,6 +55,7 @@ const defaultStubs = { ...@@ -43,6 +55,7 @@ const defaultStubs = {
}, },
}; };
const mockSuggestionListTestId = 'suggestion-list';
const defaultSlots = { const defaultSlots = {
'view-token': ` 'view-token': `
<div class="js-view-token">${mockRegularLabel.title}</div> <div class="js-view-token">${mockRegularLabel.title}</div>
...@@ -52,6 +65,10 @@ const defaultSlots = { ...@@ -52,6 +65,10 @@ const defaultSlots = {
`, `,
}; };
const defaultScopedSlots = {
'suggestions-list': `<div data-testid="${mockSuggestionListTestId}" :data-suggestions="JSON.stringify(props.suggestions)"></div>`,
};
const mockProps = { const mockProps = {
config: { ...mockLabelToken, recentSuggestionsStorageKey: mockStorageKey }, config: { ...mockLabelToken, recentSuggestionsStorageKey: mockStorageKey },
value: { data: '' }, value: { data: '' },
...@@ -62,8 +79,14 @@ const mockProps = { ...@@ -62,8 +79,14 @@ const mockProps = {
getActiveTokenValue: (labels, data) => labels.find((label) => label.title === data), getActiveTokenValue: (labels, data) => labels.find((label) => label.title === data),
}; };
function createComponent({ props = {}, stubs = defaultStubs, slots = defaultSlots } = {}) { function createComponent({
return mount(BaseToken, { props = {},
stubs = defaultStubs,
slots = defaultSlots,
scopedSlots = defaultScopedSlots,
mountFn = mount,
} = {}) {
return mountFn(BaseToken, {
propsData: { propsData: {
...mockProps, ...mockProps,
...props, ...props,
...@@ -72,9 +95,14 @@ function createComponent({ props = {}, stubs = defaultStubs, slots = defaultSlot ...@@ -72,9 +95,14 @@ function createComponent({ props = {}, stubs = defaultStubs, slots = defaultSlot
portalName: 'fake target', portalName: 'fake target',
alignSuggestions: jest.fn(), alignSuggestions: jest.fn(),
suggestionsListClass: () => 'custom-class', suggestionsListClass: () => 'custom-class',
filteredSearchSuggestionListInstance: {
register: jest.fn(),
unregister: jest.fn(),
},
}, },
stubs, stubs,
slots, slots,
scopedSlots,
}); });
} }
...@@ -82,6 +110,9 @@ describe('BaseToken', () => { ...@@ -82,6 +110,9 @@ describe('BaseToken', () => {
let wrapper; let wrapper;
const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken); const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchToken);
const findMockSuggestionList = () => wrapper.findByTestId(mockSuggestionListTestId);
const getMockSuggestionListSuggestions = () =>
JSON.parse(findMockSuggestionList().attributes('data-suggestions'));
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -136,6 +167,147 @@ describe('BaseToken', () => { ...@@ -136,6 +167,147 @@ describe('BaseToken', () => {
}); });
}); });
describe('suggestions', () => {
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('methods', () => { describe('methods', () => {
describe('handleTokenValueSelected', () => { describe('handleTokenValueSelected', () => {
const mockTokenValue = mockLabels[0]; const mockTokenValue = mockLabels[0];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment