Commit 4223146f authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch '321650-mlunoe-migrate-step-components-to-use-local-graphql-state' into 'master'

Feat(Purchase Flow): migrate step components to use GraphQL

See merge request gitlab-org/gitlab!57331
parents 8aa6760b 40455082
<script> <script>
import StepOrderApp from 'ee/vue_shared/components/step_order_app.vue'; import StepOrderApp from 'ee/vue_shared/purchase_flow/components/step_order_app.vue';
export default { export default {
components: { components: {
......
<script> <script>
import StepOrderApp from 'ee/vue_shared/components/step_order_app.vue'; import StepOrderApp from 'ee/vue_shared/purchase_flow/components/step_order_app.vue';
import Checkout from './checkout.vue'; import Checkout from './checkout.vue';
import OrderSummary from './order_summary.vue'; import OrderSummary from './order_summary.vue';
......
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
import { GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui'; import { GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import Step from './step.vue'; import { STEPS } from '../../constants';
export default { export default {
components: { components: {
...@@ -128,11 +129,12 @@ export default { ...@@ -128,11 +129,12 @@ export default {
stateSelectPrompt: s__('Checkout|Please select a state'), stateSelectPrompt: s__('Checkout|Please select a state'),
zipCodeLabel: s__('Checkout|Zip code'), zipCodeLabel: s__('Checkout|Zip code'),
}, },
stepId: STEPS[1].id,
}; };
</script> </script>
<template> <template>
<step <step
step="billingAddress" :step-id="$options.stepId"
:title="$options.i18n.stepTitle" :title="$options.i18n.stepTitle"
:is-valid="isValid" :is-valid="isValid"
:next-step-button-text="$options.i18n.nextStepButtonText" :next-step-button-text="$options.i18n.nextStepButtonText"
......
<script> <script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui'; import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions } from 'vuex';
import activeStepQuery from 'ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { STEPS } from '../../constants';
export default { export default {
components: { components: {
GlButton, GlButton,
GlLoadingIcon, GlLoadingIcon,
}, },
data() {
return {
isActive: {},
};
},
apollo: {
isActive: {
query: activeStepQuery,
update: ({ activeStep }) => activeStep.id === STEPS[3].id,
},
},
computed: { computed: {
...mapState(['isConfirmingOrder']), ...mapState(['isConfirmingOrder']),
...mapGetters(['currentStep']),
isActive() {
return this.currentStep === 'confirmOrder';
},
}, },
methods: { methods: {
...mapActions(['confirmOrder']), ...mapActions(['confirmOrder']),
......
<script> <script>
import { GlSprintf } from '@gitlab/ui'; import { GlSprintf } from '@gitlab/ui';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import Step from './step.vue'; import { STEPS } from '../../constants';
import Zuora from './zuora.vue'; import Zuora from './zuora.vue';
export default { export default {
...@@ -28,10 +29,11 @@ export default { ...@@ -28,10 +29,11 @@ export default {
creditCardDetails: s__('Checkout|%{cardType} ending in %{lastFourDigits}'), creditCardDetails: s__('Checkout|%{cardType} ending in %{lastFourDigits}'),
expirationDate: s__('Checkout|Exp %{expirationMonth}/%{expirationYear}'), expirationDate: s__('Checkout|Exp %{expirationMonth}/%{expirationYear}'),
}, },
stepId: STEPS[2].id,
}; };
</script> </script>
<template> <template>
<step step="paymentMethod" :title="$options.i18n.stepTitle" :is-valid="isValid"> <step :step-id="$options.stepId" :title="$options.i18n.stepTitle" :is-valid="isValid">
<template #body="props"> <template #body="props">
<zuora :active="props.active" /> <zuora :active="props.active" />
</template> </template>
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui'; import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { NEW_GROUP } from 'ee/subscriptions/new/constants'; import { NEW_GROUP, STEPS } from 'ee/subscriptions/new/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import Step from './step.vue';
export default { export default {
components: { components: {
...@@ -133,11 +133,12 @@ export default { ...@@ -133,11 +133,12 @@ export default {
group: s__('Checkout|Group'), group: s__('Checkout|Group'),
users: s__('Checkout|Users'), users: s__('Checkout|Users'),
}, },
stepId: STEPS[0].id,
}; };
</script> </script>
<template> <template>
<step <step
step="subscriptionDetails" :step-id="$options.stepId"
:title="$options.i18n.stepTitle" :title="$options.i18n.stepTitle"
:is-valid="isValid" :is-valid="isValid"
:next-step-button-text="$options.i18n.nextStepButtonText" :next-step-button-text="$options.i18n.nextStepButtonText"
......
// The order of the steps in this array determines the flow of the application // The order of the steps in this array determines the flow of the application
export const STEPS = ['subscriptionDetails', 'billingAddress', 'paymentMethod', 'confirmOrder']; /* eslint-disable @gitlab/require-i18n-strings */
export const STEPS = [
{ id: 'subscriptionDetails', __typename: 'Step' },
{ id: 'billingAddress', __typename: 'Step' },
{ id: 'paymentMethod', __typename: 'Step' },
{ id: 'confirmOrder', __typename: 'Step' },
];
/* eslint-enable @gitlab/require-i18n-strings */
export const ZUORA_SCRIPT_URL = 'https://static.zuora.com/Resources/libs/hosted/1.3.1/zuora-min.js'; export const ZUORA_SCRIPT_URL = 'https://static.zuora.com/Resources/libs/hosted/1.3.1/zuora-min.js';
......
import activeStepQuery from 'ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql';
import stepListQuery from 'ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql';
import resolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers';
import typeDefs from 'ee/vue_shared/purchase_flow/graphql/typedefs.graphql';
import createDefaultClient from '~/lib/graphql';
export default function createClient(stepList) {
const client = createDefaultClient(resolvers, {
typeDefs,
assumeImmutableResults: true,
});
client.cache.writeQuery({
query: stepListQuery,
data: {
stepList,
},
});
client.cache.writeQuery({
query: activeStepQuery,
data: {
activeStep: stepList[0],
},
});
return client;
}
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo';
import App from './components/app.vue'; import App from './components/app.vue';
import { STEPS } from './constants';
import createClient from './graphql';
import createStore from './store'; import createStore from './store';
Vue.use(VueApollo);
const defaultClient = createClient(STEPS);
const apolloProvider = new VueApollo({
defaultClient,
});
export default () => { export default () => {
const el = document.getElementById('js-new-subscription'); const el = document.getElementById('js-new-subscription');
const store = createStore(el.dataset); const store = createStore(el.dataset);
...@@ -9,6 +19,7 @@ export default () => { ...@@ -9,6 +19,7 @@ export default () => {
return new Vue({ return new Vue({
el, el,
store, store,
apolloProvider,
components: { components: {
App, App,
}, },
......
import Api from 'ee/api'; import Api from 'ee/api';
import activateNextStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import { STEPS, PAYMENT_FORM_ID } from '../constants'; import { PAYMENT_FORM_ID } from '../constants';
import defaultClient from '../graphql';
import * as types from './mutation_types'; import * as types from './mutation_types';
export const activateStep = ({ commit }, currentStep) => {
if (STEPS.includes(currentStep)) {
commit(types.UPDATE_CURRENT_STEP, currentStep);
}
};
export const activateNextStep = ({ commit, getters }) => {
const { currentStepIndex } = getters;
if (currentStepIndex < STEPS.length - 1) {
const nextStep = STEPS[currentStepIndex + 1];
commit(types.UPDATE_CURRENT_STEP, nextStep);
}
};
export const updateSelectedPlan = ({ commit }, selectedPlan) => { export const updateSelectedPlan = ({ commit }, selectedPlan) => {
commit(types.UPDATE_SELECTED_PLAN, selectedPlan); commit(types.UPDATE_SELECTED_PLAN, selectedPlan);
}; };
...@@ -180,10 +166,12 @@ export const fetchPaymentMethodDetails = ({ state, dispatch, commit }) => ...@@ -180,10 +166,12 @@ export const fetchPaymentMethodDetails = ({ state, dispatch, commit }) =>
.catch(() => dispatch('fetchPaymentMethodDetailsError')) .catch(() => dispatch('fetchPaymentMethodDetailsError'))
.finally(() => commit(types.UPDATE_IS_LOADING_PAYMENT_METHOD, false)); .finally(() => commit(types.UPDATE_IS_LOADING_PAYMENT_METHOD, false));
export const fetchPaymentMethodDetailsSuccess = ({ commit, dispatch }, creditCardDetails) => { export const fetchPaymentMethodDetailsSuccess = ({ commit }, creditCardDetails) => {
commit(types.UPDATE_CREDIT_CARD_DETAILS, creditCardDetails); commit(types.UPDATE_CREDIT_CARD_DETAILS, creditCardDetails);
dispatch('activateNextStep'); defaultClient.mutate({
mutation: activateNextStepMutation,
});
}; };
export const fetchPaymentMethodDetailsError = () => { export const fetchPaymentMethodDetailsError = () => {
......
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { STEPS, NEW_GROUP } from '../constants'; import { NEW_GROUP } from '../constants';
export const currentStep = (state) => state.currentStep;
export const stepIndex = () => (step) => STEPS.findIndex((el) => el === step);
export const currentStepIndex = (state, getters) => getters.stepIndex(state.currentStep);
export const selectedPlanText = (state, getters) => getters.selectedPlanDetails.text; export const selectedPlanText = (state, getters) => getters.selectedPlanDetails.text;
......
export const UPDATE_CURRENT_STEP = 'UPDATE_CURRENT_STEP';
export const UPDATE_SELECTED_PLAN = 'UPDATE_SELECTED_PLAN'; export const UPDATE_SELECTED_PLAN = 'UPDATE_SELECTED_PLAN';
export const UPDATE_SELECTED_GROUP = 'UPDATE_SELECTED_GROUP'; export const UPDATE_SELECTED_GROUP = 'UPDATE_SELECTED_GROUP';
......
import * as types from './mutation_types'; import * as types from './mutation_types';
export default { export default {
[types.UPDATE_CURRENT_STEP](state, currentStep) {
state.currentStep = currentStep;
},
[types.UPDATE_SELECTED_PLAN](state, selectedPlan) { [types.UPDATE_SELECTED_PLAN](state, selectedPlan) {
state.selectedPlan = selectedPlan; state.selectedPlan = selectedPlan;
}, },
......
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { STEPS, TAX_RATE } from '../constants'; import { TAX_RATE } from '../constants';
const parsePlanData = (planData) => const parsePlanData = (planData) =>
JSON.parse(planData).map((plan) => ({ JSON.parse(planData).map((plan) => ({
...@@ -52,7 +52,6 @@ export default ({ ...@@ -52,7 +52,6 @@ export default ({
const groups = parseGroupData(groupData); const groups = parseGroupData(groupData);
return { return {
currentStep: STEPS[0],
isSetupForCompany: parseBoolean(setupForCompany) || !isNewUser, isSetupForCompany: parseBoolean(setupForCompany) || !isNewUser,
availablePlans, availablePlans,
selectedPlan: determineSelectedPlan(planId, availablePlans), selectedPlan: determineSelectedPlan(planId, availablePlans),
......
<script> <script>
import { GlFormGroup, GlButton } from '@gitlab/ui'; import { GlFormGroup, GlButton } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex'; import activateNextStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql';
import updateStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql';
import activeStepQuery from 'ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql';
import stepListQuery from 'ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql';
import { convertToSnakeCase, dasherize } from '~/lib/utils/text_utility'; import { convertToSnakeCase, dasherize } from '~/lib/utils/text_utility';
import StepHeader from './step_header.vue'; import StepHeader from './step_header.vue';
import StepSummary from './step_summary.vue'; import StepSummary from './step_summary.vue';
...@@ -13,7 +16,7 @@ export default { ...@@ -13,7 +16,7 @@ export default {
StepSummary, StepSummary,
}, },
props: { props: {
step: { stepId: {
type: String, type: String,
required: true, required: true,
}, },
...@@ -31,30 +34,61 @@ export default { ...@@ -31,30 +34,61 @@ export default {
default: '', default: '',
}, },
}, },
data() {
return {
activeStep: {},
stepList: [],
loading: false,
};
},
apollo: {
activeStep: {
query: activeStepQuery,
},
stepList: {
query: stepListQuery,
},
},
computed: { computed: {
isActive() { isActive() {
return this.currentStep === this.step; return this.activeStep.id === this.stepId;
}, },
isFinished() { isFinished() {
return this.isValid && !this.isActive; return this.isValid && !this.isActive;
}, },
isEditable() { isEditable() {
return this.isFinished && this.stepIndex(this.step) < this.currentStepIndex; const index = this.stepList.findIndex(({ id }) => id === this.stepId);
const activeIndex = this.stepList.findIndex(({ id }) => id === this.activeStep.id);
return this.isFinished && index < activeIndex;
}, },
snakeCasedStep() { snakeCasedStep() {
return dasherize(convertToSnakeCase(this.step)); return dasherize(convertToSnakeCase(this.stepId));
}, },
...mapGetters(['currentStep', 'stepIndex', 'currentStepIndex']),
}, },
methods: { methods: {
...mapActions(['activateStep', 'activateNextStep']), async nextStep() {
nextStep() { if (!this.isValid) {
if (this.isValid) { return;
this.activateNextStep();
} }
this.loading = true;
await this.$apollo
.mutate({
mutation: activateNextStepMutation,
})
.finally(() => {
this.loading = false;
});
}, },
edit() { async edit() {
this.activateStep(this.step); this.loading = true;
await this.$apollo
.mutate({
mutation: updateStepMutation,
variables: { id: this.stepId },
})
.finally(() => {
this.loading = false;
});
}, },
}, },
}; };
......
...@@ -4,7 +4,7 @@ import { createWrapper } from '@vue/test-utils'; ...@@ -4,7 +4,7 @@ import { createWrapper } from '@vue/test-utils';
import initBuyMinutesApp from 'ee/subscriptions/buy_minutes'; import initBuyMinutesApp from 'ee/subscriptions/buy_minutes';
import * as utils from 'ee/subscriptions/buy_minutes/utils'; import * as utils from 'ee/subscriptions/buy_minutes/utils';
import StepOrderApp from 'ee/vue_shared/components/step_order_app.vue'; import StepOrderApp from 'ee/vue_shared/purchase_flow/components/step_order_app.vue';
import { mockCiMinutesPlans, mockParsedCiMinutesPlans } from './mock_data'; import { mockCiMinutesPlans, mockParsedCiMinutesPlans } from './mock_data';
jest.mock('ee/subscriptions/buy_minutes/utils'); jest.mock('ee/subscriptions/buy_minutes/utils');
......
import { mount } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import Vue, { nextTick } from 'vue'; import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Component from 'ee/subscriptions/new/components/checkout/billing_address.vue'; import BillingAddress from 'ee/subscriptions/new/components/checkout/billing_address.vue';
import Step from 'ee/subscriptions/new/components/checkout/step.vue'; import { STEPS } from 'ee/subscriptions/new/constants';
import { getStoreConfig } from 'ee/subscriptions/new/store'; import { getStoreConfig } from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types'; import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import activateNextStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
Vue.use(Vuex); const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(VueApollo);
describe('Billing Address', () => { describe('Billing Address', () => {
let store; let store;
let wrapper; let wrapper;
let mockApolloProvider;
const actionMocks = { const actionMocks = {
fetchCountries: jest.fn(), fetchCountries: jest.fn(),
fetchStates: jest.fn(), fetchStates: jest.fn(),
}; };
const createComponent = () => { function activateNextStep() {
return mockApolloProvider.clients.defaultClient.mutate({
mutation: activateNextStepMutation,
});
}
function createStore() {
const { actions, ...storeConfig } = getStoreConfig(); const { actions, ...storeConfig } = getStoreConfig();
store = new Vuex.Store({ return new Vuex.Store({
...storeConfig, ...storeConfig,
actions: { ...actions, ...actionMocks }, actions: { ...actions, ...actionMocks },
}); });
}
wrapper = mount(Component, { function createComponent(options = {}) {
store, return mount(BillingAddress, {
localVue,
...options,
}); });
}; }
beforeEach(() => { beforeEach(() => {
createComponent(); store = createStore();
mockApolloProvider = createMockApolloProvider(STEPS);
wrapper = createComponent({ store, apolloProvider: mockApolloProvider });
}); });
afterEach(() => { afterEach(() => {
...@@ -110,14 +128,15 @@ describe('Billing Address', () => { ...@@ -110,14 +128,15 @@ describe('Billing Address', () => {
}); });
describe('showing the summary', () => { describe('showing the summary', () => {
beforeEach(() => { beforeEach(async () => {
store.commit(types.UPDATE_COUNTRY, 'country'); store.commit(types.UPDATE_COUNTRY, 'country');
store.commit(types.UPDATE_STREET_ADDRESS_LINE_ONE, 'address line 1'); store.commit(types.UPDATE_STREET_ADDRESS_LINE_ONE, 'address line 1');
store.commit(types.UPDATE_STREET_ADDRESS_LINE_TWO, 'address line 2'); store.commit(types.UPDATE_STREET_ADDRESS_LINE_TWO, 'address line 2');
store.commit(types.UPDATE_COUNTRY_STATE, 'state'); store.commit(types.UPDATE_COUNTRY_STATE, 'state');
store.commit(types.UPDATE_CITY, 'city'); store.commit(types.UPDATE_CITY, 'city');
store.commit(types.UPDATE_ZIP_CODE, 'zip'); store.commit(types.UPDATE_ZIP_CODE, 'zip');
store.commit(types.UPDATE_CURRENT_STEP, 'nextStep'); await activateNextStep();
await activateNextStep();
}); });
it('should show the entered address line 1', () => { it('should show the entered address line 1', () => {
......
import { GlButton, GlLoadingIcon } from '@gitlab/ui'; import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Api from 'ee/api'; import Api from 'ee/api';
import Component from 'ee/subscriptions/new/components/checkout/confirm_order.vue'; import ConfirmOrder from 'ee/subscriptions/new/components/checkout/confirm_order.vue';
import { STEPS } from 'ee/subscriptions/new/constants';
import createStore from 'ee/subscriptions/new/store'; import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types'; import updateStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
describe('Confirm Order', () => { describe('Confirm Order', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(VueApollo);
let wrapper; let wrapper;
let mockApolloProvider;
jest.mock('ee/api.js'); jest.mock('ee/api.js');
const store = createStore(); const store = createStore();
const createComponent = (opts = {}) => { function activateStep(stepId) {
wrapper = shallowMount(Component, { return mockApolloProvider.clients.defaultClient.mutate({
mutation: updateStepMutation,
variables: { id: stepId },
});
}
function createComponent(options = {}) {
return shallowMount(ConfirmOrder, {
localVue, localVue,
store, store,
...opts, ...options,
}); });
}; }
const findConfirmButton = () => wrapper.find(GlButton); const findConfirmButton = () => wrapper.find(GlButton);
const findLoadingIcon = () => wrapper.find(GlLoadingIcon); const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
beforeEach(() => { beforeEach(() => {
createComponent(); mockApolloProvider = createMockApolloProvider(STEPS);
wrapper = createComponent({ apolloProvider: mockApolloProvider });
}); });
afterEach(() => { afterEach(() => {
...@@ -36,8 +49,8 @@ describe('Confirm Order', () => { ...@@ -36,8 +49,8 @@ describe('Confirm Order', () => {
}); });
describe('Active', () => { describe('Active', () => {
beforeEach(() => { beforeEach(async () => {
store.commit(types.UPDATE_CURRENT_STEP, 'confirmOrder'); await activateStep(STEPS[3].id);
}); });
it('button should be visible', () => { it('button should be visible', () => {
...@@ -74,8 +87,8 @@ describe('Confirm Order', () => { ...@@ -74,8 +87,8 @@ describe('Confirm Order', () => {
}); });
describe('Inactive', () => { describe('Inactive', () => {
beforeEach(() => { beforeEach(async () => {
store.commit(types.UPDATE_CURRENT_STEP, 'otherStep'); await activateStep(STEPS[1].id);
}); });
it('button should not be visible', () => { it('button should not be visible', () => {
......
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Component from 'ee/subscriptions/new/components/checkout/payment_method.vue'; import PaymentMethod from 'ee/subscriptions/new/components/checkout/payment_method.vue';
import Step from 'ee/subscriptions/new/components/checkout/step.vue'; import { STEPS } from 'ee/subscriptions/new/constants';
import createStore from 'ee/subscriptions/new/store'; import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types'; import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
describe('Payment Method', () => { describe('Payment Method', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(VueApollo);
let store; let store;
let wrapper; let wrapper;
const createComponent = (opts = {}) => { function createComponent(options = {}) {
wrapper = mount(Component, { return mount(PaymentMethod, {
localVue, localVue,
store, store,
...opts, ...options,
}); });
}; }
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore();
...@@ -31,7 +35,8 @@ describe('Payment Method', () => { ...@@ -31,7 +35,8 @@ describe('Payment Method', () => {
credit_card_expiration_year: 2009, credit_card_expiration_year: 2009,
}); });
createComponent(); const mockApollo = createMockApolloProvider(STEPS);
wrapper = createComponent({ apolloProvider: mockApollo });
}); });
afterEach(() => { afterEach(() => {
......
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Step from 'ee/subscriptions/new/components/checkout/step.vue';
import Component from 'ee/subscriptions/new/components/checkout/subscription_details.vue'; import Component from 'ee/subscriptions/new/components/checkout/subscription_details.vue';
import { NEW_GROUP } from 'ee/subscriptions/new/constants'; import { NEW_GROUP, STEPS } from 'ee/subscriptions/new/constants';
import createStore from 'ee/subscriptions/new/store'; import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types'; import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
const availablePlans = [
{ id: 'firstPlanId', code: 'bronze', price_per_year: 48, name: 'bronze' },
{ id: 'secondPlanId', code: 'silver', price_per_year: 228, name: 'silver' },
];
const groupData = [
{ id: 132, name: 'My first group', users: 3 },
{ id: 483, name: 'My second group', users: 12 },
];
const defaultInitialStoreData = {
availablePlans: JSON.stringify(availablePlans),
groupData: JSON.stringify(groupData),
planId: 'secondPlanId',
namespaceId: null,
setupForCompany: 'true',
fullName: 'Full Name',
};
describe('Subscription Details', () => { describe('Subscription Details', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
localVue.use(VueApollo);
let store;
let wrapper; let wrapper;
const availablePlans = [ function createComponent(options = {}) {
{ id: 'firstPlanId', code: 'bronze', price_per_year: 48, name: 'bronze' }, const { apolloProvider, store } = options;
{ id: 'secondPlanId', code: 'silver', price_per_year: 228, name: 'silver' }, return mount(Component, {
];
const groupData = [
{ id: 132, name: 'My first group', users: 3 },
{ id: 483, name: 'My second group', users: 12 },
];
let initialNamespaceId = null;
const initialData = (namespaceId) => {
return {
availablePlans: JSON.stringify(availablePlans),
groupData: JSON.stringify(groupData),
planId: 'secondPlanId',
namespaceId,
setupForCompany: 'true',
fullName: 'Full Name',
};
};
const createComponent = () => {
wrapper = mount(Component, {
localVue, localVue,
store, store,
apolloProvider,
stubs: {
Step,
},
}); });
}; }
const organizationNameInput = () => wrapper.find({ ref: 'organization-name' }); const organizationNameInput = () => wrapper.find({ ref: 'organization-name' });
const groupSelect = () => wrapper.find({ ref: 'group-select' }); const groupSelect = () => wrapper.find({ ref: 'group-select' });
const numberOfUsersInput = () => wrapper.find({ ref: 'number-of-users' }); const numberOfUsersInput = () => wrapper.find({ ref: 'number-of-users' });
const companyLink = () => wrapper.find({ ref: 'company-link' }); const companyLink = () => wrapper.find({ ref: 'company-link' });
beforeEach(() => {
store = createStore(initialData(initialNamespaceId));
createComponent();
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('A new user setting up for personal use', () => { describe('A new user setting up for personal use', () => {
beforeEach(() => { beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS);
const store = createStore(defaultInitialStoreData);
store.state.isNewUser = true; store.state.isNewUser = true;
store.state.isSetupForCompany = false; store.state.isSetupForCompany = false;
wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should not display an input field for the company or group name', () => { it('should not display an input field for the company or group name', () => {
...@@ -85,8 +87,11 @@ describe('Subscription Details', () => { ...@@ -85,8 +87,11 @@ describe('Subscription Details', () => {
describe('A new user setting up for a company or group', () => { describe('A new user setting up for a company or group', () => {
beforeEach(() => { beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS);
const store = createStore(defaultInitialStoreData);
store.state.isNewUser = true; store.state.isNewUser = true;
store.state.groupData = []; store.state.groupData = [];
wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should display an input field for the company or group name', () => { it('should display an input field for the company or group name', () => {
...@@ -112,8 +117,11 @@ describe('Subscription Details', () => { ...@@ -112,8 +117,11 @@ describe('Subscription Details', () => {
describe('An existing user without any groups', () => { describe('An existing user without any groups', () => {
beforeEach(() => { beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS);
const store = createStore(defaultInitialStoreData);
store.state.isNewUser = false; store.state.isNewUser = false;
store.state.groupData = []; store.state.groupData = [];
wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should display an input field for the company or group name', () => { it('should display an input field for the company or group name', () => {
...@@ -138,8 +146,13 @@ describe('Subscription Details', () => { ...@@ -138,8 +146,13 @@ describe('Subscription Details', () => {
}); });
describe('An existing user with groups', () => { describe('An existing user with groups', () => {
let store;
beforeEach(() => { beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS);
store = createStore(defaultInitialStoreData);
store.state.isNewUser = false; store.state.isNewUser = false;
wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should not display an input field for the company or group name', () => { it('should not display an input field for the company or group name', () => {
...@@ -196,9 +209,13 @@ describe('Subscription Details', () => { ...@@ -196,9 +209,13 @@ describe('Subscription Details', () => {
}); });
describe('An existing user coming from group billing page', () => { describe('An existing user coming from group billing page', () => {
let store;
beforeEach(() => { beforeEach(() => {
initialNamespaceId = '132'; const mockApollo = createMockApolloProvider(STEPS);
store = createStore({ ...defaultInitialStoreData, namespaceId: '132' });
store.state.isNewUser = false; store.state.isNewUser = false;
wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should not display an input field for the company or group name', () => { it('should not display an input field for the company or group name', () => {
...@@ -246,6 +263,13 @@ describe('Subscription Details', () => { ...@@ -246,6 +263,13 @@ describe('Subscription Details', () => {
describe('validations', () => { describe('validations', () => {
const isStepValid = () => wrapper.find(Step).props('isValid'); const isStepValid = () => wrapper.find(Step).props('isValid');
let store;
beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS);
store = createStore(defaultInitialStoreData);
wrapper = createComponent({ apolloProvider: mockApollo, store });
});
describe('when setting up for a company', () => { describe('when setting up for a company', () => {
beforeEach(() => { beforeEach(() => {
...@@ -331,12 +355,16 @@ describe('Subscription Details', () => { ...@@ -331,12 +355,16 @@ describe('Subscription Details', () => {
}); });
describe('Showing summary', () => { describe('Showing summary', () => {
let store;
beforeEach(() => { beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS, 1);
store = createStore(defaultInitialStoreData);
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, true); store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, true);
store.commit(types.UPDATE_SELECTED_PLAN, 'firstPlanId'); store.commit(types.UPDATE_SELECTED_PLAN, 'firstPlanId');
store.commit(types.UPDATE_ORGANIZATION_NAME, 'My Organization'); store.commit(types.UPDATE_ORGANIZATION_NAME, 'My Organization');
store.commit(types.UPDATE_NUMBER_OF_USERS, 25); store.commit(types.UPDATE_NUMBER_OF_USERS, 25);
store.commit(types.UPDATE_CURRENT_STEP, 'nextStep'); wrapper = createComponent({ apolloProvider: mockApollo, store });
}); });
it('should show the selected plan', () => { it('should show the selected plan', () => {
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Api from 'ee/api'; import Api from 'ee/api';
import * as constants from 'ee/subscriptions/new/constants'; import * as constants from 'ee/subscriptions/new/constants';
import defaultClient from 'ee/subscriptions/new/graphql';
import * as actions from 'ee/subscriptions/new/store/actions'; import * as actions from 'ee/subscriptions/new/store/actions';
import activateNextStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import createFlash from '~/flash'; import createFlash from '~/flash';
...@@ -16,53 +18,18 @@ const { ...@@ -16,53 +18,18 @@ const {
} = Api; } = Api;
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('ee/subscriptions/new/constants', () => ({
STEPS: ['firstStep', 'secondStep'],
}));
describe('Subscriptions Actions', () => { describe('Subscriptions Actions', () => {
let mock; let mock;
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
defaultClient.mutate = jest.fn();
}); });
afterEach(() => { afterEach(() => {
mock.restore(); mock.restore();
}); defaultClient.mutate.mockClear();
describe('activateStep', () => {
it('set the currentStep to the provided value', (done) => {
testAction(
actions.activateStep,
'secondStep',
{},
[{ type: 'UPDATE_CURRENT_STEP', payload: 'secondStep' }],
[],
done,
);
});
it('does not change the currentStep if provided value is not available', (done) => {
testAction(actions.activateStep, 'thirdStep', {}, [], [], done);
});
});
describe('activateNextStep', () => {
it('set the currentStep to the next step in the available steps', (done) => {
testAction(
actions.activateNextStep,
{},
{ currentStepIndex: 0 },
[{ type: 'UPDATE_CURRENT_STEP', payload: 'secondStep' }],
[],
done,
);
});
it('does not change the currentStep if the current step is the last step', (done) => {
testAction(actions.activateNextStep, {}, { currentStepIndex: 1 }, [], [], done);
});
}); });
describe('updateSelectedPlan', () => { describe('updateSelectedPlan', () => {
...@@ -553,7 +520,7 @@ describe('Subscriptions Actions', () => { ...@@ -553,7 +520,7 @@ describe('Subscriptions Actions', () => {
}); });
describe('fetchPaymentMethodDetailsSuccess', () => { describe('fetchPaymentMethodDetailsSuccess', () => {
it('updates creditCardDetails to the provided data and calls activateNextStep', (done) => { it('updates creditCardDetails to the provided data and calls defaultClient with activateNextStepMutation', (done) => {
testAction( testAction(
actions.fetchPaymentMethodDetailsSuccess, actions.fetchPaymentMethodDetailsSuccess,
{ {
...@@ -574,8 +541,13 @@ describe('Subscriptions Actions', () => { ...@@ -574,8 +541,13 @@ describe('Subscriptions Actions', () => {
}, },
}, },
], ],
[{ type: 'activateNextStep' }], [],
done, () => {
expect(defaultClient.mutate).toHaveBeenCalledWith({
mutation: activateNextStepMutation,
});
done();
},
); );
}); });
}); });
......
import * as constants from 'ee/subscriptions/new/constants'; import * as constants from 'ee/subscriptions/new/constants';
import * as getters from 'ee/subscriptions/new/store/getters'; import * as getters from 'ee/subscriptions/new/store/getters';
constants.STEPS = ['firstStep', 'secondStep'];
const state = { const state = {
currentStep: 'secondStep',
isSetupForCompany: true, isSetupForCompany: true,
isNewUser: true, isNewUser: true,
availablePlans: [ availablePlans: [
...@@ -26,35 +23,6 @@ const state = { ...@@ -26,35 +23,6 @@ const state = {
}; };
describe('Subscriptions Getters', () => { describe('Subscriptions Getters', () => {
describe('currentStep', () => {
it('returns the states currentStep', () => {
expect(getters.currentStep(state)).toBe('secondStep');
});
});
describe('stepIndex', () => {
it('returns a function', () => {
expect(getters.stepIndex()).toBeInstanceOf(Function);
});
it('returns a function that returns the index of the given step', () => {
expect(getters.stepIndex()('secondStep')).toBe(1);
});
});
describe('currentStepIndex', () => {
it('returns a function', () => {
expect(getters.currentStepIndex(state, getters)).toBeInstanceOf(Function);
});
it('calls the stepIndex function with the current step name', () => {
const stepIndexSpy = jest.spyOn(getters, 'stepIndex');
getters.currentStepIndex(state, getters);
expect(stepIndexSpy).toHaveBeenCalledWith('secondStep');
});
});
describe('selectedPlanText', () => { describe('selectedPlanText', () => {
it('returns the text for selectedPlan', () => { it('returns the text for selectedPlan', () => {
expect( expect(
......
...@@ -2,7 +2,6 @@ import * as types from 'ee/subscriptions/new/store/mutation_types'; ...@@ -2,7 +2,6 @@ import * as types from 'ee/subscriptions/new/store/mutation_types';
import mutations from 'ee/subscriptions/new/store/mutations'; import mutations from 'ee/subscriptions/new/store/mutations';
const state = () => ({ const state = () => ({
currentStep: 'firstStep',
selectedPlan: 'firstPlan', selectedPlan: 'firstPlan',
isSetupForCompany: true, isSetupForCompany: true,
numberOfUsers: 1, numberOfUsers: 1,
...@@ -22,7 +21,6 @@ beforeEach(() => { ...@@ -22,7 +21,6 @@ beforeEach(() => {
describe('ee/subscriptions/new/store/mutation', () => { describe('ee/subscriptions/new/store/mutation', () => {
describe.each` describe.each`
mutation | value | stateProp mutation | value | stateProp
${types.UPDATE_CURRENT_STEP} | ${'secondStep'} | ${'currentStep'}
${types.UPDATE_SELECTED_PLAN} | ${'secondPlan'} | ${'selectedPlan'} ${types.UPDATE_SELECTED_PLAN} | ${'secondPlan'} | ${'selectedPlan'}
${types.UPDATE_SELECTED_GROUP} | ${'selectedGroup'} | ${'selectedGroup'} ${types.UPDATE_SELECTED_GROUP} | ${'selectedGroup'} | ${'selectedGroup'}
${types.UPDATE_IS_SETUP_FOR_COMPANY} | ${false} | ${'isSetupForCompany'} ${types.UPDATE_IS_SETUP_FOR_COMPANY} | ${false} | ${'isSetupForCompany'}
......
import * as constants from 'ee/subscriptions/new/constants'; import * as constants from 'ee/subscriptions/new/constants';
import createState from 'ee/subscriptions/new/store/state'; import createState from 'ee/subscriptions/new/store/state';
constants.STEPS = ['firstStep', 'secondStep'];
constants.TAX_RATE = 0; constants.TAX_RATE = 0;
describe('projectsSelector default state', () => { describe('projectsSelector default state', () => {
...@@ -31,10 +30,6 @@ describe('projectsSelector default state', () => { ...@@ -31,10 +30,6 @@ describe('projectsSelector default state', () => {
const state = createState(initialData); const state = createState(initialData);
it('sets the currentStep to the first item of the STEPS constant', () => {
expect(state.currentStep).toEqual('firstStep');
});
describe('availablePlans', () => { describe('availablePlans', () => {
it('sets the availablePlans to the provided parsed availablePlans', () => { it('sets the availablePlans to the provided parsed availablePlans', () => {
expect(state.availablePlans).toEqual([ expect(state.availablePlans).toEqual([
......
import { GlButton } from '@gitlab/ui'; import { GlButton } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import VueApollo from 'vue-apollo';
import Component from 'ee/subscriptions/new/components/checkout/step.vue'; import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import StepSummary from 'ee/subscriptions/new/components/checkout/step_summary.vue'; import StepSummary from 'ee/vue_shared/purchase_flow/components/step_summary.vue';
import * as constants from 'ee/subscriptions/new/constants'; import updateStepMutation from 'ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql';
import createStore from 'ee/subscriptions/new/store'; import { STEPS } from '../mock_data';
import { createMockApolloProvider } from '../spec_helper';
describe('Step', () => { const localVue = createLocalVue();
const localVue = createLocalVue(); localVue.use(VueApollo);
localVue.use(Vuex);
let store; describe('Step', () => {
let wrapper; let wrapper;
const initialProps = { const initialProps = {
step: 'secondStep', stepId: STEPS[1].id,
isValid: true, isValid: true,
title: 'title', title: 'title',
nextStepButtonText: 'next', nextStepButtonText: 'next',
}; };
const createComponent = (propsData) => { function activateFirstStep(apolloProvider) {
wrapper = shallowMount(Component, { return apolloProvider.clients.defaultClient.mutate({
propsData: { ...initialProps, ...propsData }, mutation: updateStepMutation,
variables: { id: STEPS[0].id },
});
}
function createComponent(options = {}) {
const { apolloProvider, propsData } = options;
return shallowMount(Step, {
localVue, localVue,
store, propsData: { ...initialProps, ...propsData },
apolloProvider,
}); });
}; }
const activatePreviousStep = () => {
store.dispatch('activateStep', 'firstStep');
};
constants.STEPS = ['firstStep', 'secondStep'];
beforeEach(() => {
store = createStore();
store.dispatch('activateStep', 'secondStep');
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -45,42 +41,47 @@ describe('Step', () => { ...@@ -45,42 +41,47 @@ describe('Step', () => {
describe('Step Body', () => { describe('Step Body', () => {
it('should display the step body when this step is the current step', () => { it('should display the step body when this step is the current step', () => {
createComponent(); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find('.card > div').attributes('style')).toBeUndefined(); expect(wrapper.find('.card > div').attributes('style')).toBeUndefined();
}); });
it('should not display the step body when this step is not the current step', () => { it('should not display the step body when this step is not the current step', async () => {
activatePreviousStep(); const mockApollo = createMockApolloProvider(STEPS, 1);
createComponent(); await activateFirstStep(mockApollo);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find('.card > div').attributes('style')).toBe('display: none;'); expect(wrapper.find('.card > div').attributes('style')).toBe('display: none;');
}); });
}); });
describe('Step Summary', () => { describe('Step Summary', () => {
it('should be shown when this step is valid and not active', () => { it('should be shown when this step is valid and not active', async () => {
activatePreviousStep(); const mockApollo = createMockApolloProvider(STEPS, 1);
createComponent(); await activateFirstStep(mockApollo);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(true); expect(wrapper.find(StepSummary).exists()).toBe(true);
}); });
it('should not be shown when this step is not valid and not active', () => { it('should not be shown when this step is not valid and not active', async () => {
activatePreviousStep(); const mockApollo = createMockApolloProvider(STEPS, 1);
createComponent({ isValid: false }); await activateFirstStep(mockApollo);
wrapper = createComponent({ propsData: { isValid: false }, apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(false); expect(wrapper.find(StepSummary).exists()).toBe(false);
}); });
it('should not be shown when this step is valid and active', () => { it('should not be shown when this step is valid and active', () => {
createComponent(); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(false); expect(wrapper.find(StepSummary).exists()).toBe(false);
}); });
it('should not be shown when this step is not valid and active', () => { it('should not be shown when this step is not valid and active', () => {
createComponent({ isValid: false }); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ propsData: { isValid: false }, apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(false); expect(wrapper.find(StepSummary).exists()).toBe(false);
}); });
...@@ -88,22 +89,25 @@ describe('Step', () => { ...@@ -88,22 +89,25 @@ describe('Step', () => {
describe('isEditable', () => { describe('isEditable', () => {
it('should set the isEditable property to true when this step is finished and comes before the current step', () => { it('should set the isEditable property to true when this step is finished and comes before the current step', () => {
createComponent({ step: 'firstStep' }); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ propsData: { stepId: STEPS[0].id }, apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).props('isEditable')).toBe(true); expect(wrapper.find(StepSummary).props('isEditable')).toBe(true);
}); });
}); });
describe('Showing the summary', () => { describe('Showing the summary', () => {
it('shows the summary when this step is finished', () => { it('shows the summary when this step is finished', async () => {
activatePreviousStep(); const mockApollo = createMockApolloProvider(STEPS, 1);
createComponent(); await activateFirstStep(mockApollo);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(true); expect(wrapper.find(StepSummary).exists()).toBe(true);
}); });
it('does not show the summary when this step is not finished', () => { it('does not show the summary when this step is not finished', () => {
createComponent(); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find(StepSummary).exists()).toBe(false); expect(wrapper.find(StepSummary).exists()).toBe(false);
}); });
...@@ -111,25 +115,32 @@ describe('Step', () => { ...@@ -111,25 +115,32 @@ describe('Step', () => {
describe('Next button', () => { describe('Next button', () => {
it('shows the next button when the text was passed', () => { it('shows the next button when the text was passed', () => {
createComponent(); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.text()).toBe('next'); expect(wrapper.text()).toBe('next');
}); });
it('does not show the next button when no text was passed', () => { it('does not show the next button when no text was passed', () => {
createComponent({ nextStepButtonText: '' }); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({
propsData: { nextStepButtonText: '' },
apolloProvider: mockApollo,
});
expect(wrapper.text()).toBe(''); expect(wrapper.text()).toBe('');
}); });
it('is disabled when this step is not valid', () => { it('is disabled when this step is not valid', () => {
createComponent({ isValid: false }); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ propsData: { isValid: false }, apolloProvider: mockApollo });
expect(wrapper.find(GlButton).attributes('disabled')).toBe('true'); expect(wrapper.find(GlButton).attributes('disabled')).toBe('true');
}); });
it('is enabled when this step is valid', () => { it('is enabled when this step is valid', () => {
createComponent(); const mockApollo = createMockApolloProvider(STEPS, 1);
wrapper = createComponent({ apolloProvider: mockApollo });
expect(wrapper.find(GlButton).attributes('disabled')).toBeUndefined(); expect(wrapper.find(GlButton).attributes('disabled')).toBeUndefined();
}); });
......
import activeStepQuery from 'ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql';
import stepListQuery from 'ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql';
import resolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers';
import createMockApollo from 'helpers/mock_apollo_helper';
export function createMockApolloProvider(stepList, initialStepIndex = 0) {
const mockApollo = createMockApollo([], resolvers);
mockApollo.clients.defaultClient.cache.writeQuery({
query: stepListQuery,
data: { stepList },
});
mockApollo.clients.defaultClient.cache.writeQuery({
query: activeStepQuery,
data: { activeStep: stepList[initialStepIndex] },
});
return mockApollo;
}
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