diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 09:55:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 09:55:51 +0000 |
commit | e8d2c2579383897a1dd7f9debd359abe8ae8373d (patch) | |
tree | c42be41678c2586d49a75cabce89322082698334 /spec/frontend/jira_connect | |
parent | fc845b37ec3a90aaa719975f607740c22ba6a113 (diff) | |
download | gitlab-ce-e8d2c2579383897a1dd7f9debd359abe8ae8373d.tar.gz |
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'spec/frontend/jira_connect')
3 files changed, 377 insertions, 1 deletions
diff --git a/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js new file mode 100644 index 00000000000..ec4cb2739f8 --- /dev/null +++ b/spec/frontend/jira_connect/branches/components/project_dropdown_spec.js @@ -0,0 +1,180 @@ +import { GlDropdown, GlDropdownItem, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui'; +import { mount, shallowMount, createLocalVue } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import ProjectDropdown from '~/jira_connect/branches/components/project_dropdown.vue'; +import { PROJECTS_PER_PAGE } from '~/jira_connect/branches/constants'; +import getProjectsQuery from '~/jira_connect/branches/graphql/queries/get_projects.query.graphql'; + +const localVue = createLocalVue(); + +const mockProjects = [ + { + id: 'test', + name: 'test', + nameWithNamespace: 'test', + avatarUrl: 'https://gitlab.com', + path: 'test-path', + fullPath: 'test-path', + repository: { + empty: false, + }, + }, + { + id: 'gitlab', + name: 'GitLab', + nameWithNamespace: 'gitlab-org/gitlab', + avatarUrl: 'https://gitlab.com', + path: 'gitlab', + fullPath: 'gitlab-org/gitlab', + repository: { + empty: false, + }, + }, +]; + +const mockProjectsQueryResponse = { + data: { + projects: { + nodes: mockProjects, + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + startCursor: '', + endCursor: '', + }, + }, + }, +}; +const mockGetProjectsQuerySuccess = jest.fn().mockResolvedValue(mockProjectsQueryResponse); +const mockGetProjectsQueryFailed = jest.fn().mockRejectedValue(new Error('GraphQL error')); +const mockQueryLoading = jest.fn().mockReturnValue(new Promise(() => {})); + +describe('ProjectDropdown', () => { + let wrapper; + + const findDropdown = () => wrapper.findComponent(GlDropdown); + const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findDropdownItemByText = (text) => + findAllDropdownItems().wrappers.find((item) => item.text() === text); + const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + + function createMockApolloProvider({ mockGetProjectsQuery = mockGetProjectsQuerySuccess } = {}) { + localVue.use(VueApollo); + + const mockApollo = createMockApollo([[getProjectsQuery, mockGetProjectsQuery]]); + + return mockApollo; + } + + function createComponent({ mockApollo, props, mountFn = shallowMount } = {}) { + wrapper = mountFn(ProjectDropdown, { + localVue, + apolloProvider: mockApollo || createMockApolloProvider(), + propsData: props, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when loading projects', () => { + beforeEach(() => { + createComponent({ + mockApollo: createMockApolloProvider({ mockGetProjectsQuery: mockQueryLoading }), + }); + }); + + it('sets dropdown `loading` prop to `true`', () => { + expect(findDropdown().props('loading')).toBe(true); + }); + + it('renders loading icon in dropdown', () => { + expect(findLoadingIcon().isVisible()).toBe(true); + }); + }); + + describe('when projects query succeeds', () => { + beforeEach(async () => { + createComponent(); + await waitForPromises(); + await wrapper.vm.$nextTick(); + }); + + it('sets dropdown `loading` prop to `false`', () => { + expect(findDropdown().props('loading')).toBe(false); + }); + + it('renders dropdown items', () => { + const dropdownItems = findAllDropdownItems(); + expect(dropdownItems.wrappers).toHaveLength(mockProjects.length); + expect(dropdownItems.wrappers.map((item) => item.text())).toEqual( + mockProjects.map((project) => project.nameWithNamespace), + ); + }); + + describe('when selecting a dropdown item', () => { + it('emits `change` event with the selected project name', async () => { + const mockProject = mockProjects[0]; + const itemToSelect = findDropdownItemByText(mockProject.nameWithNamespace); + await itemToSelect.vm.$emit('click'); + + expect(wrapper.emitted('change')[0]).toEqual([mockProject]); + }); + }); + + describe('when `selectedProject` prop is specified', () => { + const mockProject = mockProjects[0]; + + beforeEach(async () => { + wrapper.setProps({ + selectedProject: mockProject, + }); + }); + + it('sets `isChecked` prop of the corresponding dropdown item to `true`', () => { + expect(findDropdownItemByText(mockProject.nameWithNamespace).props('isChecked')).toBe(true); + }); + + it('sets dropdown text to `selectedBranchName` value', () => { + expect(findDropdown().props('text')).toBe(mockProject.nameWithNamespace); + }); + }); + }); + + describe('when projects query fails', () => { + beforeEach(async () => { + createComponent({ + mockApollo: createMockApolloProvider({ mockGetProjectsQuery: mockGetProjectsQueryFailed }), + }); + await waitForPromises(); + }); + + it('emits `error` event', () => { + expect(wrapper.emitted('error')).toBeTruthy(); + }); + }); + + describe('when searching branches', () => { + it('triggers a refetch', async () => { + createComponent({ mountFn: mount }); + await waitForPromises(); + jest.clearAllMocks(); + + const mockSearchTerm = 'gitl'; + await findSearchBox().vm.$emit('input', mockSearchTerm); + + expect(mockGetProjectsQuerySuccess).toHaveBeenCalledWith({ + after: '', + first: PROJECTS_PER_PAGE, + membership: true, + search: mockSearchTerm, + searchNamespaces: true, + sort: 'similarity', + }); + }); + }); +}); diff --git a/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js b/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js new file mode 100644 index 00000000000..9dd11dd6345 --- /dev/null +++ b/spec/frontend/jira_connect/branches/components/source_branch_dropdown_spec.js @@ -0,0 +1,192 @@ +import { GlDropdown, GlDropdownItem, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui'; +import { mount, shallowMount, createLocalVue } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import SourceBranchDropdown from '~/jira_connect/branches/components/source_branch_dropdown.vue'; +import { BRANCHES_PER_PAGE } from '~/jira_connect/branches/constants'; +import getProjectQuery from '~/jira_connect/branches/graphql/queries/get_project.query.graphql'; + +const localVue = createLocalVue(); + +const mockProject = { + id: 'test', + fullPath: 'test-path', + repository: { + branchNames: ['main', 'f-test', 'release'], + rootRef: 'main', + }, +}; + +const mockProjectQueryResponse = { + data: { + project: mockProject, + }, +}; +const mockGetProjectQuery = jest.fn().mockResolvedValue(mockProjectQueryResponse); +const mockQueryLoading = jest.fn().mockReturnValue(new Promise(() => {})); + +describe('SourceBranchDropdown', () => { + let wrapper; + + const findDropdown = () => wrapper.findComponent(GlDropdown); + const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findDropdownItemByText = (text) => + findAllDropdownItems().wrappers.find((item) => item.text() === text); + const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + + const assertDropdownItems = () => { + const dropdownItems = findAllDropdownItems(); + expect(dropdownItems.wrappers).toHaveLength(mockProject.repository.branchNames.length); + expect(dropdownItems.wrappers.map((item) => item.text())).toEqual( + mockProject.repository.branchNames, + ); + }; + + function createMockApolloProvider({ getProjectQueryLoading = false } = {}) { + localVue.use(VueApollo); + + const mockApollo = createMockApollo([ + [getProjectQuery, getProjectQueryLoading ? mockQueryLoading : mockGetProjectQuery], + ]); + + return mockApollo; + } + + function createComponent({ mockApollo, props, mountFn = shallowMount } = {}) { + wrapper = mountFn(SourceBranchDropdown, { + localVue, + apolloProvider: mockApollo || createMockApolloProvider(), + propsData: props, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + describe('when `selectedProject` prop is not specified', () => { + beforeEach(() => { + createComponent(); + }); + + it('sets dropdown `disabled` prop to `true`', () => { + expect(findDropdown().props('disabled')).toBe(true); + }); + + describe('when `selectedProject` becomes specified', () => { + beforeEach(async () => { + wrapper.setProps({ + selectedProject: mockProject, + }); + + await waitForPromises(); + }); + + it('sets dropdown props correctly', () => { + expect(findDropdown().props()).toMatchObject({ + loading: false, + disabled: false, + text: 'Select a branch', + }); + }); + + it('renders available source branches as dropdown items', () => { + assertDropdownItems(); + }); + }); + }); + + describe('when `selectedProject` prop is specified', () => { + describe('when branches are loading', () => { + it('renders loading icon in dropdown', () => { + createComponent({ + mockApollo: createMockApolloProvider({ getProjectQueryLoading: true }), + props: { selectedProject: mockProject }, + }); + + expect(findLoadingIcon().isVisible()).toBe(true); + }); + }); + + describe('when branches have loaded', () => { + describe('when searching branches', () => { + it('triggers a refetch', async () => { + createComponent({ mountFn: mount, props: { selectedProject: mockProject } }); + await waitForPromises(); + jest.clearAllMocks(); + + const mockSearchTerm = 'mai'; + await findSearchBox().vm.$emit('input', mockSearchTerm); + + expect(mockGetProjectQuery).toHaveBeenCalledWith({ + branchNamesLimit: BRANCHES_PER_PAGE, + branchNamesOffset: 0, + branchNamesSearchPattern: `*${mockSearchTerm}*`, + projectPath: 'test-path', + }); + }); + }); + + describe('template', () => { + beforeEach(async () => { + createComponent({ props: { selectedProject: mockProject } }); + await waitForPromises(); + }); + + it('sets dropdown props correctly', () => { + expect(findDropdown().props()).toMatchObject({ + loading: false, + disabled: false, + text: 'Select a branch', + }); + }); + + it('omits monospace styling from dropdown', () => { + expect(findDropdown().classes()).not.toContain('gl-font-monospace'); + }); + + it('renders available source branches as dropdown items', () => { + assertDropdownItems(); + }); + + it("emits `change` event with the repository's `rootRef` by default", () => { + expect(wrapper.emitted('change')[0]).toEqual([mockProject.repository.rootRef]); + }); + + describe('when selecting a dropdown item', () => { + it('emits `change` event with the selected branch name', async () => { + const mockBranchName = mockProject.repository.branchNames[1]; + const itemToSelect = findDropdownItemByText(mockBranchName); + await itemToSelect.vm.$emit('click'); + + expect(wrapper.emitted('change')[1]).toEqual([mockBranchName]); + }); + }); + + describe('when `selectedBranchName` prop is specified', () => { + const mockBranchName = mockProject.repository.branchNames[2]; + + beforeEach(async () => { + wrapper.setProps({ + selectedBranchName: mockBranchName, + }); + }); + + it('sets `isChecked` prop of the corresponding dropdown item to `true`', () => { + expect(findDropdownItemByText(mockBranchName).props('isChecked')).toBe(true); + }); + + it('sets dropdown text to `selectedBranchName` value', () => { + expect(findDropdown().props('text')).toBe(mockBranchName); + }); + + it('adds monospace styling to dropdown', () => { + expect(findDropdown().classes()).toContain('gl-font-monospace'); + }); + }); + }); + }); + }); +}); diff --git a/spec/frontend/jira_connect/components/groups_list_spec.js b/spec/frontend/jira_connect/components/groups_list_spec.js index 4b875928a90..d583fb68771 100644 --- a/spec/frontend/jira_connect/components/groups_list_spec.js +++ b/spec/frontend/jira_connect/components/groups_list_spec.js @@ -160,9 +160,13 @@ describe('GroupsList', () => { expect(findGroupsList().classes()).toContain('gl-opacity-5'); }); - it('sets loading prop of ths search box', () => { + it('sets loading prop of the search box', () => { expect(findSearchBox().props('isLoading')).toBe(true); }); + + it('sets value prop of the search box to the search term', () => { + expect(findSearchBox().props('value')).toBe(mockSearchTeam); + }); }); describe('when group search finishes loading', () => { |