304 lines
8.6 KiB
JavaScript
304 lines
8.6 KiB
JavaScript
import {
|
|
GlFilteredSearchTokenSegment,
|
|
GlFilteredSearchSuggestion,
|
|
GlDropdownDivider,
|
|
GlAvatar,
|
|
} from '@gitlab/ui';
|
|
import { mount } from '@vue/test-utils';
|
|
import MockAdapter from 'axios-mock-adapter';
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
|
import createFlash from '~/flash';
|
|
import axios from '~/lib/utils/axios_utils';
|
|
|
|
import {
|
|
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';
|
|
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
|
|
|
|
import { mockAuthorToken, mockAuthors } from '../mock_data';
|
|
|
|
jest.mock('~/flash');
|
|
const defaultStubs = {
|
|
Portal: true,
|
|
GlFilteredSearchSuggestionList: {
|
|
template: '<div></div>',
|
|
methods: {
|
|
getValue: () => '=',
|
|
},
|
|
},
|
|
};
|
|
|
|
const mockPreloadedAuthors = [
|
|
{
|
|
id: 13,
|
|
name: 'Administrator',
|
|
username: 'root',
|
|
avatar_url: 'avatar/url',
|
|
},
|
|
];
|
|
|
|
function createComponent(options = {}) {
|
|
const {
|
|
config = mockAuthorToken,
|
|
value = { data: '' },
|
|
active = false,
|
|
stubs = defaultStubs,
|
|
data = {},
|
|
listeners = {},
|
|
} = options;
|
|
return mount(AuthorToken, {
|
|
propsData: {
|
|
config,
|
|
value,
|
|
active,
|
|
},
|
|
provide: {
|
|
portalName: 'fake target',
|
|
alignSuggestions: function fakeAlignSuggestions() {},
|
|
suggestionsListClass: 'custom-class',
|
|
},
|
|
data() {
|
|
return { ...data };
|
|
},
|
|
stubs,
|
|
listeners,
|
|
});
|
|
}
|
|
|
|
describe('AuthorToken', () => {
|
|
const originalGon = window.gon;
|
|
const currentUserLength = 1;
|
|
let mock;
|
|
let wrapper;
|
|
|
|
const getBaseToken = () => wrapper.findComponent(BaseToken);
|
|
|
|
beforeEach(() => {
|
|
mock = new MockAdapter(axios);
|
|
});
|
|
|
|
afterEach(() => {
|
|
window.gon = originalGon;
|
|
mock.restore();
|
|
wrapper.destroy();
|
|
});
|
|
|
|
describe('methods', () => {
|
|
describe('fetchAuthorBySearchTerm', () => {
|
|
beforeEach(() => {
|
|
wrapper = createComponent();
|
|
});
|
|
|
|
it('calls `config.fetchAuthors` with provided searchTerm param', () => {
|
|
jest.spyOn(wrapper.vm.config, 'fetchAuthors');
|
|
|
|
getBaseToken().vm.$emit('fetch-token-values', mockAuthors[0].username);
|
|
|
|
expect(wrapper.vm.config.fetchAuthors).toHaveBeenCalledWith(
|
|
mockAuthorToken.fetchPath,
|
|
mockAuthors[0].username,
|
|
);
|
|
});
|
|
|
|
it('sets response to `authors` when request is succesful', () => {
|
|
jest.spyOn(wrapper.vm.config, 'fetchAuthors').mockResolvedValue(mockAuthors);
|
|
|
|
getBaseToken().vm.$emit('fetch-token-values', 'root');
|
|
|
|
return waitForPromises().then(() => {
|
|
expect(getBaseToken().props('tokenValues')).toEqual(mockAuthors);
|
|
});
|
|
});
|
|
|
|
it('calls `createFlash` with flash error message when request fails', () => {
|
|
jest.spyOn(wrapper.vm.config, 'fetchAuthors').mockRejectedValue({});
|
|
|
|
getBaseToken().vm.$emit('fetch-token-values', 'root');
|
|
|
|
return waitForPromises().then(() => {
|
|
expect(createFlash).toHaveBeenCalledWith({
|
|
message: 'There was a problem fetching users.',
|
|
});
|
|
});
|
|
});
|
|
|
|
it('sets `loading` to false when request completes', async () => {
|
|
jest.spyOn(wrapper.vm.config, 'fetchAuthors').mockRejectedValue({});
|
|
|
|
getBaseToken().vm.$emit('fetch-token-values', 'root');
|
|
|
|
await waitForPromises();
|
|
|
|
expect(getBaseToken().props('tokensListLoading')).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('template', () => {
|
|
const activateTokenValuesList = async () => {
|
|
const tokenSegments = wrapper.findAllComponents(GlFilteredSearchTokenSegment);
|
|
const suggestionsSegment = tokenSegments.at(2);
|
|
suggestionsSegment.vm.$emit('activate');
|
|
await wrapper.vm.$nextTick();
|
|
};
|
|
|
|
it('renders base-token component', () => {
|
|
wrapper = createComponent({
|
|
value: { data: mockAuthors[0].username },
|
|
data: { authors: mockAuthors },
|
|
});
|
|
|
|
const baseTokenEl = getBaseToken();
|
|
|
|
expect(baseTokenEl.exists()).toBe(true);
|
|
expect(baseTokenEl.props()).toMatchObject({
|
|
tokenValues: mockAuthors,
|
|
fnActiveTokenValue: wrapper.vm.getActiveAuthor,
|
|
});
|
|
});
|
|
|
|
it('renders token item when value is selected', () => {
|
|
wrapper = createComponent({
|
|
value: { data: mockAuthors[0].username },
|
|
data: { authors: mockAuthors },
|
|
stubs: { Portal: true },
|
|
});
|
|
|
|
return wrapper.vm.$nextTick(() => {
|
|
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
|
|
|
expect(tokenSegments).toHaveLength(3); // Author, =, "Administrator"
|
|
|
|
const tokenValue = tokenSegments.at(2);
|
|
|
|
expect(tokenValue.findComponent(GlAvatar).props('src')).toBe(mockAuthors[0].avatar_url);
|
|
expect(tokenValue.text()).toBe(mockAuthors[0].name); // "Administrator"
|
|
});
|
|
});
|
|
|
|
it('renders token value with correct avatarUrl from author object', async () => {
|
|
const getAvatarEl = () =>
|
|
wrapper.findAll(GlFilteredSearchTokenSegment).at(2).findComponent(GlAvatar);
|
|
|
|
wrapper = createComponent({
|
|
value: { data: mockAuthors[0].username },
|
|
data: {
|
|
authors: [
|
|
{
|
|
...mockAuthors[0],
|
|
},
|
|
],
|
|
},
|
|
stubs: { Portal: true },
|
|
});
|
|
|
|
await wrapper.vm.$nextTick();
|
|
|
|
expect(getAvatarEl().props('src')).toBe(mockAuthors[0].avatar_url);
|
|
|
|
wrapper.setData({
|
|
authors: [
|
|
{
|
|
...mockAuthors[0],
|
|
avatarUrl: mockAuthors[0].avatar_url,
|
|
avatar_url: undefined,
|
|
},
|
|
],
|
|
});
|
|
|
|
await wrapper.vm.$nextTick();
|
|
|
|
expect(getAvatarEl().props('src')).toBe(mockAuthors[0].avatar_url);
|
|
});
|
|
|
|
it('renders provided defaultAuthors as suggestions', async () => {
|
|
const defaultAuthors = DEFAULT_NONE_ANY;
|
|
wrapper = createComponent({
|
|
active: true,
|
|
config: { ...mockAuthorToken, defaultAuthors, preloadedAuthors: mockPreloadedAuthors },
|
|
stubs: { Portal: true },
|
|
});
|
|
|
|
await activateTokenValuesList();
|
|
|
|
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
|
|
|
expect(suggestions).toHaveLength(defaultAuthors.length + currentUserLength);
|
|
defaultAuthors.forEach((label, index) => {
|
|
expect(suggestions.at(index).text()).toBe(label.text);
|
|
});
|
|
});
|
|
|
|
it('does not render divider when no defaultAuthors', async () => {
|
|
wrapper = createComponent({
|
|
active: true,
|
|
config: { ...mockAuthorToken, defaultAuthors: [] },
|
|
stubs: { Portal: true },
|
|
});
|
|
const tokenSegments = wrapper.findAll(GlFilteredSearchTokenSegment);
|
|
const suggestionsSegment = tokenSegments.at(2);
|
|
suggestionsSegment.vm.$emit('activate');
|
|
await wrapper.vm.$nextTick();
|
|
|
|
expect(wrapper.find(GlDropdownDivider).exists()).toBe(false);
|
|
});
|
|
|
|
it('renders `DEFAULT_LABEL_ANY` as default suggestions', async () => {
|
|
wrapper = createComponent({
|
|
active: true,
|
|
config: { ...mockAuthorToken, preloadedAuthors: mockPreloadedAuthors },
|
|
stubs: { Portal: true },
|
|
});
|
|
|
|
await activateTokenValuesList();
|
|
|
|
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
|
|
|
|
expect(suggestions).toHaveLength(1 + currentUserLength);
|
|
expect(suggestions.at(0).text()).toBe(DEFAULT_LABEL_ANY.text);
|
|
});
|
|
|
|
it('emits listeners in the base-token', () => {
|
|
const mockInput = jest.fn();
|
|
wrapper = createComponent({
|
|
listeners: {
|
|
input: mockInput,
|
|
},
|
|
});
|
|
wrapper.findComponent(BaseToken).vm.$emit('input', [{ data: 'mockData', operator: '=' }]);
|
|
|
|
expect(mockInput).toHaveBeenLastCalledWith([{ data: 'mockData', operator: '=' }]);
|
|
});
|
|
|
|
describe('when loading', () => {
|
|
beforeEach(() => {
|
|
wrapper = createComponent({
|
|
active: true,
|
|
config: {
|
|
...mockAuthorToken,
|
|
preloadedAuthors: mockPreloadedAuthors,
|
|
defaultAuthors: [],
|
|
},
|
|
stubs: { Portal: true },
|
|
});
|
|
});
|
|
|
|
it('shows current user', () => {
|
|
const firstSuggestion = wrapper.findComponent(GlFilteredSearchSuggestion).text();
|
|
expect(firstSuggestion).toContain('Administrator');
|
|
expect(firstSuggestion).toContain('@root');
|
|
});
|
|
|
|
it('does not show current user while searching', async () => {
|
|
wrapper.findComponent(BaseToken).vm.handleInput({ data: 'foo' });
|
|
|
|
await wrapper.vm.$nextTick();
|
|
|
|
expect(wrapper.findComponent(GlFilteredSearchSuggestion).exists()).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|