Commit 731b929e authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'vs/migrate-billing-address-to-gql' into 'master'

Migrate BillingAddress to GraphQL

See merge request gitlab-org/gitlab!63492
parents 3cb81609 5da8300a
......@@ -3,21 +3,17 @@ import ProgressBar from 'ee/registrations/components/progress_bar.vue';
import { STEPS, SUBSCRIPTON_FLOW_STEPS } from 'ee/registrations/constants';
import STATE_QUERY from 'ee/subscriptions/graphql/queries/state.query.graphql';
import { s__ } from '~/locale';
import BillingAddress from './checkout/billing_address.vue';
import SubscriptionDetails from './checkout/subscription_details.vue';
export default {
components: { ProgressBar, SubscriptionDetails },
components: { ProgressBar, SubscriptionDetails, BillingAddress },
props: {
plans: {
type: Array,
required: true,
},
},
data() {
return {
isNewUser: null,
};
},
apollo: {
isNewUser: {
query: STATE_QUERY,
......@@ -40,6 +36,7 @@ export default {
<div class="flash-container"></div>
<h2 class="gl-mt-6 gl-mb-7 gl-mb-lg-5">{{ $options.i18n.checkout }}</h2>
<subscription-details :plans="plans" />
<billing-address />
</div>
</div>
</template>
<script>
import { GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { STEPS } from 'ee/subscriptions/constants';
import updateStateMutation from 'ee/subscriptions/graphql/mutations/update_state.mutation.graphql';
import countriesQuery from 'ee/subscriptions/graphql/queries/countries.query.graphql';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import statesQuery from 'ee/subscriptions/graphql/queries/states.query.graphql';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
export default {
components: {
Step,
GlFormGroup,
GlFormInput,
GlFormSelect,
},
directives: {
autofocusonshow,
},
data() {
return {
countries: [],
};
},
apollo: {
customer: {
query: stateQuery,
},
countries: {
query: countriesQuery,
},
states: {
query: statesQuery,
skip() {
return !this.customer.country;
},
variables() {
return {
countryId: this.customer.country,
};
},
},
},
computed: {
countryModel: {
get() {
return this.customer.country;
},
set(country) {
this.updateState({ customer: { country, state: null } });
},
},
streetAddressLine1Model: {
get() {
return this.customer.address1;
},
set(address1) {
this.updateState({ customer: { address1 } });
},
},
streetAddressLine2Model: {
get() {
return this.customer.address2;
},
set(address2) {
this.updateState({ customer: { address2 } });
},
},
cityModel: {
get() {
return this.customer.city;
},
set(city) {
this.updateState({ customer: { city } });
},
},
countryStateModel: {
get() {
return this.customer.state;
},
set(state) {
this.updateState({ customer: { state } });
},
},
zipCodeModel: {
get() {
return this.customer.zipCode;
},
set(zipCode) {
this.updateState({ customer: { zipCode } });
},
},
isValid() {
return (
!isEmpty(this.customer.country) &&
!isEmpty(this.customer.address1) &&
!isEmpty(this.customer.city) &&
!isEmpty(this.customer.zipCode)
);
},
countryOptionsWithDefault() {
return [
{
name: this.$options.i18n.countrySelectPrompt,
id: null,
},
...this.countries,
];
},
stateOptionsWithDefault() {
return [
{
name: this.$options.i18n.stateSelectPrompt,
id: null,
},
...this.states,
];
},
selectedStateName() {
if (!this.customer.state || !this.states) {
return '';
}
return this.states.find((state) => state.id === this.customer.state).name;
},
},
methods: {
updateState(payload) {
this.$apollo
.mutate({
mutation: updateStateMutation,
variables: {
input: payload,
},
})
.catch((error) => {
createFlash({ message: GENERAL_ERROR_MESSAGE, error, captureError: true });
});
},
},
i18n: {
stepTitle: s__('Checkout|Billing address'),
nextStepButtonText: s__('Checkout|Continue to payment'),
countryLabel: s__('Checkout|Country'),
countrySelectPrompt: s__('Checkout|Please select a country'),
streetAddressLabel: s__('Checkout|Street address'),
cityLabel: s__('Checkout|City'),
stateLabel: s__('Checkout|State'),
stateSelectPrompt: s__('Checkout|Please select a state'),
zipCodeLabel: s__('Checkout|Zip code'),
},
stepId: STEPS[1].id,
};
</script>
<template>
<step
v-if="!$apollo.loading.customer"
:step-id="$options.stepId"
:title="$options.i18n.stepTitle"
:is-valid="isValid"
:next-step-button-text="$options.i18n.nextStepButtonText"
>
<template #body>
<gl-form-group
v-if="!$apollo.loading.countries"
:label="$options.i18n.countryLabel"
label-size="sm"
class="mb-3"
>
<gl-form-select
v-model="countryModel"
v-autofocusonshow
:options="countryOptionsWithDefault"
class="js-country"
value-field="id"
text-field="name"
data-qa-selector="country"
/>
</gl-form-group>
<gl-form-group :label="$options.i18n.streetAddressLabel" label-size="sm" class="mb-3">
<gl-form-input
v-model="streetAddressLine1Model"
type="text"
data-qa-selector="street_address_1"
/>
<gl-form-input
v-model="streetAddressLine2Model"
type="text"
data-qa-selector="street_address_2"
/>
</gl-form-group>
<gl-form-group :label="$options.i18n.cityLabel" label-size="sm" class="mb-3">
<gl-form-input v-model="cityModel" type="text" data-qa-selector="city" />
</gl-form-group>
<div class="combined d-flex">
<gl-form-group
v-if="!$apollo.loading.states && states"
:label="$options.i18n.stateLabel"
label-size="sm"
class="mr-3 w-50"
>
<gl-form-select
v-model="countryStateModel"
:options="stateOptionsWithDefault"
value-field="id"
text-field="name"
data-qa-selector="state"
/>
</gl-form-group>
<gl-form-group :label="$options.i18n.zipCodeLabel" label-size="sm" class="w-50">
<gl-form-input v-model="zipCodeModel" type="text" data-qa-selector="zip_code" />
</gl-form-group>
</div>
</template>
<template #summary>
<div class="js-summary-line-1">{{ customer.address1 }}</div>
<div class="js-summary-line-2">{{ customer.address2 }}</div>
<div class="js-summary-line-3">
{{ customer.city }}, {{ customer.country }} {{ selectedStateName }} {{ customer.zipCode }}
</div>
</template>
</step>
</template>
......@@ -6,6 +6,9 @@ import UPDATE_STATE from 'ee/subscriptions/graphql/mutations/update_state.mutati
import STATE_QUERY from 'ee/subscriptions/graphql/queries/state.query.graphql';
import { NEW_GROUP } from 'ee/subscriptions/new/constants';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants';
import createFlash from '~/flash';
import { getParameterValues } from '~/lib/utils/url_utility';
import { sprintf, s__, __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
......@@ -34,45 +37,34 @@ export default {
customer: {},
isSetupForCompany: null,
isNewUser: null,
selectedPlanId: 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 || {};
manual: true,
result({ data, loading }) {
if (loading) {
return;
}
this.subscription = subscription;
this.namespaces = namespaces;
this.customer = customer;
this.isSetupForCompany = isSetupForCompany;
this.isNewUser = isNewUser;
this.subscription = data.subscription;
this.namespaces = data.namespaces;
this.customer = data.customer;
this.isSetupForCompany = data.isSetupForCompany;
this.isNewUser = data.isNewUser;
this.selectedPlanId = data.selectedPlanId;
},
},
},
computed: {
selectedPlanModel: {
get() {
return this.subscription.planId || this.plans[0].code;
return this.selectedPlanId || this.plans[0].id;
},
set(planId) {
this.updateSubscription({ subscription: { planId } });
this.updateState({ subscription: { planId } });
},
},
selectedGroupModel: {
......@@ -83,7 +75,7 @@ export default {
const quantity =
this.namespaces.find((namespace) => namespace.id === namespaceId)?.users || 1;
this.updateSubscription({ subscription: { namespaceId, quantity } });
this.updateState({ subscription: { namespaceId, quantity } });
},
},
numberOfUsersModel: {
......@@ -91,7 +83,7 @@ export default {
return this.selectedGroupUsers || 1;
},
set(number) {
this.updateSubscription({ subscription: { quantity: number } });
this.updateState({ subscription: { quantity: number } });
},
},
companyModel: {
......@@ -99,11 +91,11 @@ export default {
return this.customer.company;
},
set(company) {
this.updateSubscription({ customer: { company } });
this.updateState({ customer: { company } });
},
},
selectedPlan() {
const selectedPlan = this.plans.find((plan) => plan.code === this.subscription.planId);
const selectedPlan = this.plans.find((plan) => plan.id === this.selectedPlanId);
if (!selectedPlan) {
return this.plans[0];
}
......@@ -111,13 +103,13 @@ export default {
return selectedPlan;
},
selectedPlanTextLine() {
return sprintf(this.$options.i18n.selectedPlan, { selectedPlanText: this.selectedPlan.code });
return sprintf(this.$options.i18n.selectedPlan, { selectedPlanText: this.selectedPlan.id });
},
selectedGroup() {
return this.namespaces.find((namespace) => namespace.id === this.subscription.namespaceId);
},
selectedGroupUsers() {
return (
this.namespaces.find((namespace) => namespace.id === this.subscription.namespaceId)
?.users || 1
);
return this.selectedGroup?.users || 1;
},
isGroupSelected() {
return this.subscription.namespaceId !== null;
......@@ -130,13 +122,13 @@ export default {
isValid() {
if (this.isSetupForCompany) {
return (
!isEmpty(this.subscription.planId) &&
(!isEmpty(this.customer.company) || this.isNewGroupSelected) &&
this.isNumberOfUsersValid
this.isNumberOfUsersValid &&
!isEmpty(this.selectedPlanId) &&
(!isEmpty(this.customer.company) || this.isGroupSelected)
);
}
return !isEmpty(this.subscription.planId) && this.subscription.quantity === 1;
return this.subscription.quantity === 1 && !isEmpty(this.selectedPlanId);
},
isShowingGroupSelector() {
return !this.isNewUser && this.namespaces.length;
......@@ -166,18 +158,41 @@ export default {
: this.$options.i18n.selectedGroupDescription;
},
},
mounted() {
this.preselectPlan();
},
methods: {
updateSubscription(payload = {}) {
this.$apollo.mutate({
updateState(payload = {}) {
this.$apollo
.mutate({
mutation: UPDATE_STATE,
variables: {
input: payload,
},
})
.catch((error) => {
createFlash({ message: GENERAL_ERROR_MESSAGE, error, captureError: true });
});
},
toggleIsSetupForCompany() {
this.updateSubscription({ isSetupForCompany: !this.isSetupForCompany });
},
preselectPlan() {
if (this.selectedPlanId) {
return;
}
let preselectedPlan = this.plans[0];
const planIdFromSearchParams = getParameterValues('planId');
if (planIdFromSearchParams.length > 0) {
preselectedPlan =
this.plans.find((plan) => plan.id === planIdFromSearchParams[0].id) || preselectedPlan;
}
this.updateState({ selectedPlanId: preselectedPlan.id });
},
},
i18n: {
stepTitle: s__('Checkout|Subscription details'),
......@@ -213,7 +228,7 @@ export default {
v-model="selectedPlanModel"
v-autofocusonshow
:options="plans"
value-field="code"
value-field="id"
text-field="name"
data-qa-selector="plan_name"
/>
......@@ -271,7 +286,7 @@ export default {
{{ selectedPlanTextLine }}
</strong>
<div v-if="isSetupForCompany" ref="summary-line-2">
{{ $options.i18n.group }}: {{ customer.company || selectedGroupName }}
{{ $options.i18n.group }}: {{ customer.company || selectedGroup.name }}
</div>
<div ref="summary-line-3">{{ $options.i18n.users }}: {{ subscription.quantity }}</div>
</template>
......
......@@ -21,15 +21,14 @@ export default {
apollo: {
state: {
query: STATE_QUERY,
update(data) {
return data;
},
manual: true,
result({ data }) {
this.subscription = data.subscription;
this.namespaces = data.namespaces;
this.isSetupForCompany = data.isSetupForCompany;
this.fullName = data.fullName;
this.customer = data.customer;
this.selectedPlanId = data.selectedPlanId;
},
},
},
......@@ -41,11 +40,12 @@ export default {
collapsed: true,
fullName: null,
customer: {},
selectedPlanId: null,
};
},
computed: {
selectedPlan() {
return this.plans.find((plan) => plan.code === this.subscription.planId);
return this.plans.find((plan) => plan.code === this.selectedPlanId);
},
selectedPlanPrice() {
return this.selectedPlan.pricePerYear;
......@@ -106,7 +106,7 @@ export default {
</script>
<template>
<div
v-if="!$apollo.loading && (!isGroupSelected || isSelectedGroupPresent)"
v-if="!$apollo.loading && (!isGroupSelected || isSelectedGroupPresent) && selectedPlan"
class="order-summary gl-display-flex gl-flex-direction-column gl-flex-grow-1 gl-mt-2 mt-lg-5"
>
<div class="d-lg-none">
......
......@@ -4,3 +4,4 @@ export const planTags = {
};
/* eslint-enable @gitlab/require-i18n-strings */
export const CUSTOMER_CLIENT = 'customerClient';
export const GITLAB_CLIENT = 'gitlabClient';
import { merge } from 'lodash';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import purchaseFlowResolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers';
import typeDefs from 'ee/vue_shared/purchase_flow/graphql/typedefs.graphql';
import createClient from '~/lib/graphql';
import { CUSTOMER_CLIENT } from './constants';
import { GITLAB_CLIENT, CUSTOMER_CLIENT } from './constants';
import { resolvers } from './graphql/resolvers';
Vue.use(VueApollo);
const defaultClient = createClient(resolvers, { assumeImmutableResults: true });
const gitlabClient = createClient(merge({}, resolvers, purchaseFlowResolvers), {
typeDefs,
assumeImmutableResults: true,
});
const customerClient = createClient(
{},
{ path: '/-/customers_dot/proxy/graphql', useGet: true, assumeImmutableResults: true },
{
path: '/-/customers_dot/proxy/graphql',
useGet: true,
assumeImmutableResults: true,
},
);
export default new VueApollo({
defaultClient,
defaultClient: gitlabClient,
clients: {
[GITLAB_CLIENT]: gitlabClient,
[CUSTOMER_CLIENT]: customerClient,
},
});
......@@ -3,7 +3,7 @@ import { merge } from 'lodash';
import Api from 'ee/api';
import * as SubscriptionsApi from 'ee/api/subscriptions_api';
import { ERROR_FETCHING_COUNTRIES, ERROR_FETCHING_STATES } from 'ee/subscriptions/constants';
import STATE_QUERY from 'ee/subscriptions/graphql/queries/state.query.graphql';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import createFlash from '~/flash';
// NOTE: These resolvers are temporary and will be removed in the future.
......@@ -15,16 +15,20 @@ export const resolvers = {
.then(({ data }) =>
data.map(([name, alpha2]) =>
// eslint-disable-next-line @gitlab/require-i18n-strings
({ name, alpha2, __typename: 'Country' }),
({ name, id: alpha2, __typename: 'Country' }),
),
)
.catch(() => createFlash({ message: ERROR_FETCHING_COUNTRIES }));
},
states: (countryId) => {
states: (_, { countryId }) => {
return Api.fetchStates(countryId)
.then(({ data }) => {
return Object.entries(data).map(([key, value]) => ({
id: value,
name: key,
// eslint-disable-next-line @gitlab/require-i18n-strings
return data.map((state) => Object.assign(state, { __typename: 'State' }));
__typename: 'State',
}));
})
.catch(() => createFlash({ message: ERROR_FETCHING_STATES }));
},
......@@ -34,13 +38,13 @@ export const resolvers = {
return SubscriptionsApi.createSubscription(groupId, customer, subscription);
},
updateState: (_, { input }, { cache }) => {
const oldState = cache.readQuery({ query: STATE_QUERY });
const oldState = cache.readQuery({ query: stateQuery });
const state = produce(oldState, (draftState) => {
merge(draftState, input);
});
cache.writeQuery({ query: STATE_QUERY, data: state });
cache.writeQuery({ query: stateQuery, data: state });
},
},
};
......@@ -24,8 +24,8 @@ export function writeInitialDataToApolloCache(apolloProvider, dataset) {
isSetupForCompany,
namespaces,
fullName,
selectedPlanId: planId,
subscription: {
planId,
paymentMethodId: null,
quantity: 1,
namespaceId: null,
......
query state {
query State {
namespaces @client {
id
name
......@@ -7,6 +7,7 @@ query state {
isNewUser @client
fullName @client
isSetupForCompany @client
selectedPlanId @client
customer @client {
country
address1
......@@ -17,7 +18,6 @@ query state {
company
}
subscription @client {
planId
paymentMethodId
quantity
namespaceId
......
query State($countryId: ID!) {
states(countryId: $countryId) @client {
id
name
}
}
import { mount, createLocalVue } from '@vue/test-utils';
import { merge } from 'lodash';
import VueApollo from 'vue-apollo';
import BillingAddress from 'ee/subscriptions/buy_minutes/components/checkout/billing_address.vue';
import { resolvers } from 'ee/subscriptions/buy_minutes/graphql/resolvers';
import { STEPS } from 'ee/subscriptions/constants';
import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql';
import Step from 'ee/vue_shared/purchase_flow/components/step.vue';
import { stateData as initialStateData } from 'ee_jest/subscriptions/buy_minutes/mock_data';
import { createMockApolloProvider } from 'ee_jest/vue_shared/purchase_flow/spec_helper';
import waitForPromises from 'helpers/wait_for_promises';
const localVue = createLocalVue();
localVue.use(VueApollo);
describe('Billing Address', () => {
let wrapper;
const apolloResolvers = {
Query: {
countries: jest.fn().mockResolvedValue([
{ id: 'NL', name: 'Netherlands' },
{ id: 'US', name: 'United States of America' },
]),
states: jest.fn().mockResolvedValue([{ id: 'CA', name: 'California' }]),
},
};
const createComponent = (apolloLocalState = {}) => {
const apolloProvider = createMockApolloProvider(STEPS, STEPS[1], {
...resolvers,
...apolloResolvers,
});
apolloProvider.clients.defaultClient.cache.writeQuery({
query: stateQuery,
data: merge({}, initialStateData, apolloLocalState),
});
return mount(BillingAddress, {
localVue,
apolloProvider,
});
};
describe('country options', () => {
const countrySelect = () => wrapper.find('.js-country');
beforeEach(() => {
wrapper = createComponent();
return waitForPromises();
});
afterEach(() => {
wrapper.destroy();
});
it('displays the countries returned from the server', () => {
expect(countrySelect().html()).toContain('<option value="NL">Netherlands</option>');
});
});
describe('validations', () => {
const isStepValid = () => wrapper.find(Step).props('isValid');
const customerData = {
country: 'US',
address1: 'address line 1',
address2: 'address line 2',
city: 'city',
zipCode: 'zip',
state: null,
};
it('is valid when country, streetAddressLine1, city and zipCode have been entered', async () => {
wrapper = createComponent({ customer: customerData });
await waitForPromises();
expect(isStepValid()).toBe(true);
});
it('is invalid when country is undefined', async () => {
wrapper = createComponent({ customer: { country: null } });
await waitForPromises();
expect(isStepValid()).toBe(false);
});
it('is invalid when streetAddressLine1 is undefined', async () => {
wrapper = createComponent({ customer: { address1: null } });
await waitForPromises();
expect(isStepValid()).toBe(false);
});
it('is invalid when city is undefined', async () => {
wrapper = createComponent({ customer: { city: null } });
await waitForPromises();
expect(isStepValid()).toBe(false);
});
it('is invalid when zipCode is undefined', async () => {
wrapper = createComponent({ customer: { zipCode: null } });
await waitForPromises();
expect(isStepValid()).toBe(false);
});
});
describe('showing the summary', () => {
beforeEach(async () => {
wrapper = createComponent({
customer: {
country: 'US',
address1: 'address line 1',
address2: 'address line 2',
city: 'city',
zipCode: 'zip',
state: 'CA',
},
});
await waitForPromises();
});
it('should show the entered address line 1', () => {
expect(wrapper.find('.js-summary-line-1').text()).toBe('address line 1');
});
it('should show the entered address line 2', () => {
expect(wrapper.find('.js-summary-line-2').text()).toBe('address line 2');
});
it('should show the entered address city, state and zip code', () => {
expect(wrapper.find('.js-summary-line-3').text()).toBe('city, US California zip');
});
});
});
......@@ -17,7 +17,7 @@ localVue.use(VueApollo);
describe('Order Summary', () => {
const resolvers = { ...purchaseFlowResolvers, ...subscriptionsResolvers };
const initialStateData = {
subscription: { planId: 'silver' },
selectedPlanId: 'silver',
};
let wrapper;
......@@ -105,7 +105,8 @@ describe('Order Summary', () => {
describe('the default plan', () => {
beforeEach(() => {
createComponent({
subscription: { planId: 'bronze', quantity: 1 },
subscription: { quantity: 1 },
selectedPlanId: 'bronze',
});
});
......@@ -126,7 +127,8 @@ describe('Order Summary', () => {
describe('Changing the number of users', () => {
beforeEach(() => {
createComponent({
subscription: { planId: 'silver', quantity: 1 },
subscription: { quantity: 1 },
selectedPlanId: 'silver',
});
});
......@@ -151,7 +153,8 @@ describe('Order Summary', () => {
describe('3 selected users', () => {
beforeEach(() => {
createComponent({
subscription: { planId: 'silver', quantity: 3 },
subscription: { quantity: 3 },
selectedPlanId: 'silver',
});
});
......@@ -175,7 +178,8 @@ describe('Order Summary', () => {
describe('no selected users', () => {
beforeEach(() => {
createComponent({
subscription: { planId: 'silver', quantity: 0 },
subscription: { quantity: 0 },
selectedPlanId: 'silver',
});
});
......
......@@ -263,25 +263,14 @@ describe('Subscription Details', () => {
describe('when setting up for a company', () => {
it('should be valid', () => {
wrapper = createComponent({
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 14 },
subscription: { namespaceId: 483, quantity: 14 },
selectedPlanId: 'firstPlanId',
customer: { company: 'Organization name' },
});
expect(isStepValid()).toBe(true);
});
it('should be invalid when no plan is selected', async () => {
wrapper = createComponent({
isSetupForCompany: true,
subscription: { planId: null, namespaceId: 483, quantity: 14 },
customer: { company: 'Organization name' },
});
await nextTick();
expect(isStepValid()).toBe(false);
});
it('should be invalid when no organization name is given, and no group is selected', async () => {
wrapper = createComponent({
isSetupForCompany: true,
......@@ -321,7 +310,8 @@ describe('Subscription Details', () => {
beforeEach(() => {
wrapper = createComponent({
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 1 },
subscription: { namespaceId: 483, quantity: 1 },
selectedPlanId: 'firstPlanId',
customer: { company: 'Organization name' },
});
});
......@@ -330,22 +320,11 @@ describe('Subscription Details', () => {
expect(isStepValid()).toBe(true);
});
it('should be invalid when no plan is selected', async () => {
wrapper = createComponent({
isSetupForCompany: false,
subscription: { planId: null, namespaceId: 483, quantity: 1 },
customer: { company: 'Organization name' },
});
await nextTick();
expect(isStepValid()).toBe(false);
});
it('should be invalid when no number of users is 0', async () => {
wrapper = createComponent({
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 0 },
subscription: { namespaceId: 483, quantity: 0 },
selectedPlanId: 'firstPlanId',
customer: { company: 'Organization name' },
});
......@@ -357,7 +336,8 @@ describe('Subscription Details', () => {
it('should be invalid when no number of users is greater than 1', async () => {
wrapper = createComponent({
isSetupForCompany: false,
subscription: { planId: 'firstPlanId', namespaceId: 483, quantity: 2 },
subscription: { namespaceId: 483, quantity: 2 },
selectedPlanId: 'firstPlanId',
customer: { company: 'Organization name' },
});
......
......@@ -47,7 +47,7 @@ const countries = [
['Uruguay', 'UY'],
];
const states = [{ id: 1, name: 'state' }];
const states = { California: 'CA' };
describe('~/subscriptions/buy_minutes/graphql/resolvers', () => {
describe('Query', () => {
......@@ -62,8 +62,8 @@ describe('~/subscriptions/buy_minutes/graphql/resolvers', () => {
expect(createFlash).not.toHaveBeenCalled();
expect(result).toStrictEqual([
{ name: 'United States of America', alpha2: 'US', __typename: 'Country' },
{ name: 'Uruguay', alpha2: 'UY', __typename: 'Country' },
{ name: 'United States of America', id: 'US', __typename: 'Country' },
{ name: 'Uruguay', id: 'UY', __typename: 'Country' },
]);
});
});
......@@ -88,10 +88,10 @@ describe('~/subscriptions/buy_minutes/graphql/resolvers', () => {
});
it('returns an array of states with typename', async () => {
const result = await resolvers.Query.states(1);
const result = await resolvers.Query.states(null, { countryId: 1 });
expect(createFlash).not.toHaveBeenCalled();
expect(result).toStrictEqual([{ id: 1, name: 'state', __typename: 'State' }]);
expect(result).toStrictEqual([{ id: 'CA', name: 'California', __typename: 'State' }]);
});
});
......@@ -101,7 +101,7 @@ describe('~/subscriptions/buy_minutes/graphql/resolvers', () => {
});
it('shows a flash message', async () => {
await resolvers.Query.states();
await resolvers.Query.states(null, { countryId: 1 });
expect(createFlash).toHaveBeenCalledWith({ message: ERROR_FETCHING_STATES });
});
......
......@@ -19,12 +19,12 @@ export const mockSetupForCompany = 'true';
export const stateData = {
namespaces: [],
subscription: {
planId: 'secondPlanId',
quantity: 1,
namespaceId: null,
paymentMethodId: null,
__typename: 'Subscription',
},
selectedPlanId: null,
customer: {
country: null,
address1: null,
......
import { merge } from 'lodash';
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);
export function createMockApolloProvider(stepList, initialStepIndex = 0, additionalResolvers = {}) {
const mockApollo = createMockApollo([], merge({}, resolvers, additionalResolvers));
mockApollo.clients.defaultClient.cache.writeQuery({
query: stepListQuery,
data: { stepList },
......
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