Commit dbdb7f6f authored by Alex Buijs's avatar Alex Buijs

Allow selecting a group to apply license to

When an exisiting user is buying a license, allow
the user to select a group if there is one.
parent a29c2a71
...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState(['newUser']), ...mapState(['isNewUser']),
}, },
i18n: { i18n: {
checkout: s__('Checkout|Checkout'), checkout: s__('Checkout|Checkout'),
...@@ -26,7 +26,7 @@ export default { ...@@ -26,7 +26,7 @@ export default {
<template> <template>
<div class="checkout d-flex flex-column justify-content-between w-100"> <div class="checkout d-flex flex-column justify-content-between w-100">
<div class="full-width"> <div class="full-width">
<progress-bar v-if="newUser" :step="step" /> <progress-bar v-if="isNewUser" :step="step" />
<div class="flash-container"></div> <div class="flash-container"></div>
<h2 class="mt-4 mb-3 mb-lg-5">{{ $options.i18n.checkout }}</h2> <h2 class="mt-4 mb-3 mb-lg-5">{{ $options.i18n.checkout }}</h2>
<subscription-details /> <subscription-details />
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import _ from 'underscore'; import _ from 'underscore';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import { NEW_GROUP } from 'ee/subscriptions/new/constants';
import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui'; import { GlFormGroup, GlFormSelect, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale'; import { sprintf, s__ } from '~/locale';
import Step from './step.vue'; import Step from './step.vue';
...@@ -22,11 +23,19 @@ export default { ...@@ -22,11 +23,19 @@ export default {
...mapState([ ...mapState([
'availablePlans', 'availablePlans',
'selectedPlan', 'selectedPlan',
'isNewUser',
'groupData',
'selectedGroup',
'isSetupForCompany', 'isSetupForCompany',
'organizationName', 'organizationName',
'numberOfUsers', 'numberOfUsers',
]), ]),
...mapGetters(['selectedPlanText']), ...mapGetters([
'selectedPlanText',
'isGroupSelected',
'selectedGroupUsers',
'selectedGroupName',
]),
selectedPlanModel: { selectedPlanModel: {
get() { get() {
return this.selectedPlan; return this.selectedPlan;
...@@ -35,6 +44,14 @@ export default { ...@@ -35,6 +44,14 @@ export default {
this.updateSelectedPlan(selectedPlan); this.updateSelectedPlan(selectedPlan);
}, },
}, },
selectedGroupModel: {
get() {
return this.selectedGroup;
},
set(selectedGroup) {
this.updateSelectedGroup(selectedGroup);
},
},
numberOfUsersModel: { numberOfUsersModel: {
get() { get() {
return this.numberOfUsers; return this.numberOfUsers;
...@@ -58,16 +75,42 @@ export default { ...@@ -58,16 +75,42 @@ export default {
if (this.isSetupForCompany) { if (this.isSetupForCompany) {
return ( return (
!_.isEmpty(this.selectedPlan) && !_.isEmpty(this.selectedPlan) &&
!_.isEmpty(this.organizationName) && (!_.isEmpty(this.organizationName) || this.isGroupSelected) &&
this.numberOfUsers > 0 this.numberOfUsers > 0 &&
this.numberOfUsers >= this.selectedGroupUsers
); );
} }
return !_.isEmpty(this.selectedPlan) && this.numberOfUsers === 1; return !_.isEmpty(this.selectedPlan) && this.numberOfUsers === 1;
}, },
isShowingGroupSelector() {
return !this.isNewUser && this.groupData.length;
},
isShowingNameOfCompanyInput() {
return this.isSetupForCompany && (!this.groupData.length || this.selectedGroup === NEW_GROUP);
},
groupOptionsWithDefault() {
return [
{
text: this.$options.i18n.groupSelectPrompt,
value: null,
},
...this.groupData,
{
text: this.$options.i18n.groupSelectCreateNewOption,
value: NEW_GROUP,
},
];
},
groupSelectDescription() {
return this.selectedGroup === NEW_GROUP
? this.$options.i18n.createNewGroupDescription
: this.$options.i18n.selectedGroupDescription;
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
'updateSelectedPlan', 'updateSelectedPlan',
'updateSelectedGroup',
'toggleIsSetupForCompany', 'toggleIsSetupForCompany',
'updateNumberOfUsers', 'updateNumberOfUsers',
'updateOrganizationName', 'updateOrganizationName',
...@@ -77,6 +120,11 @@ export default { ...@@ -77,6 +120,11 @@ export default {
stepTitle: s__('Checkout|Subscription details'), stepTitle: s__('Checkout|Subscription details'),
nextStepButtonText: s__('Checkout|Continue to billing'), nextStepButtonText: s__('Checkout|Continue to billing'),
selectedPlanLabel: s__('Checkout|GitLab plan'), selectedPlanLabel: s__('Checkout|GitLab plan'),
selectedGroupLabel: s__('Checkout|GitLab group'),
groupSelectPrompt: s__('Checkout|Select'),
groupSelectCreateNewOption: s__('Checkout|Create a new group'),
selectedGroupDescription: s__('Checkout|Your subscription will be applied to this group'),
createNewGroupDescription: s__("Checkout|You'll create your new group after checkout"),
organizationNameLabel: s__('Checkout|Name of company or organization using GitLab'), organizationNameLabel: s__('Checkout|Name of company or organization using GitLab'),
numberOfUsersLabel: s__('Checkout|Number of users'), numberOfUsersLabel: s__('Checkout|Number of users'),
needMoreUsersLink: s__('Checkout|Need more users? Purchase GitLab for your %{company}.'), needMoreUsersLink: s__('Checkout|Need more users? Purchase GitLab for your %{company}.'),
...@@ -95,46 +143,44 @@ export default { ...@@ -95,46 +143,44 @@ export default {
:next-step-button-text="$options.i18n.nextStepButtonText" :next-step-button-text="$options.i18n.nextStepButtonText"
> >
<template #body> <template #body>
<gl-form-group :label="$options.i18n.selectedPlanLabel" label-size="sm" class="mb-3">
<gl-form-select v-model="selectedPlanModel" v-autofocusonshow :options="availablePlans" />
</gl-form-group>
<gl-form-group <gl-form-group
:label="$options.i18n.selectedPlanLabel" v-if="isShowingGroupSelector"
:label="$options.i18n.selectedGroupLabel"
:description="groupSelectDescription"
label-size="sm" label-size="sm"
label-for="selectedPlan" class="mb-3"
class="append-bottom-default"
> >
<gl-form-select <gl-form-select
id="selectedPlan" ref="group-select"
v-model="selectedPlanModel" v-model="selectedGroupModel"
v-autofocusonshow :options="groupOptionsWithDefault"
:options="availablePlans"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
v-if="isSetupForCompany" v-if="isShowingNameOfCompanyInput"
:label="$options.i18n.organizationNameLabel" :label="$options.i18n.organizationNameLabel"
label-size="sm" label-size="sm"
label-for="organizationName" class="mb-3"
class="append-bottom-default"
> >
<gl-form-input id="organizationName" v-model="organizationNameModel" type="text" /> <gl-form-input ref="organization-name" v-model="organizationNameModel" type="text" />
</gl-form-group> </gl-form-group>
<div class="combined d-flex"> <div class="combined d-flex">
<gl-form-group <gl-form-group :label="$options.i18n.numberOfUsersLabel" label-size="sm" class="number">
:label="$options.i18n.numberOfUsersLabel"
label-size="sm"
label-for="numberOfUsers"
class="number"
>
<gl-form-input <gl-form-input
id="numberOfUsers" ref="number-of-users"
v-model.number="numberOfUsersModel" v-model.number="numberOfUsersModel"
type="number" type="number"
min="0" :min="selectedGroupUsers"
:disabled="!isSetupForCompany" :disabled="!isSetupForCompany"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
v-if="!isSetupForCompany" v-if="!isSetupForCompany"
class="label prepend-left-default align-self-end company-link" ref="company-link"
class="label ml-3 align-self-end"
> >
<gl-sprintf :message="$options.i18n.needMoreUsersLink"> <gl-sprintf :message="$options.i18n.needMoreUsersLink">
<template #company> <template #company>
...@@ -145,13 +191,13 @@ export default { ...@@ -145,13 +191,13 @@ export default {
</div> </div>
</template> </template>
<template #summary> <template #summary>
<strong class="js-summary-line-1"> <strong ref="summary-line-1">
{{ selectedPlanTextLine }} {{ selectedPlanTextLine }}
</strong> </strong>
<div v-if="isSetupForCompany" class="js-summary-line-2"> <div v-if="isSetupForCompany" ref="summary-line-2">
{{ $options.i18n.group }}: {{ organizationName }} {{ $options.i18n.group }}: {{ organizationName || selectedGroupName }}
</div> </div>
<div class="js-summary-line-3">{{ $options.i18n.users }}: {{ numberOfUsers }}</div> <div ref="summary-line-3">{{ $options.i18n.users }}: {{ numberOfUsers }}</div>
</template> </template>
</step> </step>
</template> </template>
...@@ -18,3 +18,5 @@ export const PROGRESS_STEPS = { ...@@ -18,3 +18,5 @@ export const PROGRESS_STEPS = {
}; };
export const TAX_RATE = 0; export const TAX_RATE = 0;
export const NEW_GROUP = 'new_group';
...@@ -25,6 +25,12 @@ export const updateSelectedPlan = ({ commit }, selectedPlan) => { ...@@ -25,6 +25,12 @@ export const updateSelectedPlan = ({ commit }, selectedPlan) => {
commit(types.UPDATE_SELECTED_PLAN, selectedPlan); commit(types.UPDATE_SELECTED_PLAN, selectedPlan);
}; };
export const updateSelectedGroup = ({ commit, getters }, selectedGroup) => {
commit(types.UPDATE_SELECTED_GROUP, selectedGroup);
commit(types.UPDATE_ORGANIZATION_NAME, null);
commit(types.UPDATE_NUMBER_OF_USERS, getters.selectedGroupUsers);
};
export const toggleIsSetupForCompany = ({ state, commit }) => { export const toggleIsSetupForCompany = ({ state, commit }) => {
commit(types.UPDATE_IS_SETUP_FOR_COMPANY, !state.isSetupForCompany); commit(types.UPDATE_IS_SETUP_FOR_COMPANY, !state.isSetupForCompany);
}; };
......
import { STEPS } from '../constants'; import { STEPS, NEW_GROUP } from '../constants';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export const currentStep = state => state.currentStep; export const currentStep = state => state.currentStep;
...@@ -15,8 +15,10 @@ export const selectedPlanPrice = (state, getters) => ...@@ -15,8 +15,10 @@ export const selectedPlanPrice = (state, getters) =>
export const selectedPlanDetails = state => export const selectedPlanDetails = state =>
state.availablePlans.find(plan => plan.value === state.selectedPlan); state.availablePlans.find(plan => plan.value === state.selectedPlan);
export const confirmOrderParams = state => ({ export const confirmOrderParams = (state, getters) => ({
setup_for_company: state.isSetupForCompany, setup_for_company: state.isSetupForCompany,
selected_group: getters.selectedGroupId,
new_user: state.isNewUser,
customer: { customer: {
country: state.country, country: state.country,
address_1: state.streetAddressLine1, address_1: state.streetAddressLine1,
...@@ -42,10 +44,27 @@ export const vat = (state, getters) => state.taxRate * getters.totalExVat; ...@@ -42,10 +44,27 @@ export const vat = (state, getters) => state.taxRate * getters.totalExVat;
export const totalAmount = (_, getters) => getters.totalExVat + getters.vat; export const totalAmount = (_, getters) => getters.totalExVat + getters.vat;
export const name = state => { export const name = (state, getters) => {
if (state.isSetupForCompany && state.organizationName) return state.organizationName; if (state.isSetupForCompany && state.organizationName) return state.organizationName;
else if (getters.isGroupSelected) return getters.selectedGroupName;
else if (state.isSetupForCompany) return s__('Checkout|Your organization'); else if (state.isSetupForCompany) return s__('Checkout|Your organization');
return state.fullName; return state.fullName;
}; };
export const usersPresent = state => state.numberOfUsers > 0; export const usersPresent = state => state.numberOfUsers > 0;
export const isGroupSelected = state =>
state.selectedGroup !== null && state.selectedGroup !== NEW_GROUP;
export const selectedGroupUsers = (state, getters) => {
if (!getters.isGroupSelected) return 1;
return state.groupData.find(group => group.value === state.selectedGroup).numberOfUsers;
};
export const selectedGroupName = (state, getters) => {
if (!getters.isGroupSelected) return null;
return state.groupData.find(group => group.value === state.selectedGroup).text;
};
export const selectedGroupId = (state, getters) =>
getters.isGroupSelected ? state.selectedGroup : null;
...@@ -2,6 +2,8 @@ export const UPDATE_CURRENT_STEP = 'UPDATE_CURRENT_STEP'; ...@@ -2,6 +2,8 @@ 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_IS_SETUP_FOR_COMPANY = 'UPDATE_IS_SETUP_FOR_COMPANY'; export const UPDATE_IS_SETUP_FOR_COMPANY = 'UPDATE_IS_SETUP_FOR_COMPANY';
export const UPDATE_NUMBER_OF_USERS = 'UPDATE_NUMBER_OF_USERS'; export const UPDATE_NUMBER_OF_USERS = 'UPDATE_NUMBER_OF_USERS';
......
...@@ -9,6 +9,10 @@ export default { ...@@ -9,6 +9,10 @@ export default {
state.selectedPlan = selectedPlan; state.selectedPlan = selectedPlan;
}, },
[types.UPDATE_SELECTED_GROUP](state, selectedGroup) {
state.selectedGroup = selectedGroup;
},
[types.UPDATE_IS_SETUP_FOR_COMPANY](state, isSetupForCompany) { [types.UPDATE_IS_SETUP_FOR_COMPANY](state, isSetupForCompany) {
state.isSetupForCompany = isSetupForCompany; state.isSetupForCompany = isSetupForCompany;
}, },
......
...@@ -9,6 +9,13 @@ const parsePlanData = planData => ...@@ -9,6 +9,13 @@ const parsePlanData = planData =>
pricePerUserPerYear: plan.price_per_year, pricePerUserPerYear: plan.price_per_year,
})); }));
const parseGroupData = groupData =>
JSON.parse(groupData).map(group => ({
value: group.id,
text: group.name,
numberOfUsers: group.users,
}));
const determineSelectedPlan = (planId, plans) => { const determineSelectedPlan = (planId, plans) => {
if (planId && plans.find(plan => plan.value === planId)) { if (planId && plans.find(plan => plan.value === planId)) {
return planId; return planId;
...@@ -16,18 +23,28 @@ const determineSelectedPlan = (planId, plans) => { ...@@ -16,18 +23,28 @@ const determineSelectedPlan = (planId, plans) => {
return plans[0] && plans[0].value; return plans[0] && plans[0].value;
}; };
export default ({ planData = '[]', planId, setupForCompany, fullName, newUser }) => { export default ({
planData = '[]',
planId,
setupForCompany,
fullName,
newUser,
groupData = '[]',
}) => {
const availablePlans = parsePlanData(planData); const availablePlans = parsePlanData(planData);
const isNewUser = parseBoolean(newUser);
return { return {
currentStep: STEPS[0], currentStep: STEPS[0],
isSetupForCompany: parseBoolean(setupForCompany), isSetupForCompany: parseBoolean(setupForCompany) || !isNewUser,
availablePlans, availablePlans,
selectedPlan: determineSelectedPlan(planId, availablePlans), selectedPlan: determineSelectedPlan(planId, availablePlans),
newUser: parseBoolean(newUser), isNewUser,
fullName, fullName,
groupData: parseGroupData(groupData),
selectedGroup: null,
organizationName: null, organizationName: null,
numberOfUsers: parseBoolean(setupForCompany) ? 0 : 1, numberOfUsers: 1,
country: null, country: null,
streetAddressLine1: null, streetAddressLine1: null,
streetAddressLine2: null, streetAddressLine2: null,
......
...@@ -4,6 +4,7 @@ import createStore from 'ee/subscriptions/new/store'; ...@@ -4,6 +4,7 @@ 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/subscriptions/new/components/checkout/step.vue'; 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';
describe('Subscription Details', () => { describe('Subscription Details', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -17,15 +18,19 @@ describe('Subscription Details', () => { ...@@ -17,15 +18,19 @@ describe('Subscription Details', () => {
{ id: 'secondPlanId', code: 'silver', price_per_year: 228 }, { id: 'secondPlanId', code: 'silver', price_per_year: 228 },
]; ];
const groupData = [
{ id: 132, name: 'My first group', users: 3 },
{ id: 483, name: 'My second group', users: 12 },
];
const initialData = { const initialData = {
planData: JSON.stringify(planData), planData: JSON.stringify(planData),
groupData: JSON.stringify(groupData),
planId: 'secondPlanId', planId: 'secondPlanId',
setupForCompany: 'true', setupForCompany: 'true',
fullName: 'Full Name', fullName: 'Full Name',
}; };
const isStepValid = () => wrapper.find(Step).props('isValid');
const createComponent = () => { const createComponent = () => {
wrapper = mount(Component, { wrapper = mount(Component, {
localVue, localVue,
...@@ -33,6 +38,11 @@ describe('Subscription Details', () => { ...@@ -33,6 +38,11 @@ describe('Subscription Details', () => {
}); });
}; };
const organizationNameInput = () => wrapper.find({ ref: 'organization-name' });
const groupSelect = () => wrapper.find({ ref: 'group-select' });
const numberOfUsersInput = () => wrapper.find({ ref: 'number-of-users' });
const companyLink = () => wrapper.find({ ref: 'company-link' });
beforeEach(() => { beforeEach(() => {
store = createStore(initialData); store = createStore(initialData);
createComponent(); createComponent();
...@@ -42,58 +52,226 @@ describe('Subscription Details', () => { ...@@ -42,58 +52,226 @@ describe('Subscription Details', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('Setting up for personal use', () => { describe('A new user setting up for personal use', () => {
beforeEach(() => { beforeEach(() => {
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, false); store.state.isNewUser = true;
store.commit(types.UPDATE_NUMBER_OF_USERS, 1); store.state.isSetupForCompany = false;
}); });
it('should be valid', () => { it('should not display an input field for the company or group name', () => {
expect(isStepValid()).toBe(true); expect(organizationNameInput().exists()).toBe(false);
}); });
it('should not display an input field for the company or group name', () => { it('should not display the group select', () => {
expect(wrapper.find('#organizationName').exists()).toBe(false); expect(groupSelect().exists()).toBe(false);
}); });
it('should disable the number of users input field', () => { it('should disable the number of users input field', () => {
expect(wrapper.find('#numberOfUsers').attributes('disabled')).toBeDefined(); expect(numberOfUsersInput().attributes('disabled')).toBeDefined();
});
it('should set the min number of users to 1', () => {
expect(numberOfUsersInput().attributes('min')).toBe('1');
}); });
it('should show a link to change to setting up for a company', () => { it('should show a link to change to setting up for a company', () => {
expect(wrapper.find('.company-link').exists()).toBe(true); expect(companyLink().exists()).toBe(true);
}); });
}); });
describe('Setting up for a company or group', () => { describe('A new user setting up for a company or group', () => {
beforeEach(() => { beforeEach(() => {
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, true); store.state.isNewUser = true;
store.commit(types.UPDATE_NUMBER_OF_USERS, 0); store.state.groupData = [];
});
it('should display an input field for the company or group name', () => {
expect(organizationNameInput().exists()).toBe(true);
}); });
it('should be invalid', () => { it('should not display the group select', () => {
expect(isStepValid()).toBe(false); expect(groupSelect().exists()).toBe(false);
});
it('should enable the number of users input field', () => {
expect(numberOfUsersInput().attributes('disabled')).toBeUndefined();
});
it('should set the min number of users to 1', () => {
expect(numberOfUsersInput().attributes('min')).toBe('1');
});
it('should not show a link to change to setting up for a company', () => {
expect(companyLink().exists()).toBe(false);
});
});
describe('An existing user without any groups', () => {
beforeEach(() => {
store.state.isNewUser = false;
store.state.groupData = [];
}); });
it('should display an input field for the company or group name', () => { it('should display an input field for the company or group name', () => {
expect(wrapper.find('#organizationName').exists()).toBe(true); expect(organizationNameInput().exists()).toBe(true);
});
it('should not display the group select', () => {
expect(groupSelect().exists()).toBe(false);
}); });
it('should enable the number of users input field', () => { it('should enable the number of users input field', () => {
expect(wrapper.find('#numberOfUsers').attributes('disabled')).toBeUndefined(); expect(numberOfUsersInput().attributes('disabled')).toBeUndefined();
}); });
it('should not show the link to change to setting up for a company', () => { it('should set the min number of users to 1', () => {
expect(wrapper.find('.company-link').exists()).toBe(false); expect(numberOfUsersInput().attributes('min')).toBe('1');
});
it('should not show a link to change to setting up for a company', () => {
expect(companyLink().exists()).toBe(false);
});
});
describe('An existing user with groups', () => {
beforeEach(() => {
store.state.isNewUser = false;
});
it('should not display an input field for the company or group name', () => {
expect(organizationNameInput().exists()).toBe(false);
});
it('should display the group select', () => {
expect(groupSelect().exists()).toBe(true);
});
it('should enable the number of users input field', () => {
expect(numberOfUsersInput().attributes('disabled')).toBeUndefined();
});
it('should set the min number of users to 1', () => {
expect(numberOfUsersInput().attributes('min')).toBe('1');
});
it('should not show a link to change to setting up for a company', () => {
expect(companyLink().exists()).toBe(false);
});
describe('selecting an existing group', () => {
beforeEach(() => {
store.commit(types.UPDATE_SELECTED_GROUP, 483);
});
it('should display the correct description', () => {
expect(wrapper.text()).toContain('Your subscription will be applied to this group');
});
it('should set the min number of users to 12', () => {
expect(numberOfUsersInput().attributes('min')).toBe('12');
});
}); });
describe('filling in the company name and the number of users', () => { describe('selecting "Create a new group', () => {
it('should make the component valid', () => { beforeEach(() => {
store.commit(types.UPDATE_ORGANIZATION_NAME, 'My Organization'); store.commit(types.UPDATE_SELECTED_GROUP, NEW_GROUP);
});
it('should display the correct description', () => {
expect(wrapper.text()).toContain("You'll create your new group after checkout");
});
it('should display an input field for the company or group name', () => {
expect(organizationNameInput().exists()).toBe(true);
});
it('should set the min number of users to 1', () => {
expect(numberOfUsersInput().attributes('min')).toBe('1');
});
});
});
describe('validations', () => {
const isStepValid = () => wrapper.find(Step).props('isValid');
describe('when setting up for a company', () => {
beforeEach(() => {
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, true);
store.commit(types.UPDATE_SELECTED_PLAN, 'firstPlanId');
store.commit(types.UPDATE_ORGANIZATION_NAME, 'Organization name');
store.commit(types.UPDATE_SELECTED_GROUP, 483);
store.commit(types.UPDATE_NUMBER_OF_USERS, 14);
});
it('should be valid', () => {
expect(isStepValid()).toBe(true);
});
it('should be invalid when no plan is selected', () => {
store.commit(types.UPDATE_SELECTED_PLAN, null);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
it('should be invalid when no organization name is given, and no group is selected', () => {
store.commit(types.UPDATE_ORGANIZATION_NAME, null);
store.commit(types.UPDATE_SELECTED_GROUP, null);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
it('should be invalid when number of users is 0', () => {
store.commit(types.UPDATE_NUMBER_OF_USERS, 0);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
it('should be invalid when number of users is smaller than the selected group users', () => {
store.commit(types.UPDATE_NUMBER_OF_USERS, 10);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
});
describe('when not setting up for a company', () => {
beforeEach(() => {
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, false);
store.commit(types.UPDATE_NUMBER_OF_USERS, 1);
});
it('should be valid', () => {
expect(isStepValid()).toBe(true);
});
it('should be invalid when no plan is selected', () => {
store.commit(types.UPDATE_SELECTED_PLAN, null);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
it('should be invalid when no number of users is 0', () => {
store.commit(types.UPDATE_NUMBER_OF_USERS, 0);
return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(false);
});
});
it('should be invalid when no number of users is greater than 1', () => {
store.commit(types.UPDATE_NUMBER_OF_USERS, 2); store.commit(types.UPDATE_NUMBER_OF_USERS, 2);
return wrapper.vm.$nextTick().then(() => { return localVue.nextTick().then(() => {
expect(isStepValid()).toBe(true); expect(isStepValid()).toBe(false);
}); });
}); });
}); });
...@@ -109,15 +287,25 @@ describe('Subscription Details', () => { ...@@ -109,15 +287,25 @@ describe('Subscription Details', () => {
}); });
it('should show the selected plan', () => { it('should show the selected plan', () => {
expect(wrapper.find('.js-summary-line-1').text()).toEqual('Bronze plan'); expect(wrapper.find({ ref: 'summary-line-1' }).text()).toEqual('Bronze plan');
}); });
it('should show the entered group name', () => { it('should show the entered group name', () => {
expect(wrapper.find('.js-summary-line-2').text()).toEqual('Group: My Organization'); expect(wrapper.find({ ref: 'summary-line-2' }).text()).toEqual('Group: My Organization');
}); });
it('should show the entered number of users', () => { it('should show the entered number of users', () => {
expect(wrapper.find('.js-summary-line-3').text()).toEqual('Users: 25'); expect(wrapper.find({ ref: 'summary-line-3' }).text()).toEqual('Users: 25');
});
describe('selecting an existing group', () => {
beforeEach(() => {
store.commit(types.UPDATE_SELECTED_GROUP, 483);
});
it('should show the selected group name', () => {
expect(wrapper.find({ ref: 'summary-line-2' }).text()).toEqual('Group: My second group');
});
}); });
}); });
}); });
...@@ -28,9 +28,9 @@ describe('Checkout', () => { ...@@ -28,9 +28,9 @@ describe('Checkout', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe.each([[true, true], [false, false]])('when newUser=%s', (newUser, visible) => { describe.each([[true, true], [false, false]])('when isNewUser=%s', (isNewUser, visible) => {
beforeEach(() => { beforeEach(() => {
store.state.newUser = newUser; store.state.isNewUser = isNewUser;
}); });
it(`progress bar visibility is ${visible}`, () => { it(`progress bar visibility is ${visible}`, () => {
......
...@@ -77,6 +77,23 @@ describe('Subscriptions Actions', () => { ...@@ -77,6 +77,23 @@ describe('Subscriptions Actions', () => {
}); });
}); });
describe('updateSelectedGroup', () => {
it('updates the selected group, resets the organization name and updates the number of users', done => {
testAction(
actions.updateSelectedGroup,
'groupId',
{ selectedGroupUsers: 3 },
[
{ type: 'UPDATE_SELECTED_GROUP', payload: 'groupId' },
{ type: 'UPDATE_ORGANIZATION_NAME', payload: null },
{ type: 'UPDATE_NUMBER_OF_USERS', payload: 3 },
],
[],
done,
);
});
});
describe('toggleIsSetupForCompany', () => { describe('toggleIsSetupForCompany', () => {
it('toggles the isSetupForCompany value', done => { it('toggles the isSetupForCompany value', done => {
testAction( testAction(
......
...@@ -6,6 +6,7 @@ constants.STEPS = ['firstStep', 'secondStep']; ...@@ -6,6 +6,7 @@ constants.STEPS = ['firstStep', 'secondStep'];
const state = { const state = {
currentStep: 'secondStep', currentStep: 'secondStep',
isSetupForCompany: true, isSetupForCompany: true,
isNewUser: true,
availablePlans: [ availablePlans: [
{ {
value: 'firstPlan', value: 'firstPlan',
...@@ -99,17 +100,30 @@ describe('Subscriptions Getters', () => { ...@@ -99,17 +100,30 @@ describe('Subscriptions Getters', () => {
describe('name', () => { describe('name', () => {
it('returns the organization name when setting up for a company and when it is present', () => { it('returns the organization name when setting up for a company and when it is present', () => {
expect(getters.name({ isSetupForCompany: true, organizationName: 'My organization' })).toBe( expect(
'My organization', getters.name({ isSetupForCompany: true, organizationName: 'My organization' }, getters),
); ).toBe('My organization');
});
it('returns the selected group name a group is selected', () => {
expect(
getters.name(
{ isSetupForCompany: true },
{ isGroupSelected: true, selectedGroupName: 'Selected group' },
),
).toBe('Selected group');
}); });
it('returns the default text when setting up for a company and the organization name is not present', () => { it('returns the default text when setting up for a company and the organization name is not present', () => {
expect(getters.name({ isSetupForCompany: true })).toBe('Your organization'); expect(getters.name({ isSetupForCompany: true }, { isGroupSelected: false })).toBe(
'Your organization',
);
}); });
it('returns the full name when not setting up for a company', () => { it('returns the full name when not setting up for a company', () => {
expect(getters.name({ isSetupForCompany: false, fullName: 'My name' })).toBe('My name'); expect(
getters.name({ isSetupForCompany: false, fullName: 'My name' }, { isGroupSelected: false }),
).toBe('My name');
}); });
}); });
...@@ -123,10 +137,78 @@ describe('Subscriptions Getters', () => { ...@@ -123,10 +137,78 @@ describe('Subscriptions Getters', () => {
}); });
}); });
describe('isGroupSelected', () => {
it('returns true when the selectedGroup is not null and does not equal "true"', () => {
expect(getters.isGroupSelected({ selectedGroup: 1 })).toBe(true);
});
it('returns false when the selectedGroup is null', () => {
expect(getters.isGroupSelected({ selectedGroup: null })).toBe(false);
});
it('returns false when the selectedGroup equals "new"', () => {
expect(getters.isGroupSelected({ selectedGroup: constants.NEW_GROUP })).toBe(false);
});
});
describe('selectedGroupUsers', () => {
it('returns 1 when no group is selected', () => {
expect(
getters.selectedGroupUsers(
{ groupData: [{ numberOfUsers: 3, value: 123 }], selectedGroup: 123 },
{ isGroupSelected: false },
),
).toBe(1);
});
it('returns the number of users of the selected group when a group is selected', () => {
expect(
getters.selectedGroupUsers(
{ groupData: [{ numberOfUsers: 3, value: 123 }], selectedGroup: 123 },
{ isGroupSelected: true },
),
).toBe(3);
});
});
describe('selectedGroupName', () => {
it('returns null when no group is selected', () => {
expect(
getters.selectedGroupName(
{ groupData: [{ text: 'Selected group', value: 123 }], selectedGroup: 123 },
{ isGroupSelected: false },
),
).toBe(null);
});
it('returns the text attribute of the selected group when a group is selected', () => {
expect(
getters.selectedGroupName(
{ groupData: [{ text: 'Selected group', value: 123 }], selectedGroup: 123 },
{ isGroupSelected: true },
),
).toBe('Selected group');
});
});
describe('selectedGroupId', () => {
it('returns null when no group is selected', () => {
expect(getters.selectedGroupId({ selectedGroup: 123 }, { isGroupSelected: false })).toBe(
null,
);
});
it('returns the id of the selected group when a group is selected', () => {
expect(getters.selectedGroupId({ selectedGroup: 123 }, { isGroupSelected: true })).toBe(123);
});
});
describe('confirmOrderParams', () => { describe('confirmOrderParams', () => {
it('returns the params to confirm the order', () => { it('returns the params to confirm the order', () => {
expect(getters.confirmOrderParams(state)).toEqual({ expect(getters.confirmOrderParams(state, { selectedGroupId: 11 })).toEqual({
setup_for_company: true, setup_for_company: true,
selected_group: 11,
new_user: true,
customer: { customer: {
country: 'Country', country: 'Country',
address_1: 'Street address line 1', address_1: 'Street address line 1',
......
...@@ -24,6 +24,7 @@ describe('ee/subscriptions/new/store/mutation', () => { ...@@ -24,6 +24,7 @@ describe('ee/subscriptions/new/store/mutation', () => {
mutation | value | stateProp mutation | value | stateProp
${types.UPDATE_CURRENT_STEP} | ${'secondStep'} | ${'currentStep'} ${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_IS_SETUP_FOR_COMPANY} | ${false} | ${'isSetupForCompany'} ${types.UPDATE_IS_SETUP_FOR_COMPANY} | ${false} | ${'isSetupForCompany'}
${types.UPDATE_NUMBER_OF_USERS} | ${2} | ${'numberOfUsers'} ${types.UPDATE_NUMBER_OF_USERS} | ${2} | ${'numberOfUsers'}
${types.UPDATE_ORGANIZATION_NAME} | ${'new name'} | ${'organizationName'} ${types.UPDATE_ORGANIZATION_NAME} | ${'new name'} | ${'organizationName'}
......
...@@ -10,11 +10,18 @@ describe('projectsSelector default state', () => { ...@@ -10,11 +10,18 @@ describe('projectsSelector default state', () => {
{ id: 'secondPlanId', code: 'silver', price_per_year: 228 }, { id: 'secondPlanId', code: 'silver', price_per_year: 228 },
]; ];
const groupData = [
{ id: 132, name: 'My first group', users: 3 },
{ id: 483, name: 'My second group', users: 12 },
];
const initialData = { const initialData = {
planData: JSON.stringify(planData), planData: JSON.stringify(planData),
groupData: JSON.stringify(groupData),
planId: 'secondPlanId', planId: 'secondPlanId',
setupForCompany: 'true', setupForCompany: 'true',
fullName: 'Full Name', fullName: 'Full Name',
newUser: 'true',
}; };
const currentDate = new Date('2020-01-07T12:44:08.135Z'); const currentDate = new Date('2020-01-07T12:44:08.135Z');
...@@ -67,12 +74,24 @@ describe('projectsSelector default state', () => { ...@@ -67,12 +74,24 @@ describe('projectsSelector default state', () => {
}); });
describe('isSetupForCompany', () => { describe('isSetupForCompany', () => {
it('sets the isSetupForCompany to true if provided setupForCompany is "true"', () => { it('sets the isSetupForCompany to true if provided setupForCompany is "true" and the provided newUser is "true"', () => {
expect(state.isSetupForCompany).toEqual(true); expect(state.isSetupForCompany).toEqual(true);
}); });
it('sets the isSetupForCompany to true if provided newUser is "false"', () => {
const modifiedState = createState({
...initialData,
...{ newUser: 'false' },
});
expect(modifiedState.isSetupForCompany).toEqual(true);
});
it('sets the isSetupForCompany to false if provided setupForCompany is "false"', () => { it('sets the isSetupForCompany to false if provided setupForCompany is "false"', () => {
const modifiedState = createState({ ...initialData, ...{ setupForCompany: 'false' } }); const modifiedState = createState({
...initialData,
...{ setupForCompany: 'false' },
});
expect(modifiedState.isSetupForCompany).toEqual(false); expect(modifiedState.isSetupForCompany).toEqual(false);
}); });
...@@ -82,22 +101,33 @@ describe('projectsSelector default state', () => { ...@@ -82,22 +101,33 @@ describe('projectsSelector default state', () => {
expect(state.fullName).toEqual('Full Name'); expect(state.fullName).toEqual('Full Name');
}); });
it('sets the organizationName to null', () => { describe('groupData', () => {
expect(state.organizationName).toBeNull(); it('sets the groupData to the provided parsed groupData', () => {
}); expect(state.groupData).toEqual([
{ value: 132, text: 'My first group', numberOfUsers: 3 },
describe('numberOfUsers', () => { { value: 483, text: 'My second group', numberOfUsers: 12 },
it('sets the numberOfUsers to 0 when setupForCompany is true', () => { ]);
expect(state.numberOfUsers).toEqual(0);
}); });
it('sets the numberOfUsers to 1 when setupForCompany is false', () => { it('sets the availablePlans to an empty array when no groupData is provided', () => {
const modifiedState = createState({ ...initialData, ...{ setupForCompany: 'false' } }); const modifiedState = createState({ ...initialData, ...{ groupData: undefined } });
expect(modifiedState.numberOfUsers).toEqual(1); expect(modifiedState.groupData).toEqual([]);
}); });
}); });
it('sets the selectedGroup to null', () => {
expect(state.selectedGroup).toBeNull();
});
it('sets the organizationName to null', () => {
expect(state.organizationName).toBeNull();
});
it('sets the numberOfUsers to 1', () => {
expect(state.numberOfUsers).toEqual(1);
});
it('sets the country to null', () => { it('sets the country to null', () => {
expect(state.country).toBeNull(); expect(state.country).toBeNull();
}); });
......
...@@ -3480,6 +3480,9 @@ msgstr "" ...@@ -3480,6 +3480,9 @@ msgstr ""
msgid "Checkout|Country" msgid "Checkout|Country"
msgstr "" msgstr ""
msgid "Checkout|Create a new group"
msgstr ""
msgid "Checkout|Credit card form failed to load. Please try again." msgid "Checkout|Credit card form failed to load. Please try again."
msgstr "" msgstr ""
...@@ -3507,6 +3510,9 @@ msgstr "" ...@@ -3507,6 +3510,9 @@ msgstr ""
msgid "Checkout|Failed to register credit card. Please try again." msgid "Checkout|Failed to register credit card. Please try again."
msgstr "" msgstr ""
msgid "Checkout|GitLab group"
msgstr ""
msgid "Checkout|GitLab plan" msgid "Checkout|GitLab plan"
msgstr "" msgstr ""
...@@ -3531,6 +3537,9 @@ msgstr "" ...@@ -3531,6 +3537,9 @@ msgstr ""
msgid "Checkout|Please select a state" msgid "Checkout|Please select a state"
msgstr "" msgstr ""
msgid "Checkout|Select"
msgstr ""
msgid "Checkout|State" msgid "Checkout|State"
msgstr "" msgstr ""
...@@ -3555,9 +3564,15 @@ msgstr "" ...@@ -3555,9 +3564,15 @@ msgstr ""
msgid "Checkout|Users" msgid "Checkout|Users"
msgstr "" msgstr ""
msgid "Checkout|You'll create your new group after checkout"
msgstr ""
msgid "Checkout|Your organization" msgid "Checkout|Your organization"
msgstr "" msgstr ""
msgid "Checkout|Your subscription will be applied to this group"
msgstr ""
msgid "Checkout|Zip code" msgid "Checkout|Zip code"
msgstr "" msgstr ""
......
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