diff options
Diffstat (limited to 'spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js')
-rw-r--r-- | spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js new file mode 100644 index 00000000000..2537b8fb816 --- /dev/null +++ b/spec/frontend/analytics/shared/components/projects_dropdown_filter_spec.js @@ -0,0 +1,264 @@ +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import { TEST_HOST } from 'helpers/test_constants'; +import ProjectsDropdownFilter from '~/analytics/shared/components/projects_dropdown_filter.vue'; +import getProjects from '~/analytics/shared/graphql/projects.query.graphql'; + +const projects = [ + { + id: 'gid://gitlab/Project/1', + name: 'Gitlab Test', + fullPath: 'gitlab-org/gitlab-test', + avatarUrl: `${TEST_HOST}/images/home/nasa.svg`, + }, + { + id: 'gid://gitlab/Project/2', + name: 'Gitlab Shell', + fullPath: 'gitlab-org/gitlab-shell', + avatarUrl: null, + }, + { + id: 'gid://gitlab/Project/3', + name: 'Foo', + fullPath: 'gitlab-org/foo', + avatarUrl: null, + }, +]; + +const defaultMocks = { + $apollo: { + query: jest.fn().mockResolvedValue({ + data: { group: { projects: { nodes: projects } } }, + }), + }, +}; + +let spyQuery; + +describe('ProjectsDropdownFilter component', () => { + let wrapper; + + const createComponent = (props = {}) => { + spyQuery = defaultMocks.$apollo.query; + wrapper = mount(ProjectsDropdownFilter, { + mocks: { ...defaultMocks }, + propsData: { + groupId: 1, + groupNamespace: 'gitlab-org', + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findDropdown = () => wrapper.find(GlDropdown); + + const findDropdownItems = () => + findDropdown() + .findAll(GlDropdownItem) + .filter((w) => w.text() !== 'No matching results'); + + const findDropdownAtIndex = (index) => findDropdownItems().at(index); + + const findDropdownButton = () => findDropdown().find('.dropdown-toggle'); + const findDropdownButtonAvatar = () => findDropdown().find('.gl-avatar'); + const findDropdownButtonAvatarAtIndex = (index) => + findDropdownAtIndex(index).find('img.gl-avatar'); + const findDropdownButtonIdentIconAtIndex = (index) => + findDropdownAtIndex(index).find('div.gl-avatar-identicon'); + + const findDropdownNameAtIndex = (index) => + findDropdownAtIndex(index).find('[data-testid="project-name"'); + const findDropdownFullPathAtIndex = (index) => + findDropdownAtIndex(index).find('[data-testid="project-full-path"]'); + + const selectDropdownItemAtIndex = (index) => + findDropdownAtIndex(index).find('button').trigger('click'); + + const selectedIds = () => wrapper.vm.selectedProjects.map(({ id }) => id); + + describe('queryParams are applied when fetching data', () => { + beforeEach(() => { + createComponent({ + queryParams: { + first: 50, + includeSubgroups: true, + }, + }); + }); + + it('applies the correct queryParams when making an api call', async () => { + wrapper.setData({ searchTerm: 'gitlab' }); + + expect(spyQuery).toHaveBeenCalledTimes(1); + + await wrapper.vm.$nextTick(() => { + expect(spyQuery).toHaveBeenCalledWith({ + query: getProjects, + variables: { + search: 'gitlab', + groupFullPath: wrapper.vm.groupNamespace, + first: 50, + includeSubgroups: true, + }, + }); + }); + }); + }); + + describe('when passed a an array of defaultProject as prop', () => { + beforeEach(() => { + createComponent({ + defaultProjects: [projects[0]], + }); + }); + + it("displays the defaultProject's name", () => { + expect(findDropdownButton().text()).toContain(projects[0].name); + }); + + it("renders the defaultProject's avatar", () => { + expect(findDropdownButtonAvatar().exists()).toBe(true); + }); + + it('marks the defaultProject as selected', () => { + expect(findDropdownAtIndex(0).props('isChecked')).toBe(true); + }); + }); + + describe('when multiSelect is false', () => { + beforeEach(() => { + createComponent({ multiSelect: false }); + }); + + describe('displays the correct information', () => { + it('contains 3 items', () => { + expect(findDropdownItems()).toHaveLength(3); + }); + + it('renders an avatar when the project has an avatarUrl', () => { + expect(findDropdownButtonAvatarAtIndex(0).exists()).toBe(true); + expect(findDropdownButtonIdentIconAtIndex(0).exists()).toBe(false); + }); + + it("renders an identicon when the project doesn't have an avatarUrl", () => { + expect(findDropdownButtonAvatarAtIndex(1).exists()).toBe(false); + expect(findDropdownButtonIdentIconAtIndex(1).exists()).toBe(true); + }); + + it('renders the project name', () => { + projects.forEach((project, index) => { + expect(findDropdownNameAtIndex(index).text()).toBe(project.name); + }); + }); + + it('renders the project fullPath', () => { + projects.forEach((project, index) => { + expect(findDropdownFullPathAtIndex(index).text()).toBe(project.fullPath); + }); + }); + }); + + describe('on project click', () => { + it('should emit the "selected" event with the selected project', () => { + selectDropdownItemAtIndex(0); + + expect(wrapper.emitted().selected).toEqual([[[projects[0]]]]); + }); + + it('should change selection when new project is clicked', () => { + selectDropdownItemAtIndex(1); + + expect(wrapper.emitted().selected).toEqual([[[projects[1]]]]); + }); + + it('selection should be emptied when a project is deselected', () => { + selectDropdownItemAtIndex(0); // Select the item + selectDropdownItemAtIndex(0); // deselect it + + expect(wrapper.emitted().selected).toEqual([[[projects[0]]], [[]]]); + }); + + it('renders an avatar in the dropdown button when the project has an avatarUrl', async () => { + selectDropdownItemAtIndex(0); + + await wrapper.vm.$nextTick().then(() => { + expect(findDropdownButtonAvatarAtIndex(0).exists()).toBe(true); + expect(findDropdownButtonIdentIconAtIndex(0).exists()).toBe(false); + }); + }); + + it("renders an identicon in the dropdown button when the project doesn't have an avatarUrl", async () => { + selectDropdownItemAtIndex(1); + + await wrapper.vm.$nextTick().then(() => { + expect(findDropdownButtonAvatarAtIndex(1).exists()).toBe(false); + expect(findDropdownButtonIdentIconAtIndex(1).exists()).toBe(true); + }); + }); + }); + }); + + describe('when multiSelect is true', () => { + beforeEach(() => { + createComponent({ multiSelect: true }); + }); + + describe('displays the correct information', () => { + it('contains 3 items', () => { + expect(findDropdownItems()).toHaveLength(3); + }); + + it('renders an avatar when the project has an avatarUrl', () => { + expect(findDropdownButtonAvatarAtIndex(0).exists()).toBe(true); + expect(findDropdownButtonIdentIconAtIndex(0).exists()).toBe(false); + }); + + it("renders an identicon when the project doesn't have an avatarUrl", () => { + expect(findDropdownButtonAvatarAtIndex(1).exists()).toBe(false); + expect(findDropdownButtonIdentIconAtIndex(1).exists()).toBe(true); + }); + + it('renders the project name', () => { + projects.forEach((project, index) => { + expect(findDropdownNameAtIndex(index).text()).toBe(project.name); + }); + }); + + it('renders the project fullPath', () => { + projects.forEach((project, index) => { + expect(findDropdownFullPathAtIndex(index).text()).toBe(project.fullPath); + }); + }); + }); + + describe('on project click', () => { + it('should add to selection when new project is clicked', () => { + selectDropdownItemAtIndex(0); + selectDropdownItemAtIndex(1); + + expect(selectedIds()).toEqual([projects[0].id, projects[1].id]); + }); + + it('should remove from selection when clicked again', () => { + selectDropdownItemAtIndex(0); + expect(selectedIds()).toEqual([projects[0].id]); + + selectDropdownItemAtIndex(0); + expect(selectedIds()).toEqual([]); + }); + + it('renders the correct placeholder text when multiple projects are selected', async () => { + selectDropdownItemAtIndex(0); + selectDropdownItemAtIndex(1); + + await wrapper.vm.$nextTick().then(() => { + expect(findDropdownButton().text()).toBe('2 projects selected'); + }); + }); + }); + }); +}); |