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/projects')
-rw-r--r--spec/frontend/projects/commit/components/form_modal_spec.js20
-rw-r--r--spec/frontend/projects/commit/components/projects_dropdown_spec.js124
-rw-r--r--spec/frontend/projects/commit/mock_data.js1
-rw-r--r--spec/frontend/projects/commit/store/actions_spec.js41
-rw-r--r--spec/frontend/projects/commit/store/getters_spec.js17
-rw-r--r--spec/frontend/projects/commit/store/mutations_spec.js20
-rw-r--r--spec/frontend/projects/compare/components/app_legacy_spec.js116
-rw-r--r--spec/frontend/projects/compare/components/app_spec.js10
-rw-r--r--spec/frontend/projects/compare/components/repo_dropdown_spec.js98
-rw-r--r--spec/frontend/projects/compare/components/revision_card_spec.js49
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js106
-rw-r--r--spec/frontend/projects/compare/components/revision_dropdown_spec.js18
-rw-r--r--spec/frontend/projects/details/upload_button_spec.js61
-rw-r--r--spec/frontend/projects/experiment_new_project_creation/components/new_project_push_tip_popover_spec.js75
-rw-r--r--spec/frontend/projects/experiment_new_project_creation/components/welcome_spec.js10
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js2
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js2
-rw-r--r--spec/frontend/projects/upload_file_experiment_tracking_spec.js43
18 files changed, 800 insertions, 13 deletions
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
index 1569f5b4bbe..708644cb7ee 100644
--- a/spec/frontend/projects/commit/components/form_modal_spec.js
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -7,6 +7,7 @@ import axios from '~/lib/utils/axios_utils';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue';
import CommitFormModal from '~/projects/commit/components/form_modal.vue';
+import ProjectsDropdown from '~/projects/commit/components/projects_dropdown.vue';
import eventHub from '~/projects/commit/event_hub';
import createStore from '~/projects/commit/store';
import mockData from '../mock_data';
@@ -20,7 +21,10 @@ describe('CommitFormModal', () => {
store = createStore({ ...mockData.mockModal, ...state });
wrapper = extendedWrapper(
method(CommitFormModal, {
- provide,
+ provide: {
+ ...provide,
+ glFeatures: { pickIntoProject: true },
+ },
propsData: { ...mockData.modalPropsData },
store,
attrs: {
@@ -33,7 +37,9 @@ describe('CommitFormModal', () => {
const findModal = () => wrapper.findComponent(GlModal);
const findStartBranch = () => wrapper.find('#start_branch');
- const findDropdown = () => wrapper.findComponent(BranchesDropdown);
+ const findTargetProject = () => wrapper.find('#target_project_id');
+ const findBranchesDropdown = () => wrapper.findComponent(BranchesDropdown);
+ const findProjectsDropdown = () => wrapper.findComponent(ProjectsDropdown);
const findForm = () => findModal().findComponent(GlForm);
const findCheckBox = () => findForm().findComponent(GlFormCheckbox);
const findPrependedText = () => wrapper.findByTestId('prepended-text');
@@ -146,11 +152,19 @@ describe('CommitFormModal', () => {
});
it('Changes the start_branch input value', async () => {
- findDropdown().vm.$emit('selectBranch', '_changed_branch_value_');
+ findBranchesDropdown().vm.$emit('selectBranch', '_changed_branch_value_');
await wrapper.vm.$nextTick();
expect(findStartBranch().attributes('value')).toBe('_changed_branch_value_');
});
+
+ it('Changes the target_project_id input value', async () => {
+ findProjectsDropdown().vm.$emit('selectProject', '_changed_project_value_');
+
+ await wrapper.vm.$nextTick();
+
+ expect(findTargetProject().attributes('value')).toBe('_changed_project_value_');
+ });
});
});
diff --git a/spec/frontend/projects/commit/components/projects_dropdown_spec.js b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
new file mode 100644
index 00000000000..bb20918e0cd
--- /dev/null
+++ b/spec/frontend/projects/commit/components/projects_dropdown_spec.js
@@ -0,0 +1,124 @@
+import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import ProjectsDropdown from '~/projects/commit/components/projects_dropdown.vue';
+
+Vue.use(Vuex);
+
+describe('ProjectsDropdown', () => {
+ let wrapper;
+ let store;
+ const spyFetchProjects = jest.fn();
+ const projectsMockData = [
+ { id: '1', name: '_project_1_', refsUrl: '_project_1_/refs' },
+ { id: '2', name: '_project_2_', refsUrl: '_project_2_/refs' },
+ { id: '3', name: '_project_3_', refsUrl: '_project_3_/refs' },
+ ];
+
+ const createComponent = (term, state = {}) => {
+ store = new Vuex.Store({
+ getters: {
+ sortedProjects: () => projectsMockData,
+ },
+ state,
+ });
+
+ wrapper = extendedWrapper(
+ shallowMount(ProjectsDropdown, {
+ store,
+ propsData: {
+ value: term,
+ },
+ }),
+ );
+ };
+
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
+ const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
+ const findNoResults = () => wrapper.findByTestId('empty-result-message');
+
+ afterEach(() => {
+ wrapper.destroy();
+ spyFetchProjects.mockReset();
+ });
+
+ describe('No projects found', () => {
+ beforeEach(() => {
+ createComponent('_non_existent_project_');
+ });
+
+ it('renders empty results message', () => {
+ expect(findNoResults().text()).toBe('No matching results');
+ });
+
+ it('shows GlSearchBoxByType with default attributes', () => {
+ expect(findSearchBoxByType().exists()).toBe(true);
+ expect(findSearchBoxByType().vm.$attrs).toMatchObject({
+ placeholder: 'Search projects',
+ });
+ });
+ });
+
+ describe('Search term is empty', () => {
+ beforeEach(() => {
+ createComponent('');
+ });
+
+ it('renders all projects when search term is empty', () => {
+ expect(findAllDropdownItems()).toHaveLength(3);
+ expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
+ expect(findDropdownItemByIndex(1).text()).toBe('_project_2_');
+ expect(findDropdownItemByIndex(2).text()).toBe('_project_3_');
+ });
+
+ it('should not be selected on the inactive project', () => {
+ expect(wrapper.vm.isSelected('_project_1_')).toBe(false);
+ });
+ });
+
+ describe('Projects found', () => {
+ beforeEach(() => {
+ createComponent('_project_1_', { targetProjectId: '1' });
+ });
+
+ it('renders only the project searched for', () => {
+ expect(findAllDropdownItems()).toHaveLength(1);
+ expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
+ });
+
+ it('should not display empty results message', () => {
+ expect(findNoResults().exists()).toBe(false);
+ });
+
+ it('should signify this project is selected', () => {
+ expect(findDropdownItemByIndex(0).props('isChecked')).toBe(true);
+ });
+
+ it('should signify the project is not selected', () => {
+ expect(wrapper.vm.isSelected('_not_selected_project_')).toBe(false);
+ });
+
+ describe('Custom events', () => {
+ it('should emit selectProject if a project is clicked', () => {
+ findDropdownItemByIndex(0).vm.$emit('click');
+
+ expect(wrapper.emitted('selectProject')).toEqual([['1']]);
+ expect(wrapper.vm.filterTerm).toBe('_project_1_');
+ });
+ });
+ });
+
+ describe('Case insensitive for search term', () => {
+ beforeEach(() => {
+ createComponent('_PrOjEcT_1_');
+ });
+
+ it('renders only the project searched for', () => {
+ expect(findAllDropdownItems()).toHaveLength(1);
+ expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/mock_data.js b/spec/frontend/projects/commit/mock_data.js
index 2b3b5a14c98..e4dcb24c4c0 100644
--- a/spec/frontend/projects/commit/mock_data.js
+++ b/spec/frontend/projects/commit/mock_data.js
@@ -24,4 +24,5 @@ export default {
openModal: '_open_modal_',
},
mockBranches: ['_branch_1', '_abc_', '_master_'],
+ mockProjects: ['_project_1', '_abc_', '_project_'],
};
diff --git a/spec/frontend/projects/commit/store/actions_spec.js b/spec/frontend/projects/commit/store/actions_spec.js
index 458372229cf..305257c9ca5 100644
--- a/spec/frontend/projects/commit/store/actions_spec.js
+++ b/spec/frontend/projects/commit/store/actions_spec.js
@@ -47,7 +47,7 @@ describe('Commit form modal store actions', () => {
it('dispatch correct actions on fetchBranches', (done) => {
jest
.spyOn(axios, 'get')
- .mockImplementation(() => Promise.resolve({ data: mockData.mockBranches }));
+ .mockImplementation(() => Promise.resolve({ data: { Branches: mockData.mockBranches } }));
testAction(
actions.fetchBranches,
@@ -108,4 +108,43 @@ describe('Commit form modal store actions', () => {
]);
});
});
+
+ describe('setBranchesEndpoint', () => {
+ it('commits SET_BRANCHES_ENDPOINT mutation', () => {
+ const endpoint = 'some/endpoint';
+
+ testAction(actions.setBranchesEndpoint, endpoint, {}, [
+ {
+ type: types.SET_BRANCHES_ENDPOINT,
+ payload: endpoint,
+ },
+ ]);
+ });
+ });
+
+ describe('setSelectedProject', () => {
+ const id = 1;
+
+ it('commits SET_SELECTED_PROJECT mutation', () => {
+ testAction(
+ actions.setSelectedProject,
+ id,
+ {},
+ [
+ {
+ type: types.SET_SELECTED_PROJECT,
+ payload: id,
+ },
+ ],
+ [
+ {
+ type: 'setBranchesEndpoint',
+ },
+ {
+ type: 'fetchBranches',
+ },
+ ],
+ );
+ });
+ });
});
diff --git a/spec/frontend/projects/commit/store/getters_spec.js b/spec/frontend/projects/commit/store/getters_spec.js
index bd0cb356854..38c45af7aa0 100644
--- a/spec/frontend/projects/commit/store/getters_spec.js
+++ b/spec/frontend/projects/commit/store/getters_spec.js
@@ -18,4 +18,21 @@ describe('Commit form modal getters', () => {
expect(getters.joinedBranches(state)).toEqual(branches.slice(1));
});
});
+
+ describe('sortedProjects', () => {
+ it('should sort projects with variable branches', () => {
+ const state = {
+ projects: mockData.mockProjects,
+ };
+
+ expect(getters.sortedProjects(state)).toEqual(mockData.mockProjects.sort());
+ });
+
+ it('should provide a uniq list of projects', () => {
+ const projects = ['_project_', '_project_', '_some_other_project'];
+ const state = { projects };
+
+ expect(getters.sortedProjects(state)).toEqual(projects.slice(1));
+ });
+ });
});
diff --git a/spec/frontend/projects/commit/store/mutations_spec.js b/spec/frontend/projects/commit/store/mutations_spec.js
index 2ea50e71772..8989e769772 100644
--- a/spec/frontend/projects/commit/store/mutations_spec.js
+++ b/spec/frontend/projects/commit/store/mutations_spec.js
@@ -35,6 +35,16 @@ describe('Commit form modal mutations', () => {
});
});
+ describe('SET_BRANCHES_ENDPOINT', () => {
+ it('should set branchesEndpoint', () => {
+ stateCopy = { branchesEndpoint: 'endpoint/1' };
+
+ mutations[types.SET_BRANCHES_ENDPOINT](stateCopy, 'endpoint/2');
+
+ expect(stateCopy.branchesEndpoint).toBe('endpoint/2');
+ });
+ });
+
describe('SET_BRANCH', () => {
it('should set branch', () => {
stateCopy = { branch: '_master_' };
@@ -54,4 +64,14 @@ describe('Commit form modal mutations', () => {
expect(stateCopy.selectedBranch).toBe('_changed_branch_');
});
});
+
+ describe('SET_SELECTED_PROJECT', () => {
+ it('should set targetProjectId', () => {
+ stateCopy = { targetProjectId: '_project_1_' };
+
+ mutations[types.SET_SELECTED_PROJECT](stateCopy, '_project_2_');
+
+ expect(stateCopy.targetProjectId).toBe('_project_2_');
+ });
+ });
});
diff --git a/spec/frontend/projects/compare/components/app_legacy_spec.js b/spec/frontend/projects/compare/components/app_legacy_spec.js
new file mode 100644
index 00000000000..4c7f0d5cccc
--- /dev/null
+++ b/spec/frontend/projects/compare/components/app_legacy_spec.js
@@ -0,0 +1,116 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import CompareApp from '~/projects/compare/components/app_legacy.vue';
+import RevisionDropdown from '~/projects/compare/components/revision_dropdown_legacy.vue';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+const projectCompareIndexPath = 'some/path';
+const refsProjectPath = 'some/refs/path';
+const paramsFrom = 'master';
+const paramsTo = 'master';
+
+describe('CompareApp component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(CompareApp, {
+ propsData: {
+ projectCompareIndexPath,
+ refsProjectPath,
+ paramsFrom,
+ paramsTo,
+ projectMergeRequestPath: '',
+ createMrPath: '',
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders component with prop', () => {
+ expect(wrapper.props()).toEqual(
+ expect.objectContaining({
+ projectCompareIndexPath,
+ refsProjectPath,
+ paramsFrom,
+ paramsTo,
+ }),
+ );
+ });
+
+ it('contains the correct form attributes', () => {
+ expect(wrapper.attributes('action')).toBe(projectCompareIndexPath);
+ expect(wrapper.attributes('method')).toBe('POST');
+ });
+
+ it('has input with csrf token', () => {
+ expect(wrapper.find('input[name="authenticity_token"]').attributes('value')).toBe(
+ 'mock-csrf-token',
+ );
+ });
+
+ it('has ellipsis', () => {
+ expect(wrapper.find('[data-testid="ellipsis"]').exists()).toBe(true);
+ });
+
+ it('render Source and Target BranchDropdown components', () => {
+ const branchDropdowns = wrapper.findAll(RevisionDropdown);
+
+ expect(branchDropdowns.length).toBe(2);
+ expect(branchDropdowns.at(0).props('revisionText')).toBe('Source');
+ expect(branchDropdowns.at(1).props('revisionText')).toBe('Target');
+ });
+
+ describe('compare button', () => {
+ const findCompareButton = () => wrapper.find(GlButton);
+
+ it('renders button', () => {
+ expect(findCompareButton().exists()).toBe(true);
+ });
+
+ it('submits form', () => {
+ findCompareButton().vm.$emit('click');
+ expect(wrapper.find('form').element.submit).toHaveBeenCalled();
+ });
+
+ it('has compare text', () => {
+ expect(findCompareButton().text()).toBe('Compare');
+ });
+ });
+
+ describe('merge request buttons', () => {
+ const findProjectMrButton = () => wrapper.find('[data-testid="projectMrButton"]');
+ const findCreateMrButton = () => wrapper.find('[data-testid="createMrButton"]');
+
+ it('does not have merge request buttons', () => {
+ createComponent();
+ expect(findProjectMrButton().exists()).toBe(false);
+ expect(findCreateMrButton().exists()).toBe(false);
+ });
+
+ it('has "View open merge request" button', () => {
+ createComponent({
+ projectMergeRequestPath: 'some/project/merge/request/path',
+ });
+ expect(findProjectMrButton().exists()).toBe(true);
+ expect(findCreateMrButton().exists()).toBe(false);
+ });
+
+ it('has "Create merge request" button', () => {
+ createComponent({
+ createMrPath: 'some/create/create/mr/path',
+ });
+ expect(findProjectMrButton().exists()).toBe(false);
+ expect(findCreateMrButton().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js
index d28a30e93b1..6de06e4373c 100644
--- a/spec/frontend/projects/compare/components/app_spec.js
+++ b/spec/frontend/projects/compare/components/app_spec.js
@@ -1,7 +1,7 @@
import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import CompareApp from '~/projects/compare/components/app.vue';
-import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue';
+import RevisionCard from '~/projects/compare/components/revision_card.vue';
jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
@@ -63,11 +63,11 @@ describe('CompareApp component', () => {
});
it('render Source and Target BranchDropdown components', () => {
- const branchDropdowns = wrapper.findAll(RevisionDropdown);
+ const revisionCards = wrapper.findAll(RevisionCard);
- expect(branchDropdowns.length).toBe(2);
- expect(branchDropdowns.at(0).props('revisionText')).toBe('Source');
- expect(branchDropdowns.at(1).props('revisionText')).toBe('Target');
+ expect(revisionCards.length).toBe(2);
+ expect(revisionCards.at(0).props('revisionText')).toBe('Source');
+ expect(revisionCards.at(1).props('revisionText')).toBe('Target');
});
describe('compare button', () => {
diff --git a/spec/frontend/projects/compare/components/repo_dropdown_spec.js b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
new file mode 100644
index 00000000000..af76632515c
--- /dev/null
+++ b/spec/frontend/projects/compare/components/repo_dropdown_spec.js
@@ -0,0 +1,98 @@
+import { GlDropdown } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RepoDropdown from '~/projects/compare/components/repo_dropdown.vue';
+
+const defaultProps = {
+ paramsName: 'to',
+};
+
+const projectToId = '1';
+const projectToName = 'some-to-name';
+const projectFromId = '2';
+const projectFromName = 'some-from-name';
+
+const defaultProvide = {
+ projectTo: { id: projectToId, name: projectToName },
+ projectsFrom: [
+ { id: projectFromId, name: projectFromName },
+ { id: 3, name: 'some-from-another-name' },
+ ],
+};
+
+describe('RepoDropdown component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}, provide = {}) => {
+ wrapper = shallowMount(RepoDropdown, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findGlDropdown = () => wrapper.find(GlDropdown);
+ const findHiddenInput = () => wrapper.find('input[type="hidden"]');
+
+ describe('Source Revision', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('set hidden input', () => {
+ expect(findHiddenInput().attributes('value')).toBe(projectToId);
+ });
+
+ it('displays the project name in the disabled dropdown', () => {
+ expect(findGlDropdown().props('text')).toBe(projectToName);
+ expect(findGlDropdown().props('disabled')).toBe(true);
+ });
+
+ it('does not emit `changeTargetProject` event', async () => {
+ wrapper.vm.emitTargetProject('foo');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('changeTargetProject')).toBeUndefined();
+ });
+ });
+
+ describe('Target Revision', () => {
+ beforeEach(() => {
+ createComponent({ paramsName: 'from' });
+ });
+
+ it('set hidden input of the first project', () => {
+ expect(findHiddenInput().attributes('value')).toBe(projectFromId);
+ });
+
+ it('displays the first project name initially in the dropdown', () => {
+ expect(findGlDropdown().props('text')).toBe(projectFromName);
+ });
+
+ it('updates the hiddin input value when onClick method is triggered', async () => {
+ const repoId = '100';
+ wrapper.vm.onClick({ id: repoId });
+ await wrapper.vm.$nextTick();
+ expect(findHiddenInput().attributes('value')).toBe(repoId);
+ });
+
+ it('emits initial `changeTargetProject` event with target project', () => {
+ expect(wrapper.emitted('changeTargetProject')).toEqual([[projectFromName]]);
+ });
+
+ it('emits `changeTargetProject` event when another target project is selected', async () => {
+ const newTargetProject = 'new-from-name';
+ wrapper.vm.$emit('changeTargetProject', newTargetProject);
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('changeTargetProject')[1]).toEqual([newTargetProject]);
+ });
+ });
+});
diff --git a/spec/frontend/projects/compare/components/revision_card_spec.js b/spec/frontend/projects/compare/components/revision_card_spec.js
new file mode 100644
index 00000000000..83f858f4454
--- /dev/null
+++ b/spec/frontend/projects/compare/components/revision_card_spec.js
@@ -0,0 +1,49 @@
+import { GlCard } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RepoDropdown from '~/projects/compare/components/repo_dropdown.vue';
+import RevisionCard from '~/projects/compare/components/revision_card.vue';
+import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue';
+
+const defaultProps = {
+ refsProjectPath: 'some/refs/path',
+ revisionText: 'Source',
+ paramsName: 'to',
+ paramsBranch: 'master',
+};
+
+describe('RepoDropdown component', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(RevisionCard, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ stubs: {
+ GlCard,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays revision text', () => {
+ expect(wrapper.find(GlCard).text()).toContain(defaultProps.revisionText);
+ });
+
+ it('renders RepoDropdown component', () => {
+ expect(wrapper.findAll(RepoDropdown).exists()).toBe(true);
+ });
+
+ it('renders RevisionDropdown component', () => {
+ expect(wrapper.findAll(RevisionDropdown).exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
new file mode 100644
index 00000000000..270c89e674c
--- /dev/null
+++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js
@@ -0,0 +1,106 @@
+import { GlDropdown } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import AxiosMockAdapter from 'axios-mock-adapter';
+import createFlash from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import RevisionDropdown from '~/projects/compare/components/revision_dropdown_legacy.vue';
+
+const defaultProps = {
+ refsProjectPath: 'some/refs/path',
+ revisionText: 'Target',
+ paramsName: 'from',
+ paramsBranch: 'master',
+};
+
+jest.mock('~/flash');
+
+describe('RevisionDropdown component', () => {
+ let wrapper;
+ let axiosMock;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(RevisionDropdown, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ axiosMock.restore();
+ });
+
+ const findGlDropdown = () => wrapper.find(GlDropdown);
+
+ it('sets hidden input', () => {
+ createComponent();
+ expect(wrapper.find('input[type="hidden"]').attributes('value')).toBe(
+ defaultProps.paramsBranch,
+ );
+ });
+
+ it('update the branches on success', async () => {
+ const Branches = ['branch-1', 'branch-2'];
+ const Tags = ['tag-1', 'tag-2', 'tag-3'];
+
+ axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(200, {
+ Branches,
+ Tags,
+ });
+
+ createComponent();
+
+ await axios.waitForAll();
+
+ expect(wrapper.vm.branches).toEqual(Branches);
+ expect(wrapper.vm.tags).toEqual(Tags);
+ });
+
+ it('sets branches and tags to be an empty array when no tags or branches are given', async () => {
+ axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(200, {
+ Branches: undefined,
+ Tags: undefined,
+ });
+
+ createComponent();
+
+ await axios.waitForAll();
+
+ expect(wrapper.vm.branches).toEqual([]);
+ expect(wrapper.vm.tags).toEqual([]);
+ });
+
+ it('shows flash message on error', async () => {
+ axiosMock.onGet('some/invalid/path').replyOnce(404);
+
+ createComponent();
+
+ await wrapper.vm.fetchBranchesAndTags();
+ expect(createFlash).toHaveBeenCalled();
+ });
+
+ describe('GlDropdown component', () => {
+ it('renders props', () => {
+ createComponent();
+ expect(wrapper.props()).toEqual(expect.objectContaining(defaultProps));
+ });
+
+ it('display default text', () => {
+ createComponent({
+ paramsBranch: null,
+ });
+ expect(findGlDropdown().props('text')).toBe('Select branch/tag');
+ });
+
+ it('display params branch text', () => {
+ createComponent();
+ expect(findGlDropdown().props('text')).toBe(defaultProps.paramsBranch);
+ });
+ });
+});
diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
index f3ff5e26d2b..69d3167c99c 100644
--- a/spec/frontend/projects/compare/components/revision_dropdown_spec.js
+++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js
@@ -7,7 +7,6 @@ import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vu
const defaultProps = {
refsProjectPath: 'some/refs/path',
- revisionText: 'Target',
paramsName: 'from',
paramsBranch: 'master',
};
@@ -57,7 +56,6 @@ describe('RevisionDropdown component', () => {
createComponent();
await axios.waitForAll();
-
expect(wrapper.vm.branches).toEqual(Branches);
expect(wrapper.vm.tags).toEqual(Tags);
});
@@ -71,6 +69,22 @@ describe('RevisionDropdown component', () => {
expect(createFlash).toHaveBeenCalled();
});
+ it('makes a new request when refsProjectPath is changed', async () => {
+ jest.spyOn(axios, 'get');
+
+ const newRefsProjectPath = 'new-selected-project-path';
+
+ createComponent();
+
+ wrapper.setProps({
+ ...defaultProps,
+ refsProjectPath: newRefsProjectPath,
+ });
+
+ await axios.waitForAll();
+ expect(axios.get).toHaveBeenLastCalledWith(newRefsProjectPath);
+ });
+
describe('GlDropdown component', () => {
it('renders props', () => {
createComponent();
diff --git a/spec/frontend/projects/details/upload_button_spec.js b/spec/frontend/projects/details/upload_button_spec.js
new file mode 100644
index 00000000000..ebb2b499ead
--- /dev/null
+++ b/spec/frontend/projects/details/upload_button_spec.js
@@ -0,0 +1,61 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import UploadButton from '~/projects/details/upload_button.vue';
+import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
+import UploadBlobModal from '~/repository/components/upload_blob_modal.vue';
+
+jest.mock('~/projects/upload_file_experiment_tracking');
+
+const MODAL_ID = 'details-modal-upload-blob';
+
+describe('UploadButton', () => {
+ let wrapper;
+ let glModalDirective;
+
+ const createComponent = () => {
+ glModalDirective = jest.fn();
+
+ return shallowMount(UploadButton, {
+ directives: {
+ glModal: {
+ bind(_, { value }) {
+ glModalDirective(value);
+ },
+ },
+ },
+ });
+ };
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays an upload button', () => {
+ expect(wrapper.find(GlButton).exists()).toBe(true);
+ });
+
+ it('contains a modal', () => {
+ const modal = wrapper.find(UploadBlobModal);
+
+ expect(modal.exists()).toBe(true);
+ expect(modal.props('modalId')).toBe(MODAL_ID);
+ });
+
+ describe('when clickinig the upload file button', () => {
+ beforeEach(() => {
+ wrapper.find(GlButton).vm.$emit('click');
+ });
+
+ it('tracks the click_upload_modal_trigger event', () => {
+ expect(trackFileUploadEvent).toHaveBeenCalledWith('click_upload_modal_trigger');
+ });
+
+ it('opens the modal', () => {
+ expect(glModalDirective).toHaveBeenCalledWith(MODAL_ID);
+ });
+ });
+});
diff --git a/spec/frontend/projects/experiment_new_project_creation/components/new_project_push_tip_popover_spec.js b/spec/frontend/projects/experiment_new_project_creation/components/new_project_push_tip_popover_spec.js
new file mode 100644
index 00000000000..1ce16640d4a
--- /dev/null
+++ b/spec/frontend/projects/experiment_new_project_creation/components/new_project_push_tip_popover_spec.js
@@ -0,0 +1,75 @@
+import { GlPopover, GlFormInputGroup } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import NewProjectPushTipPopover from '~/projects/experiment_new_project_creation/components/new_project_push_tip_popover.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+describe('New project push tip popover', () => {
+ let wrapper;
+ const targetId = 'target';
+ const pushToCreateProjectCommand = 'command';
+ const workingWithProjectsHelpPath = 'path';
+
+ const findPopover = () => wrapper.findComponent(GlPopover);
+ const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
+ const findFormInput = () => wrapper.findComponent(GlFormInputGroup);
+ const findHelpLink = () => wrapper.find('a');
+ const findTarget = () => document.getElementById(targetId);
+
+ const buildWrapper = () => {
+ wrapper = shallowMount(NewProjectPushTipPopover, {
+ propsData: {
+ target: findTarget(),
+ },
+ stubs: {
+ GlFormInputGroup,
+ },
+ provide: {
+ pushToCreateProjectCommand,
+ workingWithProjectsHelpPath,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ setFixtures(`<a id="${targetId}"></a>`);
+ buildWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders popover that targets the specified target', () => {
+ expect(findPopover().props()).toMatchObject({
+ target: findTarget(),
+ triggers: 'click blur',
+ placement: 'top',
+ title: 'Push to create a project',
+ });
+ });
+
+ it('renders a readonly form input with the push to create command', () => {
+ expect(findFormInput().props()).toMatchObject({
+ value: pushToCreateProjectCommand,
+ selectOnClick: true,
+ });
+ expect(findFormInput().attributes()).toMatchObject({
+ 'aria-label': 'Push project from command line',
+ readonly: 'readonly',
+ });
+ });
+
+ it('allows copying the push command using the clipboard button', () => {
+ expect(findClipboardButton().props()).toMatchObject({
+ text: pushToCreateProjectCommand,
+ tooltipPlacement: 'right',
+ title: 'Copy command',
+ });
+ });
+
+ it('displays a link to open the push command help page reference', () => {
+ expect(findHelpLink().attributes().href).toBe(
+ `${workingWithProjectsHelpPath}#push-to-create-a-new-project`,
+ );
+ });
+});
diff --git a/spec/frontend/projects/experiment_new_project_creation/components/welcome_spec.js b/spec/frontend/projects/experiment_new_project_creation/components/welcome_spec.js
index d6764f75262..f26d1a6d2a3 100644
--- a/spec/frontend/projects/experiment_new_project_creation/components/welcome_spec.js
+++ b/spec/frontend/projects/experiment_new_project_creation/components/welcome_spec.js
@@ -1,5 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { mockTracking } from 'helpers/tracking_helper';
+import NewProjectPushTipPopover from '~/projects/experiment_new_project_creation/components/new_project_push_tip_popover.vue';
import WelcomePage from '~/projects/experiment_new_project_creation/components/welcome.vue';
describe('Welcome page', () => {
@@ -28,4 +29,13 @@ describe('Welcome page', () => {
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', { label: 'test' });
});
});
+
+ it('renders new project push tip popover', () => {
+ createComponent({ panels: [{ name: 'test', href: '#' }] });
+
+ const popover = wrapper.findComponent(NewProjectPushTipPopover);
+
+ expect(popover.exists()).toBe(true);
+ expect(popover.props().target()).toBe(wrapper.find({ ref: 'clipTip' }).element);
+ });
});
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
index f9fbb1b3016..8acf2376860 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
@@ -154,7 +154,7 @@ describe('ServiceDeskRoot', () => {
});
it('shows an error message', () => {
- expect(getAlertText()).toContain('An error occured while saving changes:');
+ expect(getAlertText()).toContain('An error occurred while saving changes:');
});
});
});
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
index f6744f4971e..5323c1afbb5 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
@@ -40,7 +40,7 @@ describe('ServiceDeskSetting', () => {
});
it('should see activation checkbox', () => {
- expect(findToggle().exists()).toBe(true);
+ expect(findToggle().props('label')).toBe(ServiceDeskSetting.i18n.toggleLabel);
});
it('should see main panel with the email info', () => {
diff --git a/spec/frontend/projects/upload_file_experiment_tracking_spec.js b/spec/frontend/projects/upload_file_experiment_tracking_spec.js
new file mode 100644
index 00000000000..6817529e07e
--- /dev/null
+++ b/spec/frontend/projects/upload_file_experiment_tracking_spec.js
@@ -0,0 +1,43 @@
+import ExperimentTracking from '~/experimentation/experiment_tracking';
+import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking';
+
+jest.mock('~/experimentation/experiment_tracking');
+
+const eventName = 'click_upload_modal_form_submit';
+const fixture = `<a class='js-upload-file-experiment-trigger'></a><div class='project-home-panel empty-project'></div>`;
+
+beforeEach(() => {
+ document.body.innerHTML = fixture;
+});
+
+afterEach(() => {
+ document.body.innerHTML = '';
+});
+
+describe('trackFileUploadEvent', () => {
+ it('initializes ExperimentTracking with the correct tracking event', () => {
+ trackFileUploadEvent(eventName);
+
+ expect(ExperimentTracking.prototype.event).toHaveBeenCalledWith(eventName);
+ });
+
+ it('calls ExperimentTracking with the correct arguments', () => {
+ trackFileUploadEvent(eventName);
+
+ expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', {
+ label: 'blob-upload-modal',
+ property: 'empty',
+ });
+ });
+
+ it('calls ExperimentTracking with the correct arguments when the project is not empty', () => {
+ document.querySelector('.empty-project').remove();
+
+ trackFileUploadEvent(eventName);
+
+ expect(ExperimentTracking).toHaveBeenCalledWith('empty_repo_upload', {
+ label: 'blob-upload-modal',
+ property: 'nonempty',
+ });
+ });
+});