diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
commit | edaa33dee2ff2f7ea3fac488d41558eb5f86d68c (patch) | |
tree | 11f143effbfeba52329fb7afbd05e6e2a3790241 /spec/frontend/security_configuration | |
parent | d8a5691316400a0f7ec4f83832698f1988eb27c1 (diff) |
Add latest changes from gitlab-org/gitlab@14-7-stable-eev14.7.0-rc42
Diffstat (limited to 'spec/frontend/security_configuration')
3 files changed, 193 insertions, 51 deletions
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js index 0a2b18caf25..cbdf7f53913 100644 --- a/spec/frontend/security_configuration/components/app_spec.js +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -1,4 +1,4 @@ -import { GlTab } from '@gitlab/ui'; +import { GlTab, GlTabs } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { nextTick } from 'vue'; import { useLocalStorageSpy } from 'helpers/local_storage_helper'; @@ -77,6 +77,7 @@ describe('App component', () => { const findMainHeading = () => wrapper.find('h1'); const findTab = () => wrapper.findComponent(GlTab); const findTabs = () => wrapper.findAllComponents(GlTab); + const findGlTabs = () => wrapper.findComponent(GlTabs); const findByTestId = (id) => wrapper.findByTestId(id); const findFeatureCards = () => wrapper.findAllComponents(FeatureCard); const findTrainingProviderList = () => wrapper.findComponent(TrainingProviderList); @@ -154,6 +155,14 @@ describe('App component', () => { expect(findTab().exists()).toBe(true); }); + it('passes the `sync-active-tab-with-query-params` prop', () => { + expect(findGlTabs().props('syncActiveTabWithQueryParams')).toBe(true); + }); + + it('lazy loads each tab', () => { + expect(findGlTabs().attributes('lazy')).not.toBe(undefined); + }); + it('renders correct amount of tabs', () => { expect(findTabs()).toHaveLength(expectedTabs.length); }); @@ -161,6 +170,10 @@ describe('App component', () => { it.each(expectedTabs)('renders the %s tab', (tabName) => { expect(findByTestId(`${tabName}-tab`).exists()).toBe(true); }); + + it.each(expectedTabs)('has the %s query-param-value', (tabName) => { + expect(findByTestId(`${tabName}-tab`).props('queryParamValue')).toBe(tabName); + }); }); it('renders right amount of feature cards for given props with correct props', () => { @@ -182,10 +195,6 @@ describe('App component', () => { expect(findComplianceViewHistoryLink().exists()).toBe(false); expect(findSecurityViewHistoryLink().exists()).toBe(false); }); - - it('renders TrainingProviderList component', () => { - expect(findTrainingProviderList().exists()).toBe(true); - }); }); describe('Manage via MR Error Alert', () => { @@ -432,6 +441,25 @@ describe('App component', () => { }); }); + describe('Vulnerability management', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + }); + }); + + it('renders TrainingProviderList component', () => { + expect(findTrainingProviderList().exists()).toBe(true); + }); + + it('renders security training description', () => { + const vulnerabilityManagementTab = wrapper.findByTestId('vulnerability-management-tab'); + + expect(vulnerabilityManagementTab.text()).toContain(i18n.securityTrainingDescription); + }); + }); + describe('when secureVulnerabilityTraining feature flag is disabled', () => { beforeEach(() => { createComponent({ diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js index 60cc36a634c..578248e696f 100644 --- a/spec/frontend/security_configuration/components/training_provider_list_spec.js +++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js @@ -1,87 +1,192 @@ -import { GlLink, GlToggle, GlCard, GlSkeletonLoader } from '@gitlab/ui'; +import { GlAlert, GlLink, GlToggle, GlCard, GlSkeletonLoader } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue'; +import configureSecurityTrainingProvidersMutation from '~/security_configuration/graphql/configure_security_training_providers.mutation.graphql'; import waitForPromises from 'helpers/wait_for_promises'; -import { securityTrainingProviders, mockResolvers } from '../mock_data'; +import { + securityTrainingProviders, + createMockResolvers, + testProjectPath, + textProviderIds, +} from '../mock_data'; Vue.use(VueApollo); describe('TrainingProviderList component', () => { let wrapper; - let mockApollo; - let mockSecurityTrainingProvidersData; + let apolloProvider; - const createComponent = () => { - mockApollo = createMockApollo([], mockResolvers); + const createApolloProvider = ({ resolvers } = {}) => { + apolloProvider = createMockApollo([], createMockResolvers({ resolvers })); + }; + const createComponent = () => { wrapper = shallowMount(TrainingProviderList, { - apolloProvider: mockApollo, + provide: { + projectPath: testProjectPath, + }, + apolloProvider, }); }; const waitForQueryToBeLoaded = () => waitForPromises(); + const waitForMutationToBeLoaded = waitForQueryToBeLoaded; const findCards = () => wrapper.findAllComponents(GlCard); const findLinks = () => wrapper.findAllComponents(GlLink); const findToggles = () => wrapper.findAllComponents(GlToggle); + const findFirstToggle = () => findToggles().at(0); const findLoader = () => wrapper.findComponent(GlSkeletonLoader); + const findErrorAlert = () => wrapper.findComponent(GlAlert); - beforeEach(() => { - mockSecurityTrainingProvidersData = jest.fn(); - mockSecurityTrainingProvidersData.mockResolvedValue(securityTrainingProviders); - - createComponent(); - }); + const toggleFirstProvider = () => findFirstToggle().vm.$emit('change'); afterEach(() => { wrapper.destroy(); - mockApollo = null; + apolloProvider = null; }); - describe('when loading', () => { - it('shows the loader', () => { - expect(findLoader().exists()).toBe(true); + describe('with a successful response', () => { + beforeEach(() => { + createApolloProvider(); + createComponent(); }); - it('does not show the cards', () => { - expect(findCards().exists()).toBe(false); + describe('when loading', () => { + it('shows the loader', () => { + expect(findLoader().exists()).toBe(true); + }); + + it('does not show the cards', () => { + expect(findCards().exists()).toBe(false); + }); }); - }); - describe('basic structure', () => { - beforeEach(async () => { - await waitForQueryToBeLoaded(); + describe('basic structure', () => { + beforeEach(async () => { + await waitForQueryToBeLoaded(); + }); + + it('renders correct amount of cards', () => { + expect(findCards()).toHaveLength(securityTrainingProviders.length); + }); + + securityTrainingProviders.forEach(({ name, description, url, isEnabled }, index) => { + it(`shows the name for card ${index}`, () => { + expect(findCards().at(index).text()).toContain(name); + }); + + it(`shows the description for card ${index}`, () => { + expect(findCards().at(index).text()).toContain(description); + }); + + it(`shows the learn more link for card ${index}`, () => { + expect(findLinks().at(index).attributes()).toEqual({ + target: '_blank', + href: url, + }); + }); + + it(`shows the toggle with the correct value for card ${index}`, () => { + expect(findToggles().at(index).props('value')).toEqual(isEnabled); + }); + + it('does not show loader when query is populated', () => { + expect(findLoader().exists()).toBe(false); + }); + }); }); - it('renders correct amount of cards', () => { - expect(findCards()).toHaveLength(securityTrainingProviders.length); + describe('storing training provider settings', () => { + beforeEach(async () => { + jest.spyOn(apolloProvider.defaultClient, 'mutate'); + + await waitForMutationToBeLoaded(); + + toggleFirstProvider(); + }); + + it.each` + loading | wait | desc + ${true} | ${false} | ${'enables loading of GlToggle when mutation is called'} + ${false} | ${true} | ${'disables loading of GlToggle when mutation is complete'} + `('$desc', async ({ loading, wait }) => { + if (wait) { + await waitForMutationToBeLoaded(); + } + expect(findFirstToggle().props('isLoading')).toBe(loading); + }); + + it('calls mutation when toggle is changed', () => { + expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith( + expect.objectContaining({ + mutation: configureSecurityTrainingProvidersMutation, + variables: { input: { enabledProviders: textProviderIds, fullPath: testProjectPath } }, + }), + ); + }); }); + }); + + describe('with errors', () => { + const expectErrorAlertToExist = () => { + expect(findErrorAlert().props()).toMatchObject({ + dismissible: false, + variant: 'danger', + }); + }; + + describe('when fetching training providers', () => { + beforeEach(async () => { + createApolloProvider({ + resolvers: { + Query: { + securityTrainingProviders: jest.fn().mockReturnValue(new Error()), + }, + }, + }); + createComponent(); - securityTrainingProviders.forEach(({ name, description, url, isEnabled }, index) => { - it(`shows the name for card ${index}`, () => { - expect(findCards().at(index).text()).toContain(name); + await waitForQueryToBeLoaded(); }); - it(`shows the description for card ${index}`, () => { - expect(findCards().at(index).text()).toContain(description); + it('shows an non-dismissible error alert', () => { + expectErrorAlertToExist(); }); - it(`shows the learn more link for card ${index}`, () => { - expect(findLinks().at(index).attributes()).toEqual({ - target: '_blank', - href: url, + it('shows an error description', () => { + expect(findErrorAlert().text()).toBe(TrainingProviderList.i18n.providerQueryErrorMessage); + }); + }); + + describe('when storing training provider configurations', () => { + beforeEach(async () => { + createApolloProvider({ + resolvers: { + Mutation: { + configureSecurityTrainingProviders: () => ({ + errors: ['something went wrong!'], + securityTrainingProviders: [], + }), + }, + }, }); + createComponent(); + + await waitForQueryToBeLoaded(); + toggleFirstProvider(); + await waitForMutationToBeLoaded(); }); - it(`shows the toggle with the correct value for card ${index}`, () => { - expect(findToggles().at(index).props('value')).toEqual(isEnabled); + it('shows an non-dismissible error alert', () => { + expectErrorAlertToExist(); }); - it('does not show loader when query is populated', () => { - expect(findLoader().exists()).toBe(false); + it('shows an error description', () => { + expect(findErrorAlert().text()).toBe(TrainingProviderList.i18n.configMutationErrorMessage); }); }); }); diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js index cdb859c3800..37ecce3886d 100644 --- a/spec/frontend/security_configuration/mock_data.js +++ b/spec/frontend/security_configuration/mock_data.js @@ -1,16 +1,20 @@ +export const testProjectPath = 'foo/bar'; + +export const textProviderIds = [101, 102]; + export const securityTrainingProviders = [ { - id: 101, - name: 'Kontra', - description: 'Interactive developer security education.', - url: 'https://application.security/', + id: textProviderIds[0], + name: 'Vendor Name 1', + description: 'Interactive developer security education', + url: 'https://www.example.org/security/training', isEnabled: false, }, { - id: 102, - name: 'SecureCodeWarrior', + id: textProviderIds[1], + name: 'Vendor Name 2', description: 'Security training with guide and learning pathways.', - url: 'https://www.securecodewarrior.com/', + url: 'https://www.vendornametwo.com/', isEnabled: true, }, ]; @@ -21,10 +25,15 @@ export const securityTrainingProvidersResponse = { }, }; -export const mockResolvers = { +const defaultMockResolvers = { Query: { securityTrainingProviders() { return securityTrainingProviders; }, }, }; + +export const createMockResolvers = ({ resolvers: customMockResolvers = {} } = {}) => ({ + ...defaultMockResolvers, + ...customMockResolvers, +}); |