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:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-03 00:10:16 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-03 00:10:16 +0300
commit515f39456fce82eb2ab811fa366167ad084a3b12 (patch)
treeeae2c8deccede9fc025f7eba1b8a3a745dcb7f8f /spec/frontend
parentd1ade10ba69cb7c232daa36625656456c32462e4 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/clusters_list/components/agent_empty_state_spec.js13
-rw-r--r--spec/frontend/clusters_list/components/clusters_empty_state_spec.js54
-rw-r--r--spec/frontend/clusters_list/components/clusters_main_view_spec.js8
-rw-r--r--spec/frontend/ide/services/index_spec.js8
-rw-r--r--spec/frontend/jobs/components/table/cells/actions_cell_spec.js20
-rw-r--r--spec/frontend/jobs/mock_data.js37
-rw-r--r--spec/frontend/projects/new/components/new_project_url_select_spec.js81
7 files changed, 140 insertions, 81 deletions
diff --git a/spec/frontend/clusters_list/components/agent_empty_state_spec.js b/spec/frontend/clusters_list/components/agent_empty_state_spec.js
index f6918311934..ed2a0d0b97b 100644
--- a/spec/frontend/clusters_list/components/agent_empty_state_spec.js
+++ b/spec/frontend/clusters_list/components/agent_empty_state_spec.js
@@ -1,4 +1,4 @@
-import { GlEmptyState, GlSprintf } from '@gitlab/ui';
+import { GlEmptyState, GlSprintf, GlLink, GlButton } from '@gitlab/ui';
import AgentEmptyState from '~/clusters_list/components/agent_empty_state.vue';
import { INSTALL_AGENT_MODAL_ID } from '~/clusters_list/constants';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -6,8 +6,7 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { helpPagePath } from '~/helpers/help_page_helper';
const emptyStateImage = '/path/to/image';
-const multipleClustersDocsUrl = helpPagePath('user/project/clusters/multiple_kubernetes_clusters');
-const installDocsUrl = helpPagePath('administration/clusters/kas');
+const installDocsUrl = helpPagePath('user/clusters/agent/index');
describe('AgentEmptyStateComponent', () => {
let wrapper;
@@ -15,9 +14,8 @@ describe('AgentEmptyStateComponent', () => {
emptyStateImage,
};
- const findMultipleClustersDocsLink = () => wrapper.findByTestId('multiple-clusters-docs-link');
- const findInstallDocsLink = () => wrapper.findByTestId('install-docs-link');
- const findIntegrationButton = () => wrapper.findByTestId('integration-primary-button');
+ const findInstallDocsLink = () => wrapper.findComponent(GlLink);
+ const findIntegrationButton = () => wrapper.findComponent(GlButton);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
beforeEach(() => {
@@ -44,8 +42,7 @@ describe('AgentEmptyStateComponent', () => {
expect(findIntegrationButton().exists()).toBe(true);
});
- it('renders correct href attributes for the links', () => {
- expect(findMultipleClustersDocsLink().attributes('href')).toBe(multipleClustersDocsUrl);
+ it('renders correct href attributes for the docs link', () => {
expect(findInstallDocsLink().attributes('href')).toBe(installDocsUrl);
});
diff --git a/spec/frontend/clusters_list/components/clusters_empty_state_spec.js b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
index f7e1791d0f7..cf0f6881960 100644
--- a/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
@@ -6,35 +6,33 @@ import ClusterStore from '~/clusters_list/store';
const clustersEmptyStateImage = 'path/to/svg';
const newClusterPath = '/path/to/connect/cluster';
const emptyStateHelpText = 'empty state text';
-const canAddCluster = true;
describe('ClustersEmptyStateComponent', () => {
let wrapper;
- const propsData = {
- isChildComponent: false,
- };
-
- const provideData = {
+ const defaultProvideData = {
clustersEmptyStateImage,
- emptyStateHelpText: null,
newClusterPath,
};
- const entryData = {
- canAddCluster,
- };
-
const findButton = () => wrapper.findComponent(GlButton);
const findEmptyStateText = () => wrapper.findByTestId('clusters-empty-state-text');
- beforeEach(() => {
+ const createWrapper = ({
+ provideData = { emptyStateHelpText: null },
+ isChildComponent = false,
+ canAddCluster = true,
+ } = {}) => {
wrapper = shallowMountExtended(ClustersEmptyState, {
- store: ClusterStore(entryData),
- propsData,
- provide: provideData,
+ store: ClusterStore({ canAddCluster }),
+ propsData: { isChildComponent },
+ provide: { ...defaultProvideData, ...provideData },
stubs: { GlEmptyState },
});
+ };
+
+ beforeEach(() => {
+ createWrapper();
});
afterEach(() => {
@@ -55,16 +53,7 @@ describe('ClustersEmptyStateComponent', () => {
describe('when the component is loaded as a child component', () => {
beforeEach(() => {
- propsData.isChildComponent = true;
- wrapper = shallowMountExtended(ClustersEmptyState, {
- store: ClusterStore(entryData),
- propsData,
- provide: provideData,
- });
- });
-
- afterEach(() => {
- propsData.isChildComponent = false;
+ createWrapper({ isChildComponent: true });
});
it('should not render the action button', () => {
@@ -74,12 +63,7 @@ describe('ClustersEmptyStateComponent', () => {
describe('when the help text is provided', () => {
beforeEach(() => {
- provideData.emptyStateHelpText = emptyStateHelpText;
- wrapper = shallowMountExtended(ClustersEmptyState, {
- store: ClusterStore(entryData),
- propsData,
- provide: provideData,
- });
+ createWrapper({ provideData: { emptyStateHelpText } });
});
it('should show the empty state text', () => {
@@ -88,14 +72,8 @@ describe('ClustersEmptyStateComponent', () => {
});
describe('when the user cannot add clusters', () => {
- entryData.canAddCluster = false;
beforeEach(() => {
- wrapper = shallowMountExtended(ClustersEmptyState, {
- store: ClusterStore(entryData),
- propsData,
- provide: provideData,
- stubs: { GlEmptyState },
- });
+ createWrapper({ canAddCluster: false });
});
it('should disable the button', () => {
expect(findButton().props('disabled')).toBe(true);
diff --git a/spec/frontend/clusters_list/components/clusters_main_view_spec.js b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
index 7cf8e6293a1..37665bf7abd 100644
--- a/spec/frontend/clusters_list/components/clusters_main_view_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
@@ -59,10 +59,10 @@ describe('ClustersMainViewComponent', () => {
describe('tabs', () => {
it.each`
- tabTitle | queryParamValue | lineNumber
- ${'All'} | ${'all'} | ${0}
- ${'Agent'} | ${AGENT} | ${1}
- ${'Certificate based'} | ${CERTIFICATE_BASED} | ${2}
+ tabTitle | queryParamValue | lineNumber
+ ${'All'} | ${'all'} | ${0}
+ ${'Agent'} | ${AGENT} | ${1}
+ ${'Certificate'} | ${CERTIFICATE_BASED} | ${2}
`(
'renders correct tab title and query param value',
({ tabTitle, queryParamValue, lineNumber }) => {
diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js
index eacf1244d55..d250eb7f6ad 100644
--- a/spec/frontend/ide/services/index_spec.js
+++ b/spec/frontend/ide/services/index_spec.js
@@ -219,15 +219,21 @@ describe('IDE services', () => {
describe('getProjectData', () => {
it('combines gql and API requests', () => {
const gqlProjectData = {
+ id: 'gid://gitlab/Project/1',
userPermissions: {
bogus: true,
},
};
+ const expectedResponse = {
+ ...projectData,
+ ...gqlProjectData,
+ id: 1,
+ };
Api.project.mockReturnValue(Promise.resolve({ data: { ...projectData } }));
query.mockReturnValue(Promise.resolve({ data: { project: gqlProjectData } }));
return services.getProjectData(TEST_NAMESPACE, TEST_PROJECT).then((response) => {
- expect(response).toEqual({ data: { ...projectData, ...gqlProjectData } });
+ expect(response).toEqual({ data: expectedResponse });
expect(Api.project).toHaveBeenCalledWith(TEST_PROJECT_ID);
expect(query).toHaveBeenCalledWith({
query: getIdeProject,
diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
index 1b1e2d4df8f..b70fca8e9e6 100644
--- a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
@@ -5,7 +5,14 @@ import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue';
import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql';
import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql';
import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
-import { playableJob, retryableJob, scheduledJob } from '../../../mock_data';
+import {
+ playableJob,
+ retryableJob,
+ scheduledJob,
+ cannotRetryJob,
+ cannotPlayJob,
+ cannotPlayScheduledJob,
+} from '../../../mock_data';
describe('Job actions cell', () => {
let wrapper;
@@ -58,6 +65,17 @@ describe('Job actions cell', () => {
});
it.each`
+ button | action | jobType
+ ${findPlayButton} | ${'play'} | ${cannotPlayJob}
+ ${findRetryButton} | ${'retry'} | ${cannotRetryJob}
+ ${findPlayScheduledJobButton} | ${'play scheduled'} | ${cannotPlayScheduledJob}
+ `('does not display the $action button if user cannot update build', ({ button, jobType }) => {
+ createComponent(jobType);
+
+ expect(button().exists()).toBe(false);
+ });
+
+ it.each`
button | action | jobType
${findPlayButton} | ${'play'} | ${playableJob}
${findRetryButton} | ${'retry'} | ${retryableJob}
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index 5654c8e424e..86be739751b 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -1563,6 +1563,7 @@ export const mockJobsQueryResponse = {
userPermissions: {
readBuild: true,
readJobArtifacts: true,
+ updateBuild: true,
__typename: 'JobPermissions',
},
__typename: 'CiJob',
@@ -1636,10 +1637,15 @@ export const retryableJob = {
cancelable: false,
active: false,
stuck: false,
- userPermissions: { readBuild: true, __typename: 'JobPermissions' },
+ userPermissions: { readBuild: true, updateBuild: true, __typename: 'JobPermissions' },
__typename: 'CiJob',
};
+export const cannotRetryJob = {
+ ...retryableJob,
+ userPermissions: { readBuild: true, updateBuild: false, __typename: 'JobPermissions' },
+};
+
export const playableJob = {
artifacts: {
nodes: [
@@ -1700,10 +1706,25 @@ export const playableJob = {
cancelable: false,
active: false,
stuck: false,
- userPermissions: { readBuild: true, readJobArtifacts: true, __typename: 'JobPermissions' },
+ userPermissions: {
+ readBuild: true,
+ readJobArtifacts: true,
+ updateBuild: true,
+ __typename: 'JobPermissions',
+ },
__typename: 'CiJob',
};
+export const cannotPlayJob = {
+ ...playableJob,
+ userPermissions: {
+ readBuild: true,
+ readJobArtifacts: true,
+ updateBuild: false,
+ __typename: 'JobPermissions',
+ },
+};
+
export const scheduledJob = {
artifacts: { nodes: [], __typename: 'CiJobArtifactConnection' },
allowFailure: false,
@@ -1756,6 +1777,16 @@ export const scheduledJob = {
cancelable: false,
active: false,
stuck: false,
- userPermissions: { readBuild: true, __typename: 'JobPermissions' },
+ userPermissions: { readBuild: true, updateBuild: true, __typename: 'JobPermissions' },
__typename: 'CiJob',
};
+
+export const cannotPlayScheduledJob = {
+ ...scheduledJob,
+ userPermissions: {
+ readBuild: true,
+ readJobArtifacts: true,
+ updateBuild: false,
+ __typename: 'JobPermissions',
+ },
+};
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 bdce8af613b..258fa7636d4 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
@@ -5,7 +5,8 @@ import {
GlDropdownSectionHeader,
GlSearchBoxByType,
} from '@gitlab/ui';
-import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
@@ -52,8 +53,7 @@ describe('NewProjectUrlSelect component', () => {
},
};
- const localVue = createLocalVue();
- localVue.use(VueApollo);
+ Vue.use(VueApollo);
const defaultProvide = {
namespaceFullPath: 'h5bp',
@@ -64,17 +64,19 @@ describe('NewProjectUrlSelect component', () => {
userNamespaceId: '1',
};
+ let mockQueryResponse;
+
const mountComponent = ({
search = '',
queryResponse = data,
provide = defaultProvide,
mountFn = shallowMount,
} = {}) => {
- const requestHandlers = [[searchQuery, jest.fn().mockResolvedValue({ data: queryResponse })]];
+ mockQueryResponse = jest.fn().mockResolvedValue({ data: queryResponse });
+ const requestHandlers = [[searchQuery, mockQueryResponse]];
const apolloProvider = createMockApollo(requestHandlers);
return mountFn(NewProjectUrlSelect, {
- localVue,
apolloProvider,
provide,
data() {
@@ -88,12 +90,19 @@ describe('NewProjectUrlSelect component', () => {
const findButtonLabel = () => wrapper.findComponent(GlButton);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findInput = () => wrapper.findComponent(GlSearchBoxByType);
- const findHiddenInput = () => wrapper.find('input');
+ const findHiddenInput = () => wrapper.find('[name="project[namespace_id]"]');
+
const clickDropdownItem = async () => {
wrapper.findComponent(GlDropdownItem).vm.$emit('click');
await wrapper.vm.$nextTick();
};
+ const showDropdown = async () => {
+ findDropdown().vm.$emit('shown');
+ await wrapper.vm.$apollo.queries.currentUser.refetch();
+ jest.runOnlyPendingTimers();
+ };
+
afterEach(() => {
wrapper.destroy();
});
@@ -141,20 +150,18 @@ describe('NewProjectUrlSelect component', () => {
it('focuses on the input when the dropdown is opened', async () => {
wrapper = mountComponent({ mountFn: mount });
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
const spy = jest.spyOn(findInput().vm, 'focusInput');
- findDropdown().vm.$emit('shown');
+ await showDropdown();
expect(spy).toHaveBeenCalledTimes(1);
});
it('renders expected dropdown items', async () => {
wrapper = mountComponent({ mountFn: mount });
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+
+ await showDropdown();
const listItems = wrapper.findAll('li');
@@ -167,15 +174,36 @@ describe('NewProjectUrlSelect component', () => {
expect(listItems.at(5).text()).toBe(data.currentUser.namespace.fullPath);
});
+ describe('query fetching', () => {
+ describe('on component mount', () => {
+ it('does not fetch query', () => {
+ wrapper = mountComponent({ mountFn: mount });
+
+ expect(mockQueryResponse).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('on dropdown shown', () => {
+ it('fetches query', async () => {
+ wrapper = mountComponent({ mountFn: mount });
+
+ await showDropdown();
+
+ expect(mockQueryResponse).toHaveBeenCalled();
+ });
+ });
+ });
+
describe('when selecting from a group template', () => {
- const groupId = getIdFromGraphQLId(data.currentUser.groups.nodes[1].id);
+ const { fullPath, id } = data.currentUser.groups.nodes[1];
beforeEach(async () => {
wrapper = mountComponent({ mountFn: mount });
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
- eventHub.$emit('select-template', groupId);
+ // Show dropdown to fetch projects
+ await showDropdown();
+
+ eventHub.$emit('select-template', getIdFromGraphQLId(id), fullPath);
});
it('filters the dropdown items to the selected group and children', async () => {
@@ -188,7 +216,7 @@ describe('NewProjectUrlSelect component', () => {
});
it('sets the selection to the group', async () => {
- expect(findDropdown().props('text')).toBe(data.currentUser.groups.nodes[1].fullPath);
+ expect(findDropdown().props('text')).toBe(fullPath);
});
});
@@ -214,12 +242,13 @@ describe('NewProjectUrlSelect component', () => {
});
it('emits `update-visibility` event to update the visibility radio options', async () => {
- wrapper = mountComponent();
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ wrapper = mountComponent({ mountFn: mount });
const spy = jest.spyOn(eventHub, '$emit');
+ // Show dropdown to fetch projects
+ await showDropdown();
+
await clickDropdownItem();
const namespace = data.currentUser.groups.nodes[0];
@@ -233,16 +262,16 @@ describe('NewProjectUrlSelect component', () => {
});
it('updates hidden input with selected namespace', async () => {
- wrapper = mountComponent();
- jest.runOnlyPendingTimers();
- await wrapper.vm.$nextTick();
+ wrapper = mountComponent({ mountFn: mount });
+
+ // Show dropdown to fetch projects
+ await showDropdown();
await clickDropdownItem();
- expect(findHiddenInput().attributes()).toMatchObject({
- name: 'project[namespace_id]',
- value: getIdFromGraphQLId(data.currentUser.groups.nodes[0].id).toString(),
- });
+ expect(findHiddenInput().attributes('value')).toBe(
+ getIdFromGraphQLId(data.currentUser.groups.nodes[0].id).toString(),
+ );
});
it('tracks clicking on the dropdown', () => {