Commit 5c731d5a authored by Phil Hughes's avatar Phil Hughes

Merge branch '249556-use-mock-apollo-client-spec' into 'master'

Use mock-apollo-provider in SAST UI tests

See merge request gitlab-org/gitlab!52897
parents 1b52bc22 6b57808b
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import AnalyzerConfiguration from 'ee/security_configuration/sast/components/analyzer_configuration.vue'; import AnalyzerConfiguration from 'ee/security_configuration/sast/components/analyzer_configuration.vue';
import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue'; import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue';
import { makeAnalyzerEntities, makeEntities, makeSastCiConfiguration } from './helpers'; import { makeAnalyzerEntities, makeEntities, makeSastCiConfiguration } from '../helpers';
describe('AnalyzerConfiguration component', () => { describe('AnalyzerConfiguration component', () => {
let wrapper; let wrapper;
......
import { merge } from 'lodash';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import { GlLink, GlLoadingIcon, GlSprintf } from '@gitlab/ui'; import { GlLink, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import SASTConfigurationApp from 'ee/security_configuration/sast/components/app.vue'; import SASTConfigurationApp from 'ee/security_configuration/sast/components/app.vue';
import ConfigurationForm from 'ee/security_configuration/sast/components/configuration_form.vue'; import ConfigurationForm from 'ee/security_configuration/sast/components/configuration_form.vue';
import { makeSastCiConfiguration } from './helpers'; import { stripTypenames } from 'helpers/graphql_helpers';
import createMockApollo from 'helpers/mock_apollo_helper';
import sastCiConfigurationQuery from 'ee/security_configuration/sast/graphql/sast_ci_configuration.query.graphql';
import { sastCiConfigurationQueryResponse } from '../mock_data';
Vue.use(VueApollo);
const sastDocumentationPath = '/help/sast'; const sastDocumentationPath = '/help/sast';
const projectPath = 'namespace/project'; const projectPath = 'namespace/project';
...@@ -10,29 +18,29 @@ const projectPath = 'namespace/project'; ...@@ -10,29 +18,29 @@ const projectPath = 'namespace/project';
describe('SAST Configuration App', () => { describe('SAST Configuration App', () => {
let wrapper; let wrapper;
const createComponent = ({ const pendingHandler = () => new Promise(() => {});
stubs = {}, const successHandler = async () => sastCiConfigurationQueryResponse;
loading = true, const failureHandler = async () => ({ errors: [{ message: 'some error' }] });
hasLoadingError = false, const createMockApolloProvider = (handler) =>
sastCiConfiguration = null, createMockApollo([[sastCiConfigurationQuery, handler]]);
} = {}) => {
wrapper = shallowMount(SASTConfigurationApp, { const createComponent = (options) => {
mocks: { $apollo: { loading } }, wrapper = shallowMount(
stubs, SASTConfigurationApp,
provide: { merge(
sastDocumentationPath, {
projectPath, // Use a function reference here so it's lazily initialized, and can
}, // be replaced with other handlers in certain tests without
// While setting data is usually frowned upon, it is the documented way // initialising twice.
// of mocking GraphQL response data: apolloProvider: () => createMockApolloProvider(successHandler),
// https://docs.gitlab.com/ee/development/fe_guide/graphql.html#testing provide: {
data() { sastDocumentationPath,
return { projectPath,
hasLoadingError, },
sastCiConfiguration, },
}; options,
}, ),
}); );
}; };
const findHeader = () => wrapper.find('header'); const findHeader = () => wrapper.find('header');
...@@ -98,7 +106,7 @@ describe('SAST Configuration App', () => { ...@@ -98,7 +106,7 @@ describe('SAST Configuration App', () => {
describe('when loading', () => { describe('when loading', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
loading: true, apolloProvider: createMockApolloProvider(pendingHandler),
}); });
}); });
...@@ -118,8 +126,7 @@ describe('SAST Configuration App', () => { ...@@ -118,8 +126,7 @@ describe('SAST Configuration App', () => {
describe('when loading failed', () => { describe('when loading failed', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent({
loading: false, apolloProvider: createMockApolloProvider(failureHandler),
hasLoadingError: true,
}); });
}); });
...@@ -137,14 +144,8 @@ describe('SAST Configuration App', () => { ...@@ -137,14 +144,8 @@ describe('SAST Configuration App', () => {
}); });
describe('when loaded', () => { describe('when loaded', () => {
let sastCiConfiguration;
beforeEach(() => { beforeEach(() => {
sastCiConfiguration = makeSastCiConfiguration(); createComponent();
createComponent({
loading: false,
sastCiConfiguration,
});
}); });
it('does not display a loading spinner', () => { it('does not display a loading spinner', () => {
...@@ -156,7 +157,9 @@ describe('SAST Configuration App', () => { ...@@ -156,7 +157,9 @@ describe('SAST Configuration App', () => {
}); });
it('passes the sastCiConfiguration to the sastCiConfiguration prop', () => { it('passes the sastCiConfiguration to the sastCiConfiguration prop', () => {
expect(findConfigurationForm().props('sastCiConfiguration')).toBe(sastCiConfiguration); expect(findConfigurationForm().props('sastCiConfiguration')).toEqual(
stripTypenames(sastCiConfigurationQueryResponse.data.project.sastCiConfiguration),
);
}); });
it('does not display an alert message', () => { it('does not display an alert message', () => {
......
...@@ -8,7 +8,7 @@ import ExpandableSection from 'ee/security_configuration/sast/components/expanda ...@@ -8,7 +8,7 @@ import ExpandableSection from 'ee/security_configuration/sast/components/expanda
import configureSastMutation from 'ee/security_configuration/sast/graphql/configure_sast.mutation.graphql'; import configureSastMutation from 'ee/security_configuration/sast/graphql/configure_sast.mutation.graphql';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import * as Sentry from '~/sentry/wrapper'; import * as Sentry from '~/sentry/wrapper';
import { makeEntities, makeSastCiConfiguration } from './helpers'; import { makeEntities, makeSastCiConfiguration } from '../helpers';
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(), redirectTo: jest.fn(),
......
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue'; import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue';
import { makeEntities } from './helpers'; import { makeEntities } from '../helpers';
describe('DynamicFields component', () => { describe('DynamicFields component', () => {
let wrapper; let wrapper;
......
...@@ -4,7 +4,7 @@ import { ...@@ -4,7 +4,7 @@ import {
toSastCiConfigurationEntityInput, toSastCiConfigurationEntityInput,
toSastCiConfigurationAnalyzerEntityInput, toSastCiConfigurationAnalyzerEntityInput,
} from 'ee/security_configuration/sast/components/utils'; } from 'ee/security_configuration/sast/components/utils';
import { makeEntities, makeAnalyzerEntities } from './helpers'; import { makeEntities, makeAnalyzerEntities } from '../helpers';
describe('isValidConfigurationEntity', () => { describe('isValidConfigurationEntity', () => {
const validEntities = makeEntities(3); const validEntities = makeEntities(3);
......
...@@ -15,6 +15,7 @@ export const makeEntities = (count, changes) => ...@@ -15,6 +15,7 @@ export const makeEntities = (count, changes) =>
label: `label${i}`, label: `label${i}`,
type: 'string', type: 'string',
value: `value${i}`, value: `value${i}`,
size: `MEDIUM`,
...changes, ...changes,
})); }));
......
import { makeEntities } from './helpers';
export const sastCiConfigurationQueryResponse = {
data: {
project: {
sastCiConfiguration: {
global: {
nodes: makeEntities(2, { __typename: 'SastCiConfigurationEntity' }),
__typename: 'SastCiConfigurationEntityConnection',
},
pipeline: {
nodes: makeEntities(2, { __typename: 'SastCiConfigurationEntity' }),
__typename: 'SastCiConfigurationEntityConnection',
},
analyzers: {
nodes: [
{
description: 'Ruby on Rails',
enabled: false,
label: 'Brakeman',
name: 'brakeman',
variables: {
nodes: makeEntities(2, { __typename: 'SastCiConfigurationEntity' }),
__typename: 'SastCiConfigurationEntityConnection',
},
__typename: 'SastCiConfigurationAnalyzersEntity',
},
{
description: 'Python',
enabled: false,
label: 'Bandit',
name: 'bandit',
variables: {
nodes: [],
__typename: 'SastCiConfigurationEntityConnection',
},
__typename: 'SastCiConfigurationAnalyzersEntity',
},
],
__typename: 'SastCiConfigurationAnalyzersEntityConnection',
},
__typename: 'SastCiConfiguration',
},
__typename: 'Project',
},
},
};
/**
* Returns a clone of the given object with all __typename keys omitted,
* including deeply nested ones.
*
* Only works with JSON-serializable objects.
*
* @param {object} An object with __typename keys (e.g., a GraphQL response)
* @returns {object} A new object with no __typename keys
*/
export const stripTypenames = (object) => {
return JSON.parse(
JSON.stringify(object, (key, value) => (key === '__typename' ? undefined : value)),
);
};
import { stripTypenames } from './graphql_helpers';
describe('stripTypenames', () => {
it.each`
input | expected
${{}} | ${{}}
${{ __typename: 'Foo' }} | ${{}}
${{ bar: 'bar', __typename: 'Foo' }} | ${{ bar: 'bar' }}
${{ bar: { __typename: 'Bar' }, __typename: 'Foo' }} | ${{ bar: {} }}
${{ bar: [{ __typename: 'Bar' }], __typename: 'Foo' }} | ${{ bar: [{}] }}
${[]} | ${[]}
${[{ __typename: 'Foo' }]} | ${[{}]}
${[{ bar: [{ a: 1, __typename: 'Bar' }] }]} | ${[{ bar: [{ a: 1 }] }]}
`('given $input returns $expected, with all __typename keys removed', ({ input, expected }) => {
const actual = stripTypenames(input);
expect(actual).toEqual(expected);
expect(input).not.toBe(actual);
});
it('given null returns null', () => {
expect(stripTypenames(null)).toEqual(null);
});
});
import { mount, createLocalVue } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { merge } from 'lodash'; import { merge } from 'lodash';
import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -26,8 +27,8 @@ import securityReportDownloadPathsQuery from '~/vue_shared/security_reports/quer ...@@ -26,8 +27,8 @@ import securityReportDownloadPathsQuery from '~/vue_shared/security_reports/quer
jest.mock('~/flash'); jest.mock('~/flash');
const localVue = createLocalVue(); Vue.use(VueApollo);
localVue.use(Vuex); Vue.use(Vuex);
const SAST_COMPARISON_PATH = '/sast.json'; const SAST_COMPARISON_PATH = '/sast.json';
const SECRET_SCANNING_COMPARISON_PATH = '/secret_detection.json'; const SECRET_SCANNING_COMPARISON_PATH = '/secret_detection.json';
...@@ -47,7 +48,6 @@ describe('Security reports app', () => { ...@@ -47,7 +48,6 @@ describe('Security reports app', () => {
SecurityReportsApp, SecurityReportsApp,
merge( merge(
{ {
localVue,
propsData: { ...props }, propsData: { ...props },
stubs: { stubs: {
HelpIcon: true, HelpIcon: true,
...@@ -64,8 +64,6 @@ describe('Security reports app', () => { ...@@ -64,8 +64,6 @@ describe('Security reports app', () => {
Promise.resolve({ data: securityReportDownloadPathsQueryNoArtifactsResponse }); Promise.resolve({ data: securityReportDownloadPathsQueryNoArtifactsResponse });
const failureHandler = () => Promise.resolve({ errors: [{ message: 'some error' }] }); const failureHandler = () => Promise.resolve({ errors: [{ message: 'some error' }] });
const createMockApolloProvider = (handler) => { const createMockApolloProvider = (handler) => {
localVue.use(VueApollo);
const requestHandlers = [[securityReportDownloadPathsQuery, handler]]; const requestHandlers = [[securityReportDownloadPathsQuery, handler]];
return createMockApollo(requestHandlers); return createMockApollo(requestHandlers);
......
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