Commit 9e96a467 authored by Mark Florian's avatar Mark Florian Committed by David O'Regan

Deduplicate ManageViaMr specs

Previously the FOSS and EE specs for the ManageViaMr component were very
nearly identical. The only difference between them was a different
parameterisation via `describe.each`.

This removes the EE spec, and makes the FOSS spec rely on the
`ee_else_ce` import alias to switch out the appropriate parameters, such
that the correct tests are run in FOSS and EE modes in CI.
parent 1f170151
import { GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import configureDependencyScanningMutation from 'ee/security_configuration/graphql/configure_dependency_scanning.mutation.graphql';
import configureSecretDetectionMutation from 'ee/security_configuration/graphql/configure_secret_detection.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { buildConfigureSecurityFeatureMockFactory } from 'jest/vue_shared/security_reports/components/apollo_mocks';
import { redirectTo } from '~/lib/utils/url_utility';
import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue';
import {
REPORT_TYPE_DEPENDENCY_SCANNING,
REPORT_TYPE_SECRET_DETECTION,
} from '~/vue_shared/security_reports/constants';
jest.mock('~/lib/utils/url_utility');
Vue.use(VueApollo);
const projectPath = 'namespace/project';
describe('ManageViaMr component', () => {
let wrapper;
const findButton = () => wrapper.findComponent(GlButton);
describe.each`
featureName | featureType | mutation | mutationId
${'SECRET_DETECTION'} | ${REPORT_TYPE_DEPENDENCY_SCANNING} | ${configureDependencyScanningMutation} | ${'configureDependencyScanning'}
${'DEPENDENCY_SCANNING'} | ${REPORT_TYPE_SECRET_DETECTION} | ${configureSecretDetectionMutation} | ${'configureSecretDetection'}
`('$featureType', ({ featureName, mutation, featureType, mutationId }) => {
const buildConfigureSecurityFeatureMock = buildConfigureSecurityFeatureMockFactory(mutationId);
const successHandler = jest.fn(async () => buildConfigureSecurityFeatureMock());
const noSuccessPathHandler = async () =>
buildConfigureSecurityFeatureMock({
successPath: '',
});
const errorHandler = async () =>
buildConfigureSecurityFeatureMock({
errors: ['foo'],
});
const pendingHandler = () => new Promise(() => {});
function createMockApolloProvider(handler) {
const requestHandlers = [[mutation, handler]];
return createMockApollo(requestHandlers);
}
function createComponent({ mockApollo, isFeatureConfigured = false } = {}) {
wrapper = extendedWrapper(
mount(ManageViaMr, {
apolloProvider: mockApollo,
provide: {
projectPath,
},
propsData: {
feature: {
name: featureName,
type: featureType,
configured: isFeatureConfigured,
},
},
}),
);
}
afterEach(() => {
wrapper.destroy();
});
describe('when feature is configured', () => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(successHandler);
createComponent({ mockApollo, isFeatureConfigured: true });
});
it('it does not render a button', () => {
expect(findButton().exists()).toBe(false);
});
});
describe('when feature is not configured', () => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(successHandler);
createComponent({ mockApollo, isFeatureConfigured: false });
});
it('it does render a button', () => {
expect(findButton().exists()).toBe(true);
});
it('clicking on the button triggers the configure mutation', () => {
findButton().trigger('click');
expect(successHandler).toHaveBeenCalledTimes(1);
expect(successHandler).toHaveBeenCalledWith({
input: {
projectPath,
},
});
});
});
describe('given a pending response', () => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(pendingHandler);
createComponent({ mockApollo });
});
it('renders spinner correctly', async () => {
const button = findButton();
expect(button.props('loading')).toBe(false);
await button.trigger('click');
expect(button.props('loading')).toBe(true);
});
});
describe('given a successful response', () => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(successHandler);
createComponent({ mockApollo });
});
it('should call redirect helper with correct value', async () => {
await wrapper.trigger('click');
await waitForPromises();
expect(redirectTo).toHaveBeenCalledTimes(1);
expect(redirectTo).toHaveBeenCalledWith('testSuccessPath');
// This is done for UX reasons. If the loading prop is set to false
// on success, then there's a period where the button is clickable
// again. Instead, we want the button to display a loading indicator
// for the remainder of the lifetime of the page (i.e., until the
// browser can start painting the new page it's been redirected to).
expect(findButton().props().loading).toBe(true);
});
});
describe.each`
handler | message
${noSuccessPathHandler} | ${`${featureName} merge request creation mutation failed`}
${errorHandler} | ${'foo'}
`('given an error response', ({ handler, message }) => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(handler);
createComponent({ mockApollo });
});
it('should catch and emit error', async () => {
await wrapper.trigger('click');
await waitForPromises();
expect(wrapper.emitted('error')).toEqual([[message]]);
expect(findButton().props('loading')).toBe(false);
});
});
});
});
...@@ -2,13 +2,13 @@ import { GlButton } from '@gitlab/ui'; ...@@ -2,13 +2,13 @@ import { GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { featureToMutationMap } from 'ee_else_ce/security_configuration/components/constants';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { humanize } from '~/lib/utils/text_utility';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import configureSast from '~/security_configuration/graphql/configure_sast.mutation.graphql';
import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue'; import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue';
import { REPORT_TYPE_SAST } from '~/vue_shared/security_reports/constants';
import { buildConfigureSecurityFeatureMockFactory } from './apollo_mocks'; import { buildConfigureSecurityFeatureMockFactory } from './apollo_mocks';
jest.mock('~/lib/utils/url_utility'); jest.mock('~/lib/utils/url_utility');
...@@ -19,10 +19,18 @@ describe('ManageViaMr component', () => { ...@@ -19,10 +19,18 @@ describe('ManageViaMr component', () => {
let wrapper; let wrapper;
const findButton = () => wrapper.findComponent(GlButton); const findButton = () => wrapper.findComponent(GlButton);
describe.each`
featureName | featureType | mutation | mutationId // This component supports different report types/mutations depending on
${'SAST'} | ${REPORT_TYPE_SAST} | ${configureSast} | ${'configureSast'} // whether it's in a CE or EE context. This makes sure we are only testing
`('$featureType', ({ featureName, mutation, featureType, mutationId }) => { // the ones available in the current test context.
const supportedReportTypes = Object.entries(featureToMutationMap).map(
([featureType, { getMutationPayload, mutationId }]) => {
const { mutation } = getMutationPayload();
return [humanize(featureType), featureType, mutation, mutationId];
},
);
describe.each(supportedReportTypes)('%s', (featureName, featureType, mutation, mutationId) => {
const buildConfigureSecurityFeatureMock = buildConfigureSecurityFeatureMockFactory(mutationId); const buildConfigureSecurityFeatureMock = buildConfigureSecurityFeatureMockFactory(mutationId);
const successHandler = async () => buildConfigureSecurityFeatureMock(); const successHandler = async () => buildConfigureSecurityFeatureMock();
const noSuccessPathHandler = async () => const noSuccessPathHandler = async () =>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment