Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js')
-rw-r--r--spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js293
1 files changed, 258 insertions, 35 deletions
diff --git a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
index fa937100982..d6763a7de41 100644
--- a/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
+++ b/spec/frontend/pipeline_editor/components/file-nav/branch_switcher_spec.js
@@ -1,11 +1,28 @@
-import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlInfiniteScroll,
+ GlLoadingIcon,
+ 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 waitForPromises from 'helpers/wait_for_promises';
import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue';
import { DEFAULT_FAILURE } from '~/pipeline_editor/constants';
-import { mockDefaultBranch, mockProjectBranches, mockProjectFullPath } from '../../mock_data';
+import getAvailableBranches from '~/pipeline_editor/graphql/queries/available_branches.graphql';
+import {
+ mockBranchPaginationLimit,
+ mockDefaultBranch,
+ mockEmptySearchBranches,
+ mockProjectBranches,
+ mockProjectFullPath,
+ mockSearchBranches,
+ mockTotalBranches,
+ mockTotalBranchResults,
+ mockTotalSearchResults,
+} from '../../mock_data';
const localVue = createLocalVue();
localVue.use(VueApollo);
@@ -15,30 +32,64 @@ describe('Pipeline editor branch switcher', () => {
let mockApollo;
let mockAvailableBranchQuery;
- const createComponentWithApollo = () => {
- const resolvers = {
- Query: {
- project: mockAvailableBranchQuery,
+ const createComponent = (
+ { isQueryLoading, mountFn, options } = {
+ isQueryLoading: false,
+ mountFn: shallowMount,
+ options: {},
+ },
+ ) => {
+ wrapper = mountFn(BranchSwitcher, {
+ propsData: {
+ paginationLimit: mockBranchPaginationLimit,
},
- };
-
- mockApollo = createMockApollo([], resolvers);
- wrapper = shallowMount(BranchSwitcher, {
- localVue,
- apolloProvider: mockApollo,
provide: {
projectFullPath: mockProjectFullPath,
+ totalBranches: mockTotalBranches,
+ },
+ mocks: {
+ $apollo: {
+ queries: {
+ availableBranches: {
+ loading: isQueryLoading,
+ },
+ },
+ },
},
data() {
return {
+ branches: ['main'],
currentBranch: mockDefaultBranch,
};
},
+ ...options,
+ });
+ };
+
+ const createComponentWithApollo = (mountFn = shallowMount) => {
+ const handlers = [[getAvailableBranches, mockAvailableBranchQuery]];
+ mockApollo = createMockApollo(handlers);
+
+ createComponent({
+ mountFn,
+ options: {
+ localVue,
+ apolloProvider: mockApollo,
+ mocks: {},
+ data() {
+ return {
+ currentBranch: mockDefaultBranch,
+ };
+ },
+ },
});
};
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findInfiniteScroll = () => wrapper.findComponent(GlInfiniteScroll);
beforeEach(() => {
mockAvailableBranchQuery = jest.fn();
@@ -48,7 +99,7 @@ describe('Pipeline editor branch switcher', () => {
wrapper.destroy();
});
- describe('while querying', () => {
+ describe('when querying for the first time', () => {
beforeEach(() => {
createComponentWithApollo();
});
@@ -61,41 +112,31 @@ describe('Pipeline editor branch switcher', () => {
describe('after querying', () => {
beforeEach(async () => {
mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
- createComponentWithApollo();
+ createComponentWithApollo(mount);
await waitForPromises();
});
- it('query is called with correct variables', async () => {
- expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1);
- expect(mockAvailableBranchQuery).toHaveBeenCalledWith(
- expect.anything(),
- {
- fullPath: mockProjectFullPath,
- },
- expect.anything(),
- expect.anything(),
- );
+ it('renders search box', () => {
+ expect(findSearchBox().exists()).toBe(true);
});
it('renders list of branches', () => {
expect(findDropdown().exists()).toBe(true);
- expect(findDropdownItems()).toHaveLength(mockProjectBranches.repository.branches.length);
+ expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
});
- it('renders current branch at the top of the list with a check mark', () => {
- const firstDropdownItem = findDropdownItems().at(0);
- const icon = firstDropdownItem.findComponent(GlIcon);
+ it('renders current branch with a check mark', () => {
+ const defaultBranchInDropdown = findDropdownItems().at(0);
- expect(firstDropdownItem.text()).toBe(mockDefaultBranch);
- expect(icon.exists()).toBe(true);
- expect(icon.props('name')).toBe('check');
+ expect(defaultBranchInDropdown.text()).toBe(mockDefaultBranch);
+ expect(defaultBranchInDropdown.props('isChecked')).toBe(true);
});
it('does not render check mark for other branches', () => {
- const secondDropdownItem = findDropdownItems().at(1);
- const icon = secondDropdownItem.findComponent(GlIcon);
+ const nonDefaultBranch = findDropdownItems().at(1);
- expect(icon.classes()).toContain('gl-visibility-hidden');
+ expect(nonDefaultBranch.text()).not.toBe(mockDefaultBranch);
+ expect(nonDefaultBranch.props('isChecked')).toBe(false);
});
});
@@ -120,4 +161,186 @@ describe('Pipeline editor branch switcher', () => {
]);
});
});
+
+ describe('when switching branches', () => {
+ beforeEach(async () => {
+ jest.spyOn(window.history, 'pushState').mockImplementation(() => {});
+ mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
+ createComponentWithApollo(mount);
+ await waitForPromises();
+ });
+
+ it('updates session history when selecting a different branch', async () => {
+ const branch = findDropdownItems().at(1);
+ await branch.vm.$emit('click');
+
+ expect(window.history.pushState).toHaveBeenCalled();
+ expect(window.history.pushState.mock.calls[0][2]).toContain(`?branch_name=${branch.text()}`);
+ });
+
+ it('does not update session history when selecting current branch', async () => {
+ const branch = findDropdownItems().at(0);
+ await branch.vm.$emit('click');
+
+ expect(branch.text()).toBe(mockDefaultBranch);
+ expect(window.history.pushState).not.toHaveBeenCalled();
+ });
+
+ it('emits the refetchContent event when selecting a different branch', async () => {
+ const branch = findDropdownItems().at(1);
+
+ expect(branch.text()).not.toBe(mockDefaultBranch);
+ expect(wrapper.emitted('refetchContent')).toBeUndefined();
+
+ await branch.vm.$emit('click');
+
+ expect(wrapper.emitted('refetchContent')).toBeDefined();
+ expect(wrapper.emitted('refetchContent')).toHaveLength(1);
+ });
+
+ it('does not emit the refetchContent event when selecting the current branch', async () => {
+ const branch = findDropdownItems().at(0);
+
+ expect(branch.text()).toBe(mockDefaultBranch);
+ expect(wrapper.emitted('refetchContent')).toBeUndefined();
+
+ await branch.vm.$emit('click');
+
+ expect(wrapper.emitted('refetchContent')).toBeUndefined();
+ });
+ });
+
+ describe('when searching', () => {
+ beforeEach(async () => {
+ mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
+ createComponentWithApollo(mount);
+ await waitForPromises();
+
+ mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches);
+ });
+
+ describe('with a search term', () => {
+ it('calls query with correct variables', async () => {
+ findSearchBox().vm.$emit('input', 'te');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
+ limit: mockTotalBranches, // fetch all branches
+ offset: 0,
+ projectFullPath: mockProjectFullPath,
+ searchPattern: '*te*',
+ });
+ });
+
+ it('fetches new list of branches', async () => {
+ expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
+
+ findSearchBox().vm.$emit('input', 'te');
+ await waitForPromises();
+
+ expect(findDropdownItems()).toHaveLength(mockTotalSearchResults);
+ });
+
+ it('does not hide dropdown when search result is empty', async () => {
+ mockAvailableBranchQuery.mockResolvedValue(mockEmptySearchBranches);
+ findSearchBox().vm.$emit('input', 'aaaaa');
+ await waitForPromises();
+
+ expect(findDropdown().exists()).toBe(true);
+ expect(findDropdownItems()).toHaveLength(0);
+ });
+ });
+
+ describe('without a search term', () => {
+ beforeEach(async () => {
+ findSearchBox().vm.$emit('input', 'te');
+ await waitForPromises();
+
+ mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
+ });
+
+ it('calls query with correct variables', async () => {
+ findSearchBox().vm.$emit('input', '');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
+ limit: mockBranchPaginationLimit, // only fetch first n branches first
+ offset: 0,
+ projectFullPath: mockProjectFullPath,
+ searchPattern: '*',
+ });
+ });
+
+ it('fetches new list of branches', async () => {
+ expect(findDropdownItems()).toHaveLength(mockTotalSearchResults);
+
+ findSearchBox().vm.$emit('input', '');
+ await waitForPromises();
+
+ expect(findDropdownItems()).toHaveLength(mockTotalBranchResults);
+ });
+ });
+ });
+
+ describe('loading icon', () => {
+ test.each`
+ isQueryLoading | isRendered
+ ${true} | ${true}
+ ${false} | ${false}
+ `('checks if query is loading before rendering', ({ isQueryLoading, isRendered }) => {
+ createComponent({ isQueryLoading, mountFn: mount });
+
+ expect(findLoadingIcon().exists()).toBe(isRendered);
+ });
+ });
+
+ describe('when scrolling to the bottom of the list', () => {
+ beforeEach(async () => {
+ mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
+ createComponentWithApollo();
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ mockAvailableBranchQuery.mockClear();
+ });
+
+ describe('when search term is empty', () => {
+ it('fetches more branches', async () => {
+ expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(1);
+
+ findInfiniteScroll().vm.$emit('bottomReached');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2);
+ });
+
+ it('calls the query with the correct variables', async () => {
+ findInfiniteScroll().vm.$emit('bottomReached');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).toHaveBeenCalledWith({
+ limit: mockBranchPaginationLimit,
+ offset: mockBranchPaginationLimit, // offset changed
+ projectFullPath: mockProjectFullPath,
+ searchPattern: '*',
+ });
+ });
+ });
+
+ describe('when search term exists', () => {
+ it('does not fetch more branches', async () => {
+ findSearchBox().vm.$emit('input', 'te');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).toHaveBeenCalledTimes(2);
+ mockAvailableBranchQuery.mockClear();
+
+ findInfiniteScroll().vm.$emit('bottomReached');
+ await waitForPromises();
+
+ expect(mockAvailableBranchQuery).not.toHaveBeenCalled();
+ });
+ });
+ });
});