Commit 6568965c authored by Illya Klymov's avatar Illya Klymov

Merge branch 'refactor-training-graphql' into 'master'

Update TrainingProviderList to use Apollo

See merge request gitlab-org/gitlab!76777
parents 535b7c49 daa15704
......@@ -4,7 +4,6 @@ import { __, s__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import UserCalloutDismisser from '~/vue_shared/components/user_callout_dismisser.vue';
import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql';
import AutoDevOpsAlert from './auto_dev_ops_alert.vue';
import AutoDevOpsEnabledAlert from './auto_dev_ops_enabled_alert.vue';
import { AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY } from './constants';
......@@ -88,7 +87,6 @@ export default {
return {
autoDevopsEnabledAlertDismissedProjects: [],
errorMessage: '',
securityTrainingProviders: [],
};
},
computed: {
......@@ -110,11 +108,6 @@ export default {
);
},
},
apollo: {
securityTrainingProviders: {
query: securityTrainingProvidersQuery,
},
},
methods: {
dismissAutoDevopsEnabledAlert() {
const dismissedProjects = new Set(this.autoDevopsEnabledAlertDismissedProjects);
......@@ -251,10 +244,7 @@ export default {
>
<section-layout :heading="$options.i18n.securityTraining">
<template #features>
<training-provider-list
:loading="$apollo.queries.securityTrainingProviders.loading"
:providers="securityTrainingProviders"
/>
<training-provider-list />
</template>
</section-layout>
</gl-tab>
......
<script>
import { GlCard, GlToggle, GlLink, GlSkeletonLoader } from '@gitlab/ui';
import securityTrainingProvidersQuery from '../graphql/security_training_providers.query.graphql';
export default {
components: {
......@@ -8,15 +9,19 @@ export default {
GlLink,
GlSkeletonLoader,
},
props: {
providers: {
type: Array,
required: true,
apollo: {
securityTrainingProviders: {
query: securityTrainingProvidersQuery,
},
loading: {
type: Boolean,
required: false,
default: false,
},
data() {
return {
securityTrainingProviders: [],
};
},
computed: {
isLoading() {
return this.$apollo.queries.securityTrainingProviders.loading;
},
},
};
......@@ -24,7 +29,7 @@ export default {
<template>
<div
v-if="loading"
v-if="isLoading"
class="gl-bg-white gl-py-6 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100"
>
<gl-skeleton-loader :width="350" :height="44">
......@@ -34,7 +39,11 @@ export default {
</gl-skeleton-loader>
</div>
<ul v-else class="gl-list-style-none gl-m-0 gl-p-0">
<li v-for="{ id, isEnabled, name, description, url } in providers" :key="id" class="gl-mb-6">
<li
v-for="{ id, isEnabled, name, description, url } in securityTrainingProviders"
:key="id"
class="gl-mb-6"
>
<gl-card>
<div class="gl-display-flex">
<gl-toggle :value="isEnabled" :label="__('Training mode')" label-position="hidden" />
......
import { GlTab } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { nextTick } from 'vue';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
import stubChildren from 'helpers/stub_children';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import SecurityConfigurationApp, { i18n } from '~/security_configuration/components/app.vue';
import AutoDevopsAlert from '~/security_configuration/components/auto_dev_ops_alert.vue';
import AutoDevopsEnabledAlert from '~/security_configuration/components/auto_dev_ops_enabled_alert.vue';
......@@ -29,8 +27,6 @@ import {
REPORT_TYPE_LICENSE_COMPLIANCE,
REPORT_TYPE_SAST,
} from '~/vue_shared/security_reports/constants';
import waitForPromises from 'helpers/wait_for_promises';
import { securityTrainingProviders } from '../mock_data';
const upgradePath = '/upgrade';
const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath';
......@@ -39,21 +35,10 @@ const gitlabCiHistoryPath = 'test/historyPath';
const projectPath = 'namespace/project';
useLocalStorageSpy();
Vue.use(VueApollo);
describe('App component', () => {
let wrapper;
let userCalloutDismissSpy;
let mockApollo;
let mockSecurityTrainingProvidersData;
const mockResolvers = {
Query: {
securityTrainingProviders() {
return securityTrainingProviders;
},
},
};
const createComponent = ({
shouldShowCallout = true,
......@@ -61,11 +46,9 @@ describe('App component', () => {
...propsData
}) => {
userCalloutDismissSpy = jest.fn();
mockApollo = createMockApollo([], mockResolvers);
wrapper = extendedWrapper(
mount(SecurityConfigurationApp, {
apolloProvider: mockApollo,
propsData,
provide: {
upgradePath,
......@@ -148,14 +131,10 @@ describe('App component', () => {
afterEach(() => {
wrapper.destroy();
mockApollo = null;
});
describe('basic structure', () => {
beforeEach(() => {
mockSecurityTrainingProvidersData = jest.fn();
mockSecurityTrainingProvidersData.mockResolvedValue(securityTrainingProviders);
createComponent({
augmentedSecurityFeatures: securityFeaturesMock,
augmentedComplianceFeatures: complianceFeaturesMock,
......@@ -204,9 +183,8 @@ describe('App component', () => {
expect(findSecurityViewHistoryLink().exists()).toBe(false);
});
it('renders training provider list with correct props', async () => {
await waitForPromises();
expect(findTrainingProviderList().props('providers')).toEqual(securityTrainingProviders);
it('renders TrainingProviderList component', () => {
expect(findTrainingProviderList().exists()).toBe(true);
});
});
......
import { 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 { securityTrainingProviders } from '../mock_data';
import waitForPromises from 'helpers/wait_for_promises';
import { securityTrainingProviders, mockResolvers } from '../mock_data';
const DEFAULT_PROPS = {
providers: securityTrainingProviders,
};
Vue.use(VueApollo);
describe('TrainingProviderList component', () => {
let wrapper;
let mockApollo;
let mockSecurityTrainingProvidersData;
const createComponent = () => {
mockApollo = createMockApollo([], mockResolvers);
const createComponent = (props = {}) => {
wrapper = shallowMount(TrainingProviderList, {
propsData: {
...DEFAULT_PROPS,
...props,
},
apolloProvider: mockApollo,
});
};
const waitForQueryToBeLoaded = () => waitForPromises();
const findCards = () => wrapper.findAllComponents(GlCard);
const findLinks = () => wrapper.findAllComponents(GlLink);
const findToggles = () => wrapper.findAllComponents(GlToggle);
const findLoader = () => wrapper.findComponent(GlSkeletonLoader);
beforeEach(() => {
mockSecurityTrainingProvidersData = jest.fn();
mockSecurityTrainingProvidersData.mockResolvedValue(securityTrainingProviders);
createComponent();
});
afterEach(() => {
wrapper.destroy();
mockApollo = null;
});
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(() => {
createComponent();
beforeEach(async () => {
await waitForQueryToBeLoaded();
});
it('renders correct amount of cards', () => {
expect(findCards()).toHaveLength(DEFAULT_PROPS.providers.length);
expect(findCards()).toHaveLength(securityTrainingProviders.length);
});
DEFAULT_PROPS.providers.forEach(({ name, description, url, isEnabled }, index) => {
securityTrainingProviders.forEach(({ name, description, url, isEnabled }, index) => {
it(`shows the name for card ${index}`, () => {
expect(findCards().at(index).text()).toContain(name);
});
......@@ -56,25 +79,10 @@ describe('TrainingProviderList component', () => {
it(`shows the toggle with the correct value for card ${index}`, () => {
expect(findToggles().at(index).props('value')).toEqual(isEnabled);
});
});
});
describe('loading', () => {
beforeEach(() => {
createComponent({ loading: true });
});
it('shows the loader', () => {
expect(findLoader().exists()).toBe(true);
});
it('does not show the cards', () => {
expect(findCards().exists()).toBe(false);
});
it('does not show loader when not loading', () => {
createComponent({ loading: false });
expect(findLoader().exists()).toBe(false);
it('does not show loader when query is populated', () => {
expect(findLoader().exists()).toBe(false);
});
});
});
});
......@@ -20,3 +20,11 @@ export const securityTrainingProvidersResponse = {
securityTrainingProviders,
},
};
export const mockResolvers = {
Query: {
securityTrainingProviders() {
return securityTrainingProviders;
},
},
};
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