summaryrefslogtreecommitdiff
path: root/spec/frontend/projects
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/projects')
-rw-r--r--spec/frontend/projects/commit/components/form_modal_spec.js15
-rw-r--r--spec/frontend/projects/commits/components/author_select_spec.js2
-rw-r--r--spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap41
-rw-r--r--spec/frontend/projects/components/project_delete_button_spec.js12
-rw-r--r--spec/frontend/projects/details/upload_button_spec.js7
-rw-r--r--spec/frontend/projects/new/components/new_project_url_select_spec.js39
-rw-r--r--spec/frontend/projects/pipelines/charts/components/app_spec.js24
-rw-r--r--spec/frontend/projects/projects_filterable_list_spec.js5
-rw-r--r--spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js98
-rw-r--r--spec/frontend/projects/settings_service_desk/components/mock_data.js8
-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.js80
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js80
-rw-r--r--spec/frontend/projects/storage_counter/components/storage_table_spec.js5
-rw-r--r--spec/frontend/projects/storage_counter/components/storage_type_icon_spec.js41
-rw-r--r--spec/frontend/projects/storage_counter/mock_data.js33
-rw-r--r--spec/frontend/projects/storage_counter/utils_spec.js17
-rw-r--r--spec/frontend/projects/upload_file_experiment_tracking_spec.js43
18 files changed, 398 insertions, 154 deletions
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
index 0c8089430d0..93e2ae13628 100644
--- a/spec/frontend/projects/commit/components/form_modal_spec.js
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -3,6 +3,7 @@ import { within } from '@testing-library/dom';
import { shallowMount, mount, createWrapper } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import api from '~/api';
import axios from '~/lib/utils/axios_utils';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue';
@@ -12,6 +13,8 @@ import eventHub from '~/projects/commit/event_hub';
import createStore from '~/projects/commit/store';
import mockData from '../mock_data';
+jest.mock('~/api');
+
describe('CommitFormModal', () => {
let wrapper;
let store;
@@ -167,4 +170,16 @@ describe('CommitFormModal', () => {
expect(findTargetProject().attributes('value')).toBe('_changed_project_value_');
});
});
+
+ it('action primary button triggers Redis HLL tracking api call', async () => {
+ createComponent(mount, {}, {}, { primaryActionEventName: 'test_event' });
+
+ await wrapper.vm.$nextTick();
+
+ jest.spyOn(findForm().element, 'submit');
+
+ getByText(mockData.modalPropsData.i18n.actionPrimaryText).trigger('click');
+
+ expect(api.trackRedisHllUserEvent).toHaveBeenCalledWith('test_event');
+ });
});
diff --git a/spec/frontend/projects/commits/components/author_select_spec.js b/spec/frontend/projects/commits/components/author_select_spec.js
index 9a8f7ff7582..60d36597fda 100644
--- a/spec/frontend/projects/commits/components/author_select_spec.js
+++ b/spec/frontend/projects/commits/components/author_select_spec.js
@@ -115,7 +115,7 @@ describe('Author Select', () => {
});
it('does not have popover text by default', () => {
- expect(wrapper.attributes('title')).not.toExist();
+ expect(wrapper.attributes('title')).toBeUndefined();
});
});
diff --git a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
index c255fcce321..e1e1aac09aa 100644
--- a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
+++ b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
@@ -52,9 +52,44 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
title="You are about to permanently delete this project"
variant="danger"
>
- <gl-sprintf-stub
- message="Once a project is permanently deleted, it %{strongStart}cannot be recovered%{strongEnd}. Permanently deleting this project will %{strongStart}immediately delete%{strongEnd} its repositories and %{strongStart}all related resources%{strongEnd}, including issues, merge requests etc."
- />
+ <p>
+ This project is
+ <strong>
+ NOT
+ </strong>
+ a fork, and has the following:
+ </p>
+
+ <ul>
+ <li>
+ 1 issue
+ </li>
+
+ <li>
+ 2 merge requests
+ </li>
+
+ <li>
+ 3 forks
+ </li>
+
+ <li>
+ 4 stars
+ </li>
+ </ul>
+ After a project is permanently deleted, it
+ <strong>
+ cannot be recovered
+ </strong>
+ . Permanently deleting this project will
+ <strong>
+ immediately delete
+ </strong>
+ its repositories and
+ <strong>
+ all related resources
+ </strong>
+ , including issues, merge requests etc.
</gl-alert-stub>
<p
diff --git a/spec/frontend/projects/components/project_delete_button_spec.js b/spec/frontend/projects/components/project_delete_button_spec.js
index 444e465ebaa..bb6021fadda 100644
--- a/spec/frontend/projects/components/project_delete_button_spec.js
+++ b/spec/frontend/projects/components/project_delete_button_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { GlSprintf } from '@gitlab/ui';
import ProjectDeleteButton from '~/projects/components/project_delete_button.vue';
import SharedDeleteButton from '~/projects/components/shared/delete_button.vue';
@@ -12,6 +13,11 @@ describe('Project remove modal', () => {
const defaultProps = {
confirmPhrase: 'foo',
formPath: 'some/path',
+ isFork: false,
+ issuesCount: 1,
+ mergeRequestsCount: 2,
+ forksCount: 3,
+ starsCount: 4,
};
const createComponent = (props = {}) => {
@@ -21,6 +27,7 @@ describe('Project remove modal', () => {
...props,
},
stubs: {
+ GlSprintf,
SharedDeleteButton,
},
});
@@ -41,7 +48,10 @@ describe('Project remove modal', () => {
});
it('passes confirmPhrase and formPath props to the shared delete button', () => {
- expect(findSharedDeleteButton().props()).toEqual(defaultProps);
+ expect(findSharedDeleteButton().props()).toEqual({
+ confirmPhrase: defaultProps.confirmPhrase,
+ formPath: defaultProps.formPath,
+ });
});
});
});
diff --git a/spec/frontend/projects/details/upload_button_spec.js b/spec/frontend/projects/details/upload_button_spec.js
index ebb2b499ead..d7308963088 100644
--- a/spec/frontend/projects/details/upload_button_spec.js
+++ b/spec/frontend/projects/details/upload_button_spec.js
@@ -1,11 +1,8 @@
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', () => {
@@ -50,10 +47,6 @@ describe('UploadButton', () => {
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/new/components/new_project_url_select_spec.js b/spec/frontend/projects/new/components/new_project_url_select_spec.js
index aa16b71172b..b3f177a1f12 100644
--- a/spec/frontend/projects/new/components/new_project_url_select_spec.js
+++ b/spec/frontend/projects/new/components/new_project_url_select_spec.js
@@ -24,14 +24,23 @@ describe('NewProjectUrlSelect component', () => {
{
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',
},
],
},
@@ -79,6 +88,10 @@ describe('NewProjectUrlSelect component', () => {
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();
@@ -127,7 +140,6 @@ describe('NewProjectUrlSelect component', () => {
it('focuses on the input when the dropdown is opened', async () => {
wrapper = mountComponent({ mountFn: mount });
-
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
@@ -140,7 +152,6 @@ describe('NewProjectUrlSelect component', () => {
it('renders expected dropdown items', async () => {
wrapper = mountComponent({ mountFn: mount });
-
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
@@ -160,7 +171,6 @@ describe('NewProjectUrlSelect component', () => {
beforeEach(async () => {
wrapper = mountComponent({ mountFn: mount });
-
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
@@ -195,23 +205,38 @@ describe('NewProjectUrlSelect component', () => {
};
wrapper = mountComponent({ search: 'no matches', queryResponse, mountFn: mount });
-
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
expect(wrapper.find('li').text()).toBe('No matches found');
});
- it('updates hidden input with selected namespace', async () => {
+ it('emits `update-visibility` event to update the visibility radio options', async () => {
wrapper = mountComponent();
-
jest.runOnlyPendingTimers();
await wrapper.vm.$nextTick();
- wrapper.findComponent(GlDropdownItem).vm.$emit('click');
+ 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(),
diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js
index 987a215eb4c..b4067f6a72b 100644
--- a/spec/frontend/projects/pipelines/charts/components/app_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js
@@ -11,6 +11,7 @@ jest.mock('~/lib/utils/url_utility');
const DeploymentFrequencyChartsStub = { name: 'DeploymentFrequencyCharts', render: () => {} };
const LeadTimeChartsStub = { name: 'LeadTimeCharts', render: () => {} };
+const ProjectQualitySummaryStub = { name: 'ProjectQualitySummary', render: () => {} };
describe('ProjectsPipelinesChartsApp', () => {
let wrapper;
@@ -23,10 +24,12 @@ describe('ProjectsPipelinesChartsApp', () => {
{
provide: {
shouldRenderDoraCharts: true,
+ shouldRenderQualitySummary: true,
},
stubs: {
DeploymentFrequencyCharts: DeploymentFrequencyChartsStub,
LeadTimeCharts: LeadTimeChartsStub,
+ ProjectQualitySummary: ProjectQualitySummaryStub,
},
},
mountOptions,
@@ -44,6 +47,7 @@ describe('ProjectsPipelinesChartsApp', () => {
const findLeadTimeCharts = () => wrapper.find(LeadTimeChartsStub);
const findDeploymentFrequencyCharts = () => wrapper.find(DeploymentFrequencyChartsStub);
const findPipelineCharts = () => wrapper.find(PipelineCharts);
+ const findProjectQualitySummary = () => wrapper.find(ProjectQualitySummaryStub);
describe('when all charts are available', () => {
beforeEach(() => {
@@ -70,6 +74,10 @@ describe('ProjectsPipelinesChartsApp', () => {
expect(findLeadTimeCharts().exists()).toBe(true);
});
+ it('renders the project quality summary', () => {
+ expect(findProjectQualitySummary().exists()).toBe(true);
+ });
+
it('sets the tab and url when a tab is clicked', async () => {
let chartsPath;
setWindowLocation(`${TEST_HOST}/gitlab-org/gitlab-test/-/pipelines/charts`);
@@ -163,9 +171,11 @@ describe('ProjectsPipelinesChartsApp', () => {
});
});
- describe('when the dora charts are not available', () => {
+ describe('when the dora charts are not available and project quality summary is not available', () => {
beforeEach(() => {
- createComponent({ provide: { shouldRenderDoraCharts: false } });
+ createComponent({
+ provide: { shouldRenderDoraCharts: false, shouldRenderQualitySummary: false },
+ });
});
it('does not render tabs', () => {
@@ -176,4 +186,14 @@ describe('ProjectsPipelinesChartsApp', () => {
expect(findPipelineCharts().exists()).toBe(true);
});
});
+
+ describe('when the project quality summary is not available', () => {
+ beforeEach(() => {
+ createComponent({ provide: { shouldRenderQualitySummary: false } });
+ });
+
+ it('does not render the tab', () => {
+ expect(findProjectQualitySummary().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/projects/projects_filterable_list_spec.js b/spec/frontend/projects/projects_filterable_list_spec.js
index d4dbf85b5ca..a41e8b7bc09 100644
--- a/spec/frontend/projects/projects_filterable_list_spec.js
+++ b/spec/frontend/projects/projects_filterable_list_spec.js
@@ -1,5 +1,4 @@
-// eslint-disable-next-line import/no-deprecated
-import { getJSONFixture, setHTMLFixture } from 'helpers/fixtures';
+import { setHTMLFixture } from 'helpers/fixtures';
import ProjectsFilterableList from '~/projects/projects_filterable_list';
describe('ProjectsFilterableList', () => {
@@ -15,8 +14,6 @@ describe('ProjectsFilterableList', () => {
</div>
<div class="js-projects-list-holder"></div>
`);
- // eslint-disable-next-line import/no-deprecated
- getJSONFixture('static/projects.json');
form = document.querySelector('form#project-filter-form');
filter = document.querySelector('.js-projects-list-filter');
holder = document.querySelector('.js-projects-list-holder');
diff --git a/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js b/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
new file mode 100644
index 00000000000..dbea94cbd53
--- /dev/null
+++ b/spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
@@ -0,0 +1,98 @@
+import { GlTokenSelector, GlToken } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import TopicsTokenSelector from '~/projects/settings/topics/components/topics_token_selector.vue';
+
+const mockTopics = [
+ { id: 1, name: 'topic1', avatarUrl: 'avatar.com/topic1.png' },
+ { id: 2, name: 'GitLab', avatarUrl: 'avatar.com/GitLab.png' },
+];
+
+describe('TopicsTokenSelector', () => {
+ let wrapper;
+ let div;
+ let input;
+
+ const createComponent = (selected) => {
+ wrapper = mount(TopicsTokenSelector, {
+ attachTo: div,
+ propsData: {
+ selected,
+ },
+ data() {
+ return {
+ topics: mockTopics,
+ };
+ },
+ mocks: {
+ $apollo: {
+ queries: {
+ topics: { loading: false },
+ },
+ },
+ },
+ });
+ };
+
+ const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
+
+ const findTokenSelectorInput = () => findTokenSelector().find('input[type="text"]');
+
+ const setTokenSelectorInputValue = (value) => {
+ const tokenSelectorInput = findTokenSelectorInput();
+
+ tokenSelectorInput.element.value = value;
+ tokenSelectorInput.trigger('input');
+
+ return nextTick();
+ };
+
+ const tokenSelectorTriggerEnter = (event) => {
+ const tokenSelectorInput = findTokenSelectorInput();
+ tokenSelectorInput.trigger('keydown.enter', event);
+ };
+
+ beforeEach(() => {
+ div = document.createElement('div');
+ input = document.createElement('input');
+ input.setAttribute('type', 'text');
+ input.id = 'project_topic_list_field';
+ document.body.appendChild(div);
+ document.body.appendChild(input);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ div.remove();
+ input.remove();
+ });
+
+ describe('when component is mounted', () => {
+ it('parses selected into tokens', async () => {
+ const selected = [
+ { id: 11, name: 'topic1' },
+ { id: 12, name: 'topic2' },
+ { id: 13, name: 'topic3' },
+ ];
+ createComponent(selected);
+ await nextTick();
+
+ wrapper.findAllComponents(GlToken).wrappers.forEach((tokenWrapper, index) => {
+ expect(tokenWrapper.text()).toBe(selected[index].name);
+ });
+ });
+ });
+
+ describe('when enter key is pressed', () => {
+ it('does not submit the form if token selector text input has a value', async () => {
+ createComponent();
+
+ await setTokenSelectorInputValue('topic');
+
+ const event = { preventDefault: jest.fn() };
+ tokenSelectorTriggerEnter(event);
+
+ expect(event.preventDefault).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/projects/settings_service_desk/components/mock_data.js b/spec/frontend/projects/settings_service_desk/components/mock_data.js
new file mode 100644
index 00000000000..934778ff601
--- /dev/null
+++ b/spec/frontend/projects/settings_service_desk/components/mock_data.js
@@ -0,0 +1,8 @@
+export const TEMPLATES = [
+ 'Project #1',
+ [
+ { name: 'Bug', project_id: 1 },
+ { name: 'Documentation', project_id: 1 },
+ { name: 'Security release', project_id: 1 },
+ ],
+];
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 8acf2376860..62224612387 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
@@ -21,6 +21,7 @@ describe('ServiceDeskRoot', () => {
outgoingName: 'GitLab Support Bot',
projectKey: 'key',
selectedTemplate: 'Bug',
+ selectedFileTemplateProjectId: 42,
templates: ['Bug', 'Documentation'],
};
@@ -52,6 +53,7 @@ describe('ServiceDeskRoot', () => {
initialOutgoingName: provideData.outgoingName,
initialProjectKey: provideData.projectKey,
initialSelectedTemplate: provideData.selectedTemplate,
+ initialSelectedFileTemplateProjectId: provideData.selectedFileTemplateProjectId,
isEnabled: provideData.initialIsEnabled,
isTemplateSaving: false,
templates: provideData.templates,
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 eacf858f22c..0fd3e7446da 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
@@ -1,4 +1,4 @@
-import { GlButton, GlFormSelect, GlLoadingIcon, GlToggle } from '@gitlab/ui';
+import { GlButton, GlDropdown, GlLoadingIcon, GlToggle } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
@@ -13,7 +13,7 @@ describe('ServiceDeskSetting', () => {
const findIncomingEmail = () => wrapper.findByTestId('incoming-email');
const findIncomingEmailLabel = () => wrapper.findByTestId('incoming-email-describer');
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
- const findTemplateDropdown = () => wrapper.find(GlFormSelect);
+ const findTemplateDropdown = () => wrapper.find(GlDropdown);
const findToggle = () => wrapper.find(GlToggle);
const createComponent = ({ props = {}, mountFunction = shallowMount } = {}) =>
@@ -128,6 +128,23 @@ describe('ServiceDeskSetting', () => {
expect(input.exists()).toBe(true);
expect(input.attributes('disabled')).toBeUndefined();
});
+
+ it('shows error when value contains uppercase or special chars', async () => {
+ wrapper = createComponent({
+ props: { customEmailEnabled: true },
+ mountFunction: mount,
+ });
+
+ const input = wrapper.findByTestId('project-suffix');
+
+ input.setValue('abc_A.');
+ input.trigger('blur');
+
+ await wrapper.vm.$nextTick();
+
+ const errorText = wrapper.find('.text-danger');
+ expect(errorText.exists()).toBe(true);
+ });
});
describe('customEmail is the same as incomingEmail', () => {
@@ -144,63 +161,6 @@ describe('ServiceDeskSetting', () => {
});
});
});
-
- describe('templates dropdown', () => {
- it('renders a dropdown to choose a template', () => {
- wrapper = createComponent();
-
- expect(findTemplateDropdown().exists()).toBe(true);
- });
-
- it('renders a dropdown with a default value of ""', () => {
- wrapper = createComponent({ mountFunction: mount });
-
- expect(findTemplateDropdown().element.value).toEqual('');
- });
-
- it('renders a dropdown with a value of "Bug" when it is the initial value', () => {
- const templates = ['Bug', 'Documentation', 'Security release'];
-
- wrapper = createComponent({
- props: { initialSelectedTemplate: 'Bug', templates },
- mountFunction: mount,
- });
-
- expect(findTemplateDropdown().element.value).toEqual('Bug');
- });
-
- it('renders a dropdown with no options when the project has no templates', () => {
- wrapper = createComponent({
- props: { templates: [] },
- mountFunction: mount,
- });
-
- // The dropdown by default has one empty option
- expect(findTemplateDropdown().element.children).toHaveLength(1);
- });
-
- it('renders a dropdown with options when the project has templates', () => {
- const templates = ['Bug', 'Documentation', 'Security release'];
-
- wrapper = createComponent({
- props: { templates },
- mountFunction: mount,
- });
-
- // An empty-named template is prepended so the user can select no template
- const expectedTemplates = [''].concat(templates);
-
- const dropdown = findTemplateDropdown();
- const dropdownList = Array.from(dropdown.element.children).map(
- (option) => option.innerText,
- );
-
- expect(dropdown.element.children).toHaveLength(expectedTemplates.length);
- expect(dropdownList.includes('Bug')).toEqual(true);
- expect(dropdownList.includes('Documentation')).toEqual(true);
- expect(dropdownList.includes('Security release')).toEqual(true);
- });
- });
});
describe('save button', () => {
@@ -214,6 +174,7 @@ describe('ServiceDeskSetting', () => {
wrapper = createComponent({
props: {
initialSelectedTemplate: 'Bug',
+ initialSelectedFileTemplateProjectId: 42,
initialOutgoingName: 'GitLab Support Bot',
initialProjectKey: 'key',
},
@@ -225,6 +186,7 @@ describe('ServiceDeskSetting', () => {
const payload = {
selectedTemplate: 'Bug',
+ fileTemplateProjectId: 42,
outgoingName: 'GitLab Support Bot',
projectKey: 'key',
};
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js
new file mode 100644
index 00000000000..cdb355f5a9b
--- /dev/null
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_template_dropdown_spec.js
@@ -0,0 +1,80 @@
+import { GlDropdown, GlDropdownSectionHeader, GlDropdownItem } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import ServiceDeskTemplateDropdown from '~/projects/settings_service_desk/components/service_desk_setting.vue';
+import { TEMPLATES } from './mock_data';
+
+describe('ServiceDeskTemplateDropdown', () => {
+ let wrapper;
+
+ const findTemplateDropdown = () => wrapper.find(GlDropdown);
+
+ const createComponent = ({ props = {} } = {}) =>
+ extendedWrapper(
+ mount(ServiceDeskTemplateDropdown, {
+ propsData: {
+ isEnabled: true,
+ ...props,
+ },
+ }),
+ );
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('templates dropdown', () => {
+ it('renders a dropdown to choose a template', () => {
+ wrapper = createComponent();
+
+ expect(findTemplateDropdown().exists()).toBe(true);
+ });
+
+ it('renders a dropdown with a default value of "Choose a template"', () => {
+ wrapper = createComponent();
+
+ expect(findTemplateDropdown().props('text')).toEqual('Choose a template');
+ });
+
+ it('renders a dropdown with a value of "Bug" when it is the initial value', () => {
+ const templates = TEMPLATES;
+
+ wrapper = createComponent({
+ props: { initialSelectedTemplate: 'Bug', initialSelectedTemplateProjectId: 1, templates },
+ });
+
+ expect(findTemplateDropdown().props('text')).toEqual('Bug');
+ });
+
+ it('renders a dropdown with header items', () => {
+ wrapper = createComponent({
+ props: { templates: TEMPLATES },
+ });
+
+ const headerItems = wrapper.findAll(GlDropdownSectionHeader);
+
+ expect(headerItems).toHaveLength(1);
+ expect(headerItems.at(0).text()).toBe(TEMPLATES[0]);
+ });
+
+ it('renders a dropdown with options when the project has templates', () => {
+ const templates = TEMPLATES;
+
+ wrapper = createComponent({
+ props: { templates },
+ });
+
+ const expectedTemplates = templates[1];
+
+ const items = wrapper.findAll(GlDropdownItem);
+ const dropdownList = expectedTemplates.map((_, index) => items.at(index).text());
+
+ expect(items).toHaveLength(expectedTemplates.length);
+ expect(dropdownList.includes('Bug')).toEqual(true);
+ expect(dropdownList.includes('Documentation')).toEqual(true);
+ expect(dropdownList.includes('Security release')).toEqual(true);
+ });
+ });
+});
diff --git a/spec/frontend/projects/storage_counter/components/storage_table_spec.js b/spec/frontend/projects/storage_counter/components/storage_table_spec.js
index 14298318fff..c9e56d8f033 100644
--- a/spec/frontend/projects/storage_counter/components/storage_table_spec.js
+++ b/spec/frontend/projects/storage_counter/components/storage_table_spec.js
@@ -1,4 +1,4 @@
-import { GlTable } from '@gitlab/ui';
+import { GlTableLite } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import StorageTable from '~/projects/storage_counter/components/storage_table.vue';
@@ -22,7 +22,7 @@ describe('StorageTable', () => {
);
};
- const findTable = () => wrapper.findComponent(GlTable);
+ const findTable = () => wrapper.findComponent(GlTableLite);
beforeEach(() => {
createComponent();
@@ -37,6 +37,7 @@ describe('StorageTable', () => {
({ storageType: { id, name, description } }) => {
expect(wrapper.findByTestId(`${id}-name`).text()).toBe(name);
expect(wrapper.findByTestId(`${id}-description`).text()).toBe(description);
+ expect(wrapper.findByTestId(`${id}-icon`).props('name')).toBe(id);
expect(wrapper.findByTestId(`${id}-help-link`).attributes('href')).toBe(
defaultProvideValues.helpLinks[id.replace(`Size`, `HelpPagePath`)]
.replace(`Size`, ``)
diff --git a/spec/frontend/projects/storage_counter/components/storage_type_icon_spec.js b/spec/frontend/projects/storage_counter/components/storage_type_icon_spec.js
new file mode 100644
index 00000000000..01efd6f14bd
--- /dev/null
+++ b/spec/frontend/projects/storage_counter/components/storage_type_icon_spec.js
@@ -0,0 +1,41 @@
+import { mount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import StorageTypeIcon from '~/projects/storage_counter/components/storage_type_icon.vue';
+
+describe('StorageTypeIcon', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(StorageTypeIcon, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findGlIcon = () => wrapper.findComponent(GlIcon);
+
+ describe('rendering icon', () => {
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ expected | provided
+ ${'doc-image'} | ${'lfsObjectsSize'}
+ ${'snippet'} | ${'snippetsSize'}
+ ${'infrastructure-registry'} | ${'repositorySize'}
+ ${'package'} | ${'packagesSize'}
+ ${'upload'} | ${'uploadsSize'}
+ ${'disk'} | ${'wikiSize'}
+ ${'disk'} | ${'anything-else'}
+ `(
+ 'renders icon with name of $expected when name prop is $provided',
+ ({ expected, provided }) => {
+ createComponent({ name: provided });
+
+ expect(findGlIcon().props('name')).toBe(expected);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/projects/storage_counter/mock_data.js b/spec/frontend/projects/storage_counter/mock_data.js
index b9fa68b3ec7..6b3e23ac386 100644
--- a/spec/frontend/projects/storage_counter/mock_data.js
+++ b/spec/frontend/projects/storage_counter/mock_data.js
@@ -1,23 +1,6 @@
-export const mockGetProjectStorageCountGraphQLResponse = {
- data: {
- project: {
- id: 'gid://gitlab/Project/20',
- statistics: {
- buildArtifactsSize: 400000.0,
- pipelineArtifactsSize: 25000.0,
- lfsObjectsSize: 4800000.0,
- packagesSize: 3800000.0,
- repositorySize: 3900000.0,
- snippetsSize: 1200000.0,
- storageSize: 15300000.0,
- uploadsSize: 900000.0,
- wikiSize: 300000.0,
- __typename: 'ProjectStatistics',
- },
- __typename: 'Project',
- },
- },
-};
+import mockGetProjectStorageCountGraphQLResponse from 'test_fixtures/graphql/projects/storage_counter/project_storage.query.graphql.json';
+
+export { mockGetProjectStorageCountGraphQLResponse };
export const mockEmptyResponse = { data: { project: null } };
@@ -37,7 +20,7 @@ export const defaultProvideValues = {
export const projectData = {
storage: {
- totalUsage: '14.6 MiB',
+ totalUsage: '13.8 MiB',
storageTypes: [
{
storageType: {
@@ -45,7 +28,7 @@ export const projectData = {
name: 'Artifacts',
description: 'Pipeline artifacts and job artifacts, created with CI/CD.',
warningMessage:
- 'There is a known issue with Artifact storage where the total could be incorrect for some projects. More details and progress are available in %{warningLinkStart}the epic%{warningLinkEnd}.',
+ 'Because of a known issue, the artifact total for some projects may be incorrect. For more details, read %{warningLinkStart}the epic%{warningLinkEnd}.',
helpPath: '/build-artifacts',
},
value: 400000,
@@ -53,7 +36,7 @@ export const projectData = {
{
storageType: {
id: 'lfsObjectsSize',
- name: 'LFS Storage',
+ name: 'LFS storage',
description: 'Audio samples, videos, datasets, and graphics.',
helpPath: '/lsf-objects',
},
@@ -72,7 +55,7 @@ export const projectData = {
storageType: {
id: 'repositorySize',
name: 'Repository',
- description: 'Git repository, managed by the Gitaly service.',
+ description: 'Git repository.',
helpPath: '/repository',
},
value: 3900000,
@@ -84,7 +67,7 @@ export const projectData = {
description: 'Shared bits of code and text.',
helpPath: '/snippets',
},
- value: 1200000,
+ value: 0,
},
{
storageType: {
diff --git a/spec/frontend/projects/storage_counter/utils_spec.js b/spec/frontend/projects/storage_counter/utils_spec.js
index 57c755266a0..fb91975a3cf 100644
--- a/spec/frontend/projects/storage_counter/utils_spec.js
+++ b/spec/frontend/projects/storage_counter/utils_spec.js
@@ -14,4 +14,21 @@ describe('parseGetProjectStorageResults', () => {
),
).toMatchObject(projectData);
});
+
+ it('includes storage type with size of 0 in returned value', () => {
+ const mockedResponse = mockGetProjectStorageCountGraphQLResponse.data;
+ // ensuring a specific storage type item has size of 0
+ mockedResponse.project.statistics.repositorySize = 0;
+
+ const response = parseGetProjectStorageResults(mockedResponse, defaultProvideValues.helpLinks);
+
+ expect(response.storage.storageTypes).toEqual(
+ expect.arrayContaining([
+ {
+ storageType: expect.any(Object),
+ value: 0,
+ },
+ ]),
+ );
+ });
});
diff --git a/spec/frontend/projects/upload_file_experiment_tracking_spec.js b/spec/frontend/projects/upload_file_experiment_tracking_spec.js
deleted file mode 100644
index 6817529e07e..00000000000
--- a/spec/frontend/projects/upload_file_experiment_tracking_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-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',
- });
- });
-});