debian-mirror-gitlab/spec/frontend/projects/new/components/new_project_url_select_spec.js
2021-12-11 22:18:48 +05:30

261 lines
7.9 KiB
JavaScript

import {
GlButton,
GlDropdown,
GlDropdownItem,
GlDropdownSectionHeader,
GlSearchBoxByType,
} from '@gitlab/ui';
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import eventHub from '~/projects/new/event_hub';
import NewProjectUrlSelect from '~/projects/new/components/new_project_url_select.vue';
import searchQuery from '~/projects/new/queries/search_namespaces_where_user_can_create_projects.query.graphql';
describe('NewProjectUrlSelect component', () => {
let wrapper;
const data = {
currentUser: {
groups: {
nodes: [
{
id: 'gid://gitlab/Group/26',
fullPath: 'flightjs',
name: 'Flight JS',
visibility: 'public',
webUrl: 'http://127.0.0.1:3000/flightjs',
},
{
id: 'gid://gitlab/Group/28',
fullPath: 'h5bp',
name: 'H5BP',
visibility: 'public',
webUrl: 'http://127.0.0.1:3000/h5bp',
},
{
id: 'gid://gitlab/Group/30',
fullPath: 'h5bp/subgroup',
name: 'H5BP Subgroup',
visibility: 'private',
webUrl: 'http://127.0.0.1:3000/h5bp/subgroup',
},
],
},
namespace: {
id: 'gid://gitlab/Namespace/1',
fullPath: 'root',
},
},
};
const localVue = createLocalVue();
localVue.use(VueApollo);
const defaultProvide = {
namespaceFullPath: 'h5bp',
namespaceId: '28',
rootUrl: 'https://gitlab.com/',
trackLabel: 'blank_project',
userNamespaceFullPath: 'root',
userNamespaceId: '1',
};
const mountComponent = ({
search = '',
queryResponse = data,
provide = defaultProvide,
mountFn = shallowMount,
} = {}) => {
const requestHandlers = [[searchQuery, jest.fn().mockResolvedValue({ data: queryResponse })]];
const apolloProvider = createMockApollo(requestHandlers);
return mountFn(NewProjectUrlSelect, {
localVue,
apolloProvider,
provide,
data() {
return {
search,
};
},
});
};
const findButtonLabel = () => wrapper.findComponent(GlButton);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findInput = () => wrapper.findComponent(GlSearchBoxByType);
const findHiddenInput = () => wrapper.find('input');
const clickDropdownItem = async () => {
wrapper.findComponent(GlDropdownItem).vm.$emit('click');
await wrapper.vm.$nextTick();
};
afterEach(() => {
wrapper.destroy();
});
it('renders the root url as a label', () => {
wrapper = mountComponent();
expect(findButtonLabel().text()).toBe(defaultProvide.rootUrl);
expect(findButtonLabel().props('label')).toBe(true);
});
describe('when namespaceId is provided', () => {
beforeEach(() => {
wrapper = mountComponent();
});
it('renders a dropdown with the given namespace full path as the text', () => {
expect(findDropdown().props('text')).toBe(defaultProvide.namespaceFullPath);
});
it('renders a dropdown with the given namespace id in the hidden input', () => {
expect(findHiddenInput().attributes('value')).toBe(defaultProvide.namespaceId);
});
});
describe('when namespaceId is not provided', () => {
const provide = {
...defaultProvide,
namespaceFullPath: undefined,
namespaceId: undefined,
};
beforeEach(() => {
wrapper = mountComponent({ provide });
});
it("renders a dropdown with the user's namespace full path as the text", () => {
expect(findDropdown().props('text')).toBe(defaultProvide.userNamespaceFullPath);
});
it("renders a dropdown with the user's namespace id in the hidden input", () => {
expect(findHiddenInput().attributes('value')).toBe(defaultProvide.userNamespaceId);
});
});
it('focuses on the input when the dropdown is opened', async () => {
wrapper = mountComponent({ mountFn: mount });
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
const spy = jest.spyOn(findInput().vm, 'focusInput');
findDropdown().vm.$emit('shown');
expect(spy).toHaveBeenCalledTimes(1);
});
it('renders expected dropdown items', async () => {
wrapper = mountComponent({ mountFn: mount });
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
const listItems = wrapper.findAll('li');
expect(listItems).toHaveLength(6);
expect(listItems.at(0).findComponent(GlDropdownSectionHeader).text()).toBe('Groups');
expect(listItems.at(1).text()).toBe(data.currentUser.groups.nodes[0].fullPath);
expect(listItems.at(2).text()).toBe(data.currentUser.groups.nodes[1].fullPath);
expect(listItems.at(3).text()).toBe(data.currentUser.groups.nodes[2].fullPath);
expect(listItems.at(4).findComponent(GlDropdownSectionHeader).text()).toBe('Users');
expect(listItems.at(5).text()).toBe(data.currentUser.namespace.fullPath);
});
describe('when selecting from a group template', () => {
const groupId = getIdFromGraphQLId(data.currentUser.groups.nodes[1].id);
beforeEach(async () => {
wrapper = mountComponent({ mountFn: mount });
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
eventHub.$emit('select-template', groupId);
});
it('filters the dropdown items to the selected group and children', async () => {
const listItems = wrapper.findAll('li');
expect(listItems).toHaveLength(3);
expect(listItems.at(0).findComponent(GlDropdownSectionHeader).text()).toBe('Groups');
expect(listItems.at(1).text()).toBe(data.currentUser.groups.nodes[1].fullPath);
expect(listItems.at(2).text()).toBe(data.currentUser.groups.nodes[2].fullPath);
});
it('sets the selection to the group', async () => {
expect(findDropdown().props('text')).toBe(data.currentUser.groups.nodes[1].fullPath);
});
});
it('renders `No matches found` when there are no matching dropdown items', async () => {
const queryResponse = {
currentUser: {
groups: {
nodes: [],
},
namespace: {
id: 'gid://gitlab/Namespace/1',
fullPath: 'root',
},
},
};
wrapper = mountComponent({ search: 'no matches', queryResponse, mountFn: mount });
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
expect(wrapper.find('li').text()).toBe('No matches found');
});
it('emits `update-visibility` event to update the visibility radio options', async () => {
wrapper = mountComponent();
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
const spy = jest.spyOn(eventHub, '$emit');
await clickDropdownItem();
const namespace = data.currentUser.groups.nodes[0];
expect(spy).toHaveBeenCalledWith('update-visibility', {
name: namespace.name,
visibility: namespace.visibility,
showPath: namespace.webUrl,
editPath: `${namespace.webUrl}/-/edit`,
});
});
it('updates hidden input with selected namespace', async () => {
wrapper = mountComponent();
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
await clickDropdownItem();
expect(findHiddenInput().attributes()).toMatchObject({
name: 'project[namespace_id]',
value: getIdFromGraphQLId(data.currentUser.groups.nodes[0].id).toString(),
});
});
it('tracks clicking on the dropdown', () => {
wrapper = mountComponent();
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
findDropdown().vm.$emit('show');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'activate_form_input', {
label: defaultProvide.trackLabel,
property: 'project_path',
});
unmockTracking();
});
});