Commit 87c15fb7 authored by Michael Lunøe's avatar Michael Lunøe Committed by Olena Horal-Koretska

Clean up initial data parsing in /buy_minutes route

parent c765eb69
......@@ -21,7 +21,7 @@ export default {
emptySvg,
data() {
return {
plans: [],
plans: null,
hasError: false,
};
},
......@@ -33,6 +33,11 @@ export default {
tags: [planTags.CI_1000_MINUTES_PLAN],
},
update(data) {
if (!data?.plans?.length) {
this.hasError = true;
return null;
}
return data.plans;
},
error(error) {
......@@ -50,7 +55,7 @@ export default {
:description="$options.i18n.ERROR_FETCHING_DATA_DESCRIPTION"
:svg-path="`data:image/svg+xml;utf8,${encodeURIComponent($options.emptySvg)}`"
/>
<step-order-app v-else>
<step-order-app v-else-if="!$apollo.loading">
<template #checkout>
<checkout :plans="plans" />
</template>
......
......@@ -13,16 +13,16 @@ export default {
required: true,
},
},
data() {
return {
isNewUser: null,
};
},
apollo: {
state: {
isNewUser: {
query: STATE_QUERY,
},
},
computed: {
isNewUser() {
return this.state.isNewUser;
},
},
currentStep: STEPS.checkout,
steps: SUBSCRIPTON_FLOW_STEPS,
i18n: {
......@@ -31,7 +31,10 @@ export default {
};
</script>
<template>
<div class="checkout gl-flex gl-flex-column gl-justify-content-between w-100">
<div
v-if="!$apollo.loading"
class="checkout gl-flex gl-flex-column gl-justify-content-between w-100"
>
<div class="full-width">
<progress-bar v-if="isNewUser" :steps="$options.steps" :current-step="$options.currentStep" />
<div class="flash-container"></div>
......
<script>
import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { STEPS } from 'ee/subscriptions/constants';
import UPDATE_STATE from 'ee/subscriptions/graphql/mutations/update_state.mutation.graphql';
import STATE_QUERY from 'ee/subscriptions/graphql/queries/state.query.graphql';
import { NEW_GROUP, STEPS } from 'ee/subscriptions/new/constants';
import { NEW_GROUP } from 'ee/subscriptions/new/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { sprintf, s__, __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
......@@ -26,21 +27,49 @@ export default {
required: true,
},
},
data() {
return {
subscription: {},
namespaces: [],
customer: {},
isSetupForCompany: null,
isNewUser: null,
};
},
apollo: {
state: {
query: STATE_QUERY,
update(data) {
const {
subscription = {},
namespaces = [],
customer = {},
isSetupForCompany = null,
isNewUser = null,
} = data;
return {
subscription,
namespaces,
customer,
isSetupForCompany,
isNewUser,
};
},
result({ data }) {
const { subscription, namespaces, customer, isSetupForCompany, isNewUser } = data || {};
this.subscription = subscription;
this.namespaces = namespaces;
this.customer = customer;
this.isSetupForCompany = isSetupForCompany;
this.isNewUser = isNewUser;
},
},
},
computed: {
subscription() {
return this.state.subscription;
},
namespaces() {
return this.state.namespaces;
},
selectedPlanModel: {
get() {
return this.subscription.planId;
return this.subscription.planId || this.plans[0].code;
},
set(planId) {
this.updateSubscription({ subscription: { planId } });
......@@ -67,7 +96,7 @@ export default {
},
companyModel: {
get() {
return this.state.customer.company;
return this.customer.company;
},
set(company) {
this.updateSubscription({ customer: { company } });
......@@ -99,10 +128,10 @@ export default {
);
},
isValid() {
if (this.state.isSetupForCompany) {
if (this.isSetupForCompany) {
return (
!isEmpty(this.subscription.planId) &&
(!isEmpty(this.state.customer.company) || this.isNewGroupSelected) &&
(!isEmpty(this.customer.company) || this.isNewGroupSelected) &&
this.isNumberOfUsersValid
);
}
......@@ -110,13 +139,13 @@ export default {
return !isEmpty(this.subscription.planId) && this.subscription.quantity === 1;
},
isShowingGroupSelector() {
return !this.state.isNewUser && this.namespaces.length;
return !this.isNewUser && this.namespaces.length;
},
isNewGroupSelected() {
return this.subscription.namespaceId === NEW_GROUP;
},
isShowingNameOfCompanyInput() {
return this.state.isSetupForCompany && (!this.namespaces.length || this.isNewGroupSelected);
return this.isSetupForCompany && (!this.namespaces.length || this.isNewGroupSelected);
},
groupOptionsWithDefault() {
return [
......@@ -147,7 +176,7 @@ export default {
});
},
toggleIsSetupForCompany() {
this.updateSubscription({ isSetupForCompany: !this.state.isSetupForCompany });
this.updateSubscription({ isSetupForCompany: !this.isSetupForCompany });
},
},
i18n: {
......@@ -172,6 +201,7 @@ export default {
</script>
<template>
<step
v-if="!$apollo.loading"
:step-id="$options.stepId"
:title="$options.i18n.stepTitle"
:is-valid="isValid"
......@@ -219,12 +249,12 @@ export default {
v-model.number="numberOfUsersModel"
type="number"
:min="selectedGroupUsers"
:disabled="!state.isSetupForCompany"
:disabled="!isSetupForCompany"
data-qa-selector="number_of_users"
/>
</gl-form-group>
<gl-form-group
v-if="!state.isSetupForCompany"
v-if="!isSetupForCompany"
ref="company-link"
class="label ml-3 align-self-end"
>
......@@ -240,7 +270,7 @@ export default {
<strong ref="summary-line-1">
{{ selectedPlanTextLine }}
</strong>
<div v-if="state.isSetupForCompany" ref="summary-line-2">
<div v-if="isSetupForCompany" ref="summary-line-2">
{{ $options.i18n.group }}: {{ customer.company || selectedGroupName }}
</div>
<div ref="summary-line-3">{{ $options.i18n.users }}: {{ subscription.quantity }}</div>
......
import Vue from 'vue';
import App from 'ee/subscriptions/buy_minutes/components/app.vue';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import { STEPS } from 'ee/subscriptions/new/constants';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import ensureData from '~/ensure_data';
import App from './components/app.vue';
import apolloProvider from './graphql';
const arrayToGraphqlArray = (arr, typename) =>
Array.from(arr, (item) =>
Object.assign(convertObjectPropsToCamelCase(item, { deep: true }), { __typename: typename }),
);
const writeInitialDataToApolloProvider = (dataset) => {
const { groupData, newUser, setupForCompany, fullName, planId } = dataset;
// eslint-disable-next-line @gitlab/require-i18n-strings
const namespaces = arrayToGraphqlArray(JSON.parse(groupData), 'Namespace');
const isNewUser = parseBoolean(newUser);
const isSetupForCompany = parseBoolean(setupForCompany) || !isNewUser;
apolloProvider.clients.defaultClient.cache.writeQuery({
query: stateQuery,
data: {
state: {
isNewUser,
isSetupForCompany,
namespaces,
fullName,
subscription: {
planId,
paymentMethodId: null,
quantity: 1,
namespaceId: null,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Subscription',
},
customer: {
country: null,
address1: null,
address2: null,
city: null,
state: null,
zipCode: null,
company: null,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Customer',
},
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'State',
},
activeStep: STEPS[0],
stepList: STEPS,
},
});
};
import { writeInitialDataToApolloCache } from './utils';
export default (el) => {
if (!el) {
return null;
}
writeInitialDataToApolloProvider(el.dataset);
const extendedApp = ensureData(App, {
parseData: writeInitialDataToApolloCache.bind(null, apolloProvider),
data: el.dataset,
shouldLog: true,
});
return new Vue({
el,
apolloProvider,
render(createElement) {
return createElement(App);
return createElement(extendedApp);
},
});
};
import { STEPS } from 'ee/subscriptions/constants';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
function arrayToGraphqlArray(arr, typename) {
return Array.from(arr, (item) => {
return Object.assign(convertObjectPropsToCamelCase(item, { deep: true }), {
__typename: typename,
});
});
}
export function writeInitialDataToApolloCache(apolloProvider, dataset) {
const { groupData, newUser, setupForCompany, fullName, planId = null } = dataset;
// eslint-disable-next-line @gitlab/require-i18n-strings
const namespaces = arrayToGraphqlArray(JSON.parse(groupData), 'Namespace');
const isNewUser = parseBoolean(newUser);
const isSetupForCompany = parseBoolean(setupForCompany) || !isNewUser;
apolloProvider.clients.defaultClient.cache.writeQuery({
query: stateQuery,
data: {
isNewUser,
isSetupForCompany,
namespaces,
fullName,
subscription: {
planId,
paymentMethodId: null,
quantity: 1,
namespaceId: null,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Subscription',
},
customer: {
country: null,
address1: null,
address2: null,
city: null,
state: null,
zipCode: null,
company: null,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename: 'Customer',
},
activeStep: STEPS[0],
stepList: STEPS,
},
});
}
......@@ -2,3 +2,13 @@ import { s__ } from '~/locale';
export const ERROR_FETCHING_COUNTRIES = s__('Checkout|Failed to load countries. Please try again.');
export const ERROR_FETCHING_STATES = s__('Checkout|Failed to load states. Please try again.');
// The order of the steps in this array determines the flow of the application
/* 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 */
......@@ -3,13 +3,6 @@ query getPlans($tags: [PlanTag!]) {
id
name
code
active
deprecated
free
pricePerMonth
pricePerYear
features
aboutPageHref
hideDeprecatedCard
}
}
query state {
state @client {
namespaces {
id
name
users
}
isNewUser
fullName
isSetupForCompany
customer {
country
address1
address2
city
state
zipCode
company
}
subscription {
planId
paymentMethodId
quantity
namespaceId
}
namespaces @client {
id
name
users
}
isNewUser @client
fullName @client
isSetupForCompany @client
customer @client {
country
address1
address2
city
state
zipCode
company
}
subscription @client {
planId
paymentMethodId
quantity
namespaceId
}
activeStep @client {
id
......
......@@ -2,10 +2,10 @@
import { GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { mapState, mapActions } from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { s__ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { STEPS } from '../../constants';
export default {
components: {
......
<script>
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants';
import activeStepQuery from 'ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import { STEPS } from '../../constants';
export default {
components: {
......
<script>
import { GlSprintf } from '@gitlab/ui';
import { mapState } from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { sprintf, s__ } from '~/locale';
import { STEPS } from '../../constants';
import Zuora from './zuora.vue';
export default {
......
......@@ -2,7 +2,8 @@
import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { mapState, mapGetters, mapActions } from 'vuex';
import { NEW_GROUP, STEPS } from 'ee/subscriptions/new/constants';
import { STEPS } from 'ee/subscriptions/constants';
import { NEW_GROUP } from 'ee/subscriptions/new/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { sprintf, s__ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
......
// The order of the steps in this array determines the flow of the application
/* 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 PAYMENT_FORM_ID = 'paid_signup_flow';
......
......@@ -3,7 +3,7 @@ import stepListQuery from 'ee/vue_shared/purchase_flow/graphql/queries/step_list
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';
import { STEPS } from './constants';
import { STEPS } from '../constants';
function createClient(stepList) {
const client = createDefaultClient(resolvers, {
......
......@@ -37,6 +37,41 @@ describe('App', () => {
});
describe('when data is not received', () => {
it('should display the GlEmptyState for empty data', async () => {
const mockApollo = createMockApolloProvider({
plansQueryMock: jest.fn().mockResolvedValue({ data: null }),
});
wrapper = createComponent({ apolloProvider: mockApollo });
await waitForPromises();
expect(wrapper.findComponent(StepOrderApp).exists()).toBe(false);
expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
it('should display the GlEmptyState for empty plans', async () => {
const mockApollo = createMockApolloProvider({
plansQueryMock: jest.fn().mockResolvedValue({ data: { plans: null } }),
});
wrapper = createComponent({ apolloProvider: mockApollo });
await waitForPromises();
expect(wrapper.findComponent(StepOrderApp).exists()).toBe(false);
expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
it('should display the GlEmptyState for plans data of wrong type', async () => {
const mockApollo = createMockApolloProvider({
plansQueryMock: jest.fn().mockResolvedValue({ data: { plans: {} } }),
});
wrapper = createComponent({ apolloProvider: mockApollo });
await waitForPromises();
expect(wrapper.findComponent(StepOrderApp).exists()).toBe(false);
expect(wrapper.findComponent(GlEmptyState).exists()).toBe(true);
});
});
describe('when an error is received', () => {
it('should display the GlEmptyState', async () => {
const mockApollo = createMockApolloProvider({
plansQueryMock: jest.fn().mockRejectedValue(new Error('An error happened!')),
......
......@@ -10,7 +10,7 @@ import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import purchaseFlowResolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers';
import {
stateData as initialStateData,
namespaces as defaultNamespaces,
mockParsedNamespaces,
mockCiMinutesPlans,
} from 'ee_jest/subscriptions/buy_minutes/mock_data';
import createMockApollo from 'helpers/mock_apollo_helper';
......@@ -61,7 +61,7 @@ describe('Subscription Details', () => {
describe('A new user setting up for personal use', () => {
beforeEach(() => {
wrapper = createComponent({ state: { isNewUser: true, isSetupForCompany: false } });
wrapper = createComponent({ isNewUser: true, isSetupForCompany: false });
});
it('should not display an input field for the company or group name', () => {
......@@ -87,9 +87,7 @@ describe('Subscription Details', () => {
describe('A new user setting up for a company or group', () => {
beforeEach(() => {
wrapper = createComponent({
state: { isNewUser: true, isSetupForCompany: true, namespaces: [] },
});
wrapper = createComponent({ isNewUser: true, isSetupForCompany: true, namespaces: [] });
});
it('should display an input field for the company or group name', () => {
......@@ -115,9 +113,7 @@ describe('Subscription Details', () => {
describe('An existing user without any groups', () => {
beforeEach(() => {
wrapper = createComponent({
state: { isNewUser: false, namespaces: [] },
});
wrapper = createComponent({ isNewUser: false, namespaces: [] });
});
it('should display an input field for the company or group name', () => {
......@@ -143,7 +139,7 @@ describe('Subscription Details', () => {
describe('An existing user with groups', () => {
beforeEach(() => {
wrapper = createComponent({ state: { isNewUser: false, namespaces: defaultNamespaces } });
wrapper = createComponent({ isNewUser: false, namespaces: mockParsedNamespaces });
});
it('should not display an input field for the company or group name', () => {
......@@ -170,7 +166,8 @@ describe('Subscription Details', () => {
describe('selecting an existing group', () => {
beforeEach(() => {
wrapper = createComponent({
state: { subscription: { namespaceId: 483 }, namespaces: defaultNamespaces },
subscription: { namespaceId: 483 },
namespaces: mockParsedNamespaces,
});
});
......@@ -186,7 +183,8 @@ describe('Subscription Details', () => {
describe('selecting "Create a new group', () => {
beforeEach(() => {
wrapper = createComponent({
state: { subscription: { namespaceId: NEW_GROUP }, namespaces: defaultNamespaces },
subscription: { namespaceId: NEW_GROUP },
namespaces: mockParsedNamespaces,
});
});
......@@ -206,12 +204,10 @@ describe('Subscription Details', () => {
describe('An existing user coming from group billing page', () => {
beforeEach(() => {
wrapper = createComponent({
state: {
isNewUser: false,
isSetupForCompany: true,
subscription: { namespaceId: 132 },
namespaces: defaultNamespaces,
},
isNewUser: false,
isSetupForCompany: true,
subscription: { namespaceId: 132 },
namespaces: mockParsedNamespaces,
});
});
......@@ -242,7 +238,8 @@ describe('Subscription Details', () => {
describe('selecting an existing group', () => {
beforeEach(() => {
wrapper = createComponent({
state: { subscription: { namespaceId: 483 }, namespaces: defaultNamespaces },
subscription: { namespaceId: 483 },
namespaces: mockParsedNamespaces,
});
});
......@@ -266,10 +263,8 @@ describe('Subscription Details', () => {
describe('when setting up for a company', () => {
it('should be valid', () => {
wrapper = createComponent({
state: {
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 14 },
customer: { company: 'Organization name' },
},
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 14 },
customer: { company: 'Organization name' },
});
expect(isStepValid()).toBe(true);
......@@ -277,11 +272,9 @@ describe('Subscription Details', () => {
it('should be invalid when no plan is selected', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: true,
subscription: { planId: null, namespaceId: 483, quantity: 14 },
customer: { company: 'Organization name' },
},
isSetupForCompany: true,
subscription: { planId: null, namespaceId: 483, quantity: 14 },
customer: { company: 'Organization name' },
});
await nextTick();
......@@ -291,11 +284,9 @@ describe('Subscription Details', () => {
it('should be invalid when no organization name is given, and no group is selected', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: true,
subscription: { namespaceId: null },
customer: { company: null },
},
isSetupForCompany: true,
subscription: { namespaceId: null },
customer: { company: null },
});
await nextTick();
......@@ -305,10 +296,8 @@ describe('Subscription Details', () => {
it('should be invalid when number of users is 0', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: true,
subscription: { quantity: 0 },
},
isSetupForCompany: true,
subscription: { quantity: 0 },
});
await nextTick();
......@@ -318,10 +307,8 @@ describe('Subscription Details', () => {
it('should be invalid when number of users is smaller than the selected group users', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: true,
subscription: { namespaceId: 483, quantity: 10 },
},
isSetupForCompany: true,
subscription: { namespaceId: 483, quantity: 10 },
});
await nextTick();
......@@ -333,11 +320,9 @@ describe('Subscription Details', () => {
describe('when not setting up for a company', () => {
beforeEach(() => {
wrapper = createComponent({
state: {
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 1 },
customer: { company: 'Organization name' },
},
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 1 },
customer: { company: 'Organization name' },
});
});
......@@ -347,11 +332,9 @@ describe('Subscription Details', () => {
it('should be invalid when no plan is selected', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: false,
subscription: { planId: null, namespaceId: 483, quantity: 1 },
customer: { company: 'Organization name' },
},
isSetupForCompany: false,
subscription: { planId: null, namespaceId: 483, quantity: 1 },
customer: { company: 'Organization name' },
});
await nextTick();
......@@ -361,11 +344,9 @@ describe('Subscription Details', () => {
it('should be invalid when no number of users is 0', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 0 },
customer: { company: 'Organization name' },
},
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 0 },
customer: { company: 'Organization name' },
});
await nextTick();
......@@ -375,11 +356,9 @@ describe('Subscription Details', () => {
it('should be invalid when no number of users is greater than 1', async () => {
wrapper = createComponent({
state: {
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 2 },
customer: { company: 'Organization name' },
},
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 2 },
customer: { company: 'Organization name' },
});
await nextTick();
......
......@@ -11,12 +11,13 @@ import {
mockCiMinutesPlans,
} from 'ee_jest/subscriptions/buy_minutes/mock_data';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
const localVue = createLocalVue();
localVue.use(VueApollo);
describe('Checkout', () => {
const resolvers = { ...purchaseFlowResolvers, ...subscriptionsResolvers };
const resolvers = merge({}, purchaseFlowResolvers, subscriptionsResolvers);
let wrapper;
const createMockApolloProvider = (stateData = {}) => {
......@@ -54,8 +55,8 @@ describe('Checkout', () => {
[true, true],
[false, false],
])('when isNewUser=%s', (isNewUser, visible) => {
beforeEach(() => {
createComponent({ state: { isNewUser } });
beforeEach(async () => {
createComponent({ isNewUser });
});
it(`progress bar visibility is ${visible}`, () => {
......@@ -64,8 +65,9 @@ describe('Checkout', () => {
});
describe('passing the correct options to the progress bar component', () => {
beforeEach(() => {
createComponent({ state: { isNewUser: true } });
beforeEach(async () => {
createComponent({ isNewUser: true });
await waitForPromises();
});
it('passes the steps', () => {
......
import { createWrapper } from '@vue/test-utils';
import initBuyMinutesApp from 'ee/subscriptions/buy_minutes';
import StepOrderApp from 'ee/vue_shared/purchase_flow/components/step_order_app.vue';
import { mockCiMinutesPlans } from './mock_data';
import { createMockApolloProvider } from './spec_helper';
jest.doMock('ee/subscriptions/buy_minutes/graphql', createMockApolloProvider());
describe('initBuyMinutesApp', () => {
let vm;
let wrapper;
function createComponent() {
const el = document.createElement('div');
Object.assign(el.dataset, {
planId: mockCiMinutesPlans[0].code,
groupData: '[]',
fullName: 'GitLab',
});
vm = initBuyMinutesApp(el).$mount();
wrapper = createWrapper(vm);
}
afterEach(() => {
if (vm) {
vm.$destroy();
}
wrapper.destroy();
vm = null;
});
it('displays the StepOrderApp', () => {
createComponent();
expect(wrapper.find(StepOrderApp).exists()).toBe(true);
});
});
import { STEPS } from 'ee/subscriptions/new/constants';
import { STEPS } from 'ee/subscriptions/constants';
export const mockCiMinutesPlans = [
{
id: 'ci_minutes',
deprecated: false,
name: '1000 CI minutes pack',
code: 'ci_minutes',
active: true,
free: null,
pricePerMonth: 0.8333333333333334,
pricePerYear: 10.0,
features: null,
aboutPageHref: null,
hideDeprecatedCard: false,
},
{ id: 'firstPlanId', code: 'bronze', pricePerYear: 48, name: 'bronze', __typename: 'Plan' },
{ id: 'secondPlanId', code: 'silver', pricePerYear: 228, name: 'silver', __typename: 'Plan' },
];
export const mockNamespaces =
'[{"id":132,"name":"Gitlab Org","users":3},{"id":483,"name":"Gnuwget","users":12}]';
export const namespaces = [
{ id: 132, name: 'My first group', users: 3, __typename: 'Namespace' },
{ id: 483, name: 'My second group', users: 12, __typename: 'Namespace' },
export const mockParsedNamespaces = [
{ __typename: 'Namespace', id: 132, name: 'Gitlab Org', users: 3 },
{ __typename: 'Namespace', id: 483, name: 'Gnuwget', users: 12 },
];
export const plans = [
{ id: 'firstPlanId', code: 'bronze', pricePerYear: 48, name: 'bronze', __typename: 'Plan' },
{ id: 'secondPlanId', code: 'silver', pricePerYear: 228, name: 'silver', __typename: 'Plan' },
];
export const mockNewUser = 'false';
export const mockFullName = 'John Admin';
export const mockSetupForCompany = 'true';
export const stateData = {
state: {
plans,
namespaces: [],
subscription: {
planId: 'secondPlanId',
quantity: 1,
namespaceId: null,
paymentMethodId: null,
__typename: 'Subscription',
},
customer: {
country: null,
address1: null,
address2: null,
city: null,
state: null,
zipCode: null,
company: null,
__typename: 'Customer',
},
fullName: 'Full Name',
isNewUser: false,
isSetupForCompany: true,
namespaces: [],
subscription: {
planId: 'secondPlanId',
quantity: 1,
namespaceId: null,
paymentMethodId: null,
__typename: 'Subscription',
},
customer: {
country: null,
address1: null,
address2: null,
city: null,
state: null,
zipCode: null,
company: null,
__typename: 'Customer',
},
fullName: 'Full Name',
isNewUser: false,
isSetupForCompany: true,
stepList: STEPS,
activeStep: STEPS[0],
};
import apolloProvider from 'ee/subscriptions/buy_minutes/graphql';
import { writeInitialDataToApolloCache } from 'ee/subscriptions/buy_minutes/utils';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import {
mockNamespaces,
mockParsedNamespaces,
mockNewUser,
mockFullName,
mockSetupForCompany,
} from './mock_data';
const DEFAULT_DATA = {
groupData: mockNamespaces,
newUser: mockNewUser,
fullName: mockFullName,
setupForCompany: mockSetupForCompany,
};
describe('utils', () => {
beforeEach(() => {
apolloProvider.clients.defaultClient.clearStore();
});
describe('#writeInitialDataToApolloCache', () => {
describe('namespaces', () => {
describe.each`
namespaces | parsedNamespaces | throws
${'[]'} | ${[]} | ${false}
${'null'} | ${{}} | ${true}
${''} | ${{}} | ${true}
${mockNamespaces} | ${mockParsedNamespaces} | ${false}
`('parameter decoding', ({ namespaces, parsedNamespaces, throws }) => {
it(`decodes ${namespaces} to ${parsedNamespaces}`, async () => {
if (throws) {
expect(() => {
writeInitialDataToApolloCache(apolloProvider, { groupData: namespaces });
}).toThrow();
} else {
writeInitialDataToApolloCache(apolloProvider, {
...DEFAULT_DATA,
groupData: namespaces,
});
const sourceData = await apolloProvider.clients.defaultClient.query({
query: stateQuery,
});
expect(sourceData.data.namespaces).toStrictEqual(parsedNamespaces);
}
});
});
});
describe('newUser', () => {
describe.each`
newUser | parsedNewUser | throws
${'true'} | ${true} | ${false}
${mockNewUser} | ${false} | ${false}
${''} | ${false} | ${true}
`('parameter decoding', ({ newUser, parsedNewUser, throws }) => {
it(`decodes ${newUser} to ${parsedNewUser}`, async () => {
if (throws) {
expect(() => {
writeInitialDataToApolloCache(apolloProvider, { newUser });
}).toThrow();
} else {
writeInitialDataToApolloCache(apolloProvider, { ...DEFAULT_DATA, newUser });
const sourceData = await apolloProvider.clients.defaultClient.query({
query: stateQuery,
});
expect(sourceData.data.isNewUser).toEqual(parsedNewUser);
}
});
});
});
describe('fullName', () => {
describe.each`
fullName | parsedFullName
${mockFullName} | ${mockFullName}
${''} | ${''}
${null} | ${null}
`('parameter decoding', ({ fullName, parsedFullName }) => {
it(`decodes ${fullName} to ${parsedFullName}`, async () => {
writeInitialDataToApolloCache(apolloProvider, { ...DEFAULT_DATA, fullName });
const sourceData = await apolloProvider.clients.defaultClient.query({
query: stateQuery,
});
expect(sourceData.data.fullName).toEqual(parsedFullName);
});
});
});
describe('setupForCompany', () => {
describe.each`
setupForCompany | parsedSetupForCompany | throws
${mockSetupForCompany} | ${true} | ${false}
${'false'} | ${false} | ${false}
${''} | ${false} | ${true}
`('parameter decoding', ({ setupForCompany, parsedSetupForCompany, throws }) => {
it(`decodes ${setupForCompany} to ${parsedSetupForCompany}`, async () => {
if (throws) {
expect(() => {
writeInitialDataToApolloCache(apolloProvider, { setupForCompany });
}).toThrow();
} else {
writeInitialDataToApolloCache(apolloProvider, {
...DEFAULT_DATA,
newUser: 'true',
setupForCompany,
});
const sourceData = await apolloProvider.clients.defaultClient.query({
query: stateQuery,
});
expect(sourceData.data.isSetupForCompany).toEqual(parsedSetupForCompany);
}
});
});
});
});
});
......@@ -2,8 +2,8 @@ import { mount, createLocalVue } from '@vue/test-utils';
import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import BillingAddress from 'ee/subscriptions/new/components/checkout/billing_address.vue';
import { STEPS } from 'ee/subscriptions/new/constants';
import { getStoreConfig } from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
......
......@@ -3,8 +3,8 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex';
import Api from 'ee/api';
import { STEPS } from 'ee/subscriptions/constants';
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 { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
......
import { mount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import PaymentMethod from 'ee/subscriptions/new/components/checkout/payment_method.vue';
import { STEPS } from 'ee/subscriptions/new/constants';
import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
......
import { mount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import Vuex from 'vuex';
import { STEPS } from 'ee/subscriptions/constants';
import Component from 'ee/subscriptions/new/components/checkout/subscription_details.vue';
import { NEW_GROUP, STEPS } from 'ee/subscriptions/new/constants';
import { NEW_GROUP } from 'ee/subscriptions/new/constants';
import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
......
......@@ -9,7 +9,7 @@ describe('ee/vue_shared/purchase_flow/graphql/resolvers', () => {
let mockApolloClient;
describe('Query', () => {
beforeEach(async () => {
beforeEach(() => {
const mockApollo = createMockApolloProvider(STEPS, 0);
mockApolloClient = mockApollo.clients.defaultClient;
});
......
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