Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
0b90af66
Commit
0b90af66
authored
Apr 07, 2021
by
Michael Lunøe
Committed by
Vitaly Slobodin
Apr 07, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re: Feat(Purchase Flow): migrate step components to use GraphQL
parent
c6963498
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
441 additions
and
207 deletions
+441
-207
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
.../javascripts/subscriptions/buy_minutes/components/app.vue
+1
-1
ee/app/assets/javascripts/subscriptions/new/components/app.vue
...p/assets/javascripts/subscriptions/new/components/app.vue
+1
-1
ee/app/assets/javascripts/subscriptions/new/components/checkout/billing_address.vue
...subscriptions/new/components/checkout/billing_address.vue
+4
-2
ee/app/assets/javascripts/subscriptions/new/components/checkout/confirm_order.vue
...s/subscriptions/new/components/checkout/confirm_order.vue
+14
-5
ee/app/assets/javascripts/subscriptions/new/components/checkout/payment_method.vue
.../subscriptions/new/components/checkout/payment_method.vue
+4
-2
ee/app/assets/javascripts/subscriptions/new/components/checkout/subscription_details.vue
...riptions/new/components/checkout/subscription_details.vue
+4
-3
ee/app/assets/javascripts/subscriptions/new/constants.js
ee/app/assets/javascripts/subscriptions/new/constants.js
+8
-1
ee/app/assets/javascripts/subscriptions/new/graphql.js
ee/app/assets/javascripts/subscriptions/new/graphql.js
+31
-0
ee/app/assets/javascripts/subscriptions/new/index.js
ee/app/assets/javascripts/subscriptions/new/index.js
+9
-0
ee/app/assets/javascripts/subscriptions/new/store/actions.js
ee/app/assets/javascripts/subscriptions/new/store/actions.js
+7
-19
ee/app/assets/javascripts/subscriptions/new/store/getters.js
ee/app/assets/javascripts/subscriptions/new/store/getters.js
+1
-7
ee/app/assets/javascripts/subscriptions/new/store/mutation_types.js
...ets/javascripts/subscriptions/new/store/mutation_types.js
+0
-2
ee/app/assets/javascripts/subscriptions/new/store/mutations.js
...p/assets/javascripts/subscriptions/new/store/mutations.js
+0
-4
ee/app/assets/javascripts/subscriptions/new/store/state.js
ee/app/assets/javascripts/subscriptions/new/store/state.js
+1
-2
ee/app/assets/javascripts/vue_shared/purchase_flow/components/step.vue
.../javascripts/vue_shared/purchase_flow/components/step.vue
+46
-12
ee/app/assets/javascripts/vue_shared/purchase_flow/components/step_header.vue
...ripts/vue_shared/purchase_flow/components/step_header.vue
+0
-0
ee/app/assets/javascripts/vue_shared/purchase_flow/components/step_order_app.vue
...ts/vue_shared/purchase_flow/components/step_order_app.vue
+0
-0
ee/app/assets/javascripts/vue_shared/purchase_flow/components/step_summary.vue
...ipts/vue_shared/purchase_flow/components/step_summary.vue
+0
-0
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
+1
-1
ee/spec/frontend/subscriptions/new/components/checkout/billing_address_spec.js
...criptions/new/components/checkout/billing_address_spec.js
+32
-13
ee/spec/frontend/subscriptions/new/components/checkout/confirm_order_spec.js
...bscriptions/new/components/checkout/confirm_order_spec.js
+24
-11
ee/spec/frontend/subscriptions/new/components/checkout/payment_method_spec.js
...scriptions/new/components/checkout/payment_method_spec.js
+12
-7
ee/spec/frontend/subscriptions/new/components/checkout/subscription_details_spec.js
...ions/new/components/checkout/subscription_details_spec.js
+63
-35
ee/spec/frontend/subscriptions/new/store/actions_spec.js
ee/spec/frontend/subscriptions/new/store/actions_spec.js
+12
-40
ee/spec/frontend/subscriptions/new/store/getters_spec.js
ee/spec/frontend/subscriptions/new/store/getters_spec.js
+0
-32
ee/spec/frontend/subscriptions/new/store/mutations_spec.js
ee/spec/frontend/subscriptions/new/store/mutations_spec.js
+0
-2
ee/spec/frontend/subscriptions/new/store/state_spec.js
ee/spec/frontend/subscriptions/new/store/state_spec.js
+0
-5
ee/spec/frontend/vue_shared/purchase_flow/components/step_spec.js
...frontend/vue_shared/purchase_flow/components/step_spec.js
+148
-0
ee/spec/frontend/vue_shared/purchase_flow/spec_helper.js
ee/spec/frontend/vue_shared/purchase_flow/spec_helper.js
+18
-0
No files found.
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
View file @
0b90af66
<
script
>
import
StepOrderApp
from
'
ee/vue_shared/components/step_order_app.vue
'
;
import
StepOrderApp
from
'
ee/vue_shared/
purchase_flow/
components/step_order_app.vue
'
;
export
default
{
components
:
{
...
...
ee/app/assets/javascripts/subscriptions/new/components/app.vue
View file @
0b90af66
<
script
>
import
StepOrderApp
from
'
ee/vue_shared/components/step_order_app.vue
'
;
import
StepOrderApp
from
'
ee/vue_shared/
purchase_flow/
components/step_order_app.vue
'
;
import
Checkout
from
'
./checkout.vue
'
;
import
OrderSummary
from
'
./order_summary.vue
'
;
...
...
ee/app/assets/javascripts/subscriptions/new/components/checkout/billing_address.vue
View file @
0b90af66
...
...
@@ -2,9 +2,10 @@
import
{
GlFormGroup
,
GlFormInput
,
GlFormSelect
}
from
'
@gitlab/ui
'
;
import
{
isEmpty
}
from
'
lodash
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
{
s__
}
from
'
~/locale
'
;
import
autofocusonshow
from
'
~/vue_shared/directives/autofocusonshow
'
;
import
Step
from
'
./step.vue
'
;
import
{
STEPS
}
from
'
../../constants
'
;
export
default
{
components
:
{
...
...
@@ -128,11 +129,12 @@ export default {
stateSelectPrompt
:
s__
(
'
Checkout|Please select a state
'
),
zipCodeLabel
:
s__
(
'
Checkout|Zip code
'
),
},
stepId
:
STEPS
[
1
].
id
,
};
</
script
>
<
template
>
<step
step=
"billingAddress
"
:step-id=
"$options.stepId
"
:title=
"$options.i18n.stepTitle"
:is-valid=
"isValid"
:next-step-button-text=
"$options.i18n.nextStepButtonText"
...
...
ee/app/assets/javascripts/subscriptions/new/components/checkout/confirm_order.vue
View file @
0b90af66
<
script
>
import
{
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
mapState
,
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
activeStepQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql
'
;
import
{
s__
}
from
'
~/locale
'
;
import
{
STEPS
}
from
'
../../constants
'
;
export
default
{
components
:
{
GlButton
,
GlLoadingIcon
,
},
data
()
{
return
{
isActive
:
{},
};
},
apollo
:
{
isActive
:
{
query
:
activeStepQuery
,
update
:
({
activeStep
})
=>
activeStep
.
id
===
STEPS
[
3
].
id
,
},
},
computed
:
{
...
mapState
([
'
isConfirmingOrder
'
]),
...
mapGetters
([
'
currentStep
'
]),
isActive
()
{
return
this
.
currentStep
===
'
confirmOrder
'
;
},
},
methods
:
{
...
mapActions
([
'
confirmOrder
'
]),
...
...
ee/app/assets/javascripts/subscriptions/new/components/checkout/payment_method.vue
View file @
0b90af66
<
script
>
import
{
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
mapState
}
from
'
vuex
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
{
sprintf
,
s__
}
from
'
~/locale
'
;
import
Step
from
'
./step.vue
'
;
import
{
STEPS
}
from
'
../../constants
'
;
import
Zuora
from
'
./zuora.vue
'
;
export
default
{
...
...
@@ -28,10 +29,11 @@ export default {
creditCardDetails
:
s__
(
'
Checkout|%{cardType} ending in %{lastFourDigits}
'
),
expirationDate
:
s__
(
'
Checkout|Exp %{expirationMonth}/%{expirationYear}
'
),
},
stepId
:
STEPS
[
2
].
id
,
};
</
script
>
<
template
>
<step
step=
"paymentMetho
d"
:title=
"$options.i18n.stepTitle"
:is-valid=
"isValid"
>
<step
:step-id=
"$options.stepI
d"
:title=
"$options.i18n.stepTitle"
:is-valid=
"isValid"
>
<template
#body
="
props
"
>
<zuora
:active=
"props.active"
/>
</
template
>
...
...
ee/app/assets/javascripts/subscriptions/new/components/checkout/subscription_details.vue
View file @
0b90af66
...
...
@@ -2,10 +2,10 @@
import
{
GlFormGroup
,
GlFormSelect
,
GlFormInput
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
isEmpty
}
from
'
lodash
'
;
import
{
mapState
,
mapGetters
,
mapActions
}
from
'
vuex
'
;
import
{
NEW_GROUP
}
from
'
ee/subscriptions/new/constants
'
;
import
{
NEW_GROUP
,
STEPS
}
from
'
ee/subscriptions/new/constants
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
{
sprintf
,
s__
}
from
'
~/locale
'
;
import
autofocusonshow
from
'
~/vue_shared/directives/autofocusonshow
'
;
import
Step
from
'
./step.vue
'
;
export
default
{
components
:
{
...
...
@@ -133,11 +133,12 @@ export default {
group
:
s__
(
'
Checkout|Group
'
),
users
:
s__
(
'
Checkout|Users
'
),
},
stepId
:
STEPS
[
0
].
id
,
};
</
script
>
<
template
>
<step
step=
"subscriptionDetails
"
:step-id=
"$options.stepId
"
:title=
"$options.i18n.stepTitle"
:is-valid=
"isValid"
:next-step-button-text=
"$options.i18n.nextStepButtonText"
...
...
ee/app/assets/javascripts/subscriptions/new/constants.js
View file @
0b90af66
// The order of the steps in this array determines the flow of the application
export
const
STEPS
=
[
'
subscriptionDetails
'
,
'
billingAddress
'
,
'
paymentMethod
'
,
'
confirmOrder
'
];
/* eslint-disable @gitlab/require-i18n-strings */
export
const
STEPS
=
[
{
id
:
'
subscriptionDetails
'
,
__typename
:
'
Step
'
},
{
id
:
'
billingAddress
'
,
__typename
:
'
Step
'
},
{
id
:
'
paymentMethod
'
,
__typename
:
'
Step
'
},
{
id
:
'
confirmOrder
'
,
__typename
:
'
Step
'
},
];
/* eslint-enable @gitlab/require-i18n-strings */
export
const
ZUORA_SCRIPT_URL
=
'
https://static.zuora.com/Resources/libs/hosted/1.3.1/zuora-min.js
'
;
...
...
ee/app/assets/javascripts/subscriptions/new/graphql.js
0 → 100644
View file @
0b90af66
import
activeStepQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql
'
;
import
stepListQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql
'
;
import
resolvers
from
'
ee/vue_shared/purchase_flow/graphql/resolvers
'
;
import
typeDefs
from
'
ee/vue_shared/purchase_flow/graphql/typedefs.graphql
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
{
STEPS
}
from
'
./constants
'
;
function
createClient
(
stepList
)
{
const
client
=
createDefaultClient
(
resolvers
,
{
typeDefs
,
assumeImmutableResults
:
true
,
});
client
.
cache
.
writeQuery
({
query
:
stepListQuery
,
data
:
{
stepList
,
},
});
client
.
cache
.
writeQuery
({
query
:
activeStepQuery
,
data
:
{
activeStep
:
stepList
[
0
],
},
});
return
client
;
}
export
default
createClient
(
STEPS
);
ee/app/assets/javascripts/subscriptions/new/index.js
View file @
0b90af66
import
Vue
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
App
from
'
./components/app.vue
'
;
import
defaultClient
from
'
./graphql
'
;
import
createStore
from
'
./store
'
;
Vue
.
use
(
VueApollo
);
const
apolloProvider
=
new
VueApollo
({
defaultClient
,
});
export
default
()
=>
{
const
el
=
document
.
getElementById
(
'
js-new-subscription
'
);
const
store
=
createStore
(
el
.
dataset
);
...
...
@@ -9,6 +17,7 @@ export default () => {
return
new
Vue
({
el
,
store
,
apolloProvider
,
components
:
{
App
,
},
...
...
ee/app/assets/javascripts/subscriptions/new/store/actions.js
View file @
0b90af66
import
Api
from
'
ee/api
'
;
import
activateNextStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql
'
;
import
createFlash
from
'
~/flash
'
;
import
{
redirectTo
}
from
'
~/lib/utils/url_utility
'
;
import
{
sprintf
,
s__
}
from
'
~/locale
'
;
import
{
STEPS
,
PAYMENT_FORM_ID
}
from
'
../constants
'
;
import
{
PAYMENT_FORM_ID
}
from
'
../constants
'
;
import
defaultClient
from
'
../graphql
'
;
import
*
as
types
from
'
./mutation_types
'
;
export
const
activateStep
=
({
commit
},
currentStep
)
=>
{
if
(
STEPS
.
includes
(
currentStep
))
{
commit
(
types
.
UPDATE_CURRENT_STEP
,
currentStep
);
}
};
export
const
activateNextStep
=
({
commit
,
getters
})
=>
{
const
{
currentStepIndex
}
=
getters
;
if
(
currentStepIndex
<
STEPS
.
length
-
1
)
{
const
nextStep
=
STEPS
[
currentStepIndex
+
1
];
commit
(
types
.
UPDATE_CURRENT_STEP
,
nextStep
);
}
};
export
const
updateSelectedPlan
=
({
commit
},
selectedPlan
)
=>
{
commit
(
types
.
UPDATE_SELECTED_PLAN
,
selectedPlan
);
};
...
...
@@ -180,10 +166,12 @@ export const fetchPaymentMethodDetails = ({ state, dispatch, commit }) =>
.
catch
(()
=>
dispatch
(
'
fetchPaymentMethodDetailsError
'
))
.
finally
(()
=>
commit
(
types
.
UPDATE_IS_LOADING_PAYMENT_METHOD
,
false
));
export
const
fetchPaymentMethodDetailsSuccess
=
({
commit
,
dispatch
},
creditCardDetails
)
=>
{
export
const
fetchPaymentMethodDetailsSuccess
=
({
commit
},
creditCardDetails
)
=>
{
commit
(
types
.
UPDATE_CREDIT_CARD_DETAILS
,
creditCardDetails
);
dispatch
(
'
activateNextStep
'
);
defaultClient
.
mutate
({
mutation
:
activateNextStepMutation
,
});
};
export
const
fetchPaymentMethodDetailsError
=
()
=>
{
...
...
ee/app/assets/javascripts/subscriptions/new/store/getters.js
View file @
0b90af66
import
{
s__
}
from
'
~/locale
'
;
import
{
STEPS
,
NEW_GROUP
}
from
'
../constants
'
;
export
const
currentStep
=
(
state
)
=>
state
.
currentStep
;
export
const
stepIndex
=
()
=>
(
step
)
=>
STEPS
.
findIndex
((
el
)
=>
el
===
step
);
export
const
currentStepIndex
=
(
state
,
getters
)
=>
getters
.
stepIndex
(
state
.
currentStep
);
import
{
NEW_GROUP
}
from
'
../constants
'
;
export
const
selectedPlanText
=
(
state
,
getters
)
=>
getters
.
selectedPlanDetails
.
text
;
...
...
ee/app/assets/javascripts/subscriptions/new/store/mutation_types.js
View file @
0b90af66
export
const
UPDATE_CURRENT_STEP
=
'
UPDATE_CURRENT_STEP
'
;
export
const
UPDATE_SELECTED_PLAN
=
'
UPDATE_SELECTED_PLAN
'
;
export
const
UPDATE_SELECTED_GROUP
=
'
UPDATE_SELECTED_GROUP
'
;
...
...
ee/app/assets/javascripts/subscriptions/new/store/mutations.js
View file @
0b90af66
import
*
as
types
from
'
./mutation_types
'
;
export
default
{
[
types
.
UPDATE_CURRENT_STEP
](
state
,
currentStep
)
{
state
.
currentStep
=
currentStep
;
},
[
types
.
UPDATE_SELECTED_PLAN
](
state
,
selectedPlan
)
{
state
.
selectedPlan
=
selectedPlan
;
},
...
...
ee/app/assets/javascripts/subscriptions/new/store/state.js
View file @
0b90af66
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
{
capitalizeFirstCharacter
}
from
'
~/lib/utils/text_utility
'
;
import
{
STEPS
,
TAX_RATE
}
from
'
../constants
'
;
import
{
TAX_RATE
}
from
'
../constants
'
;
const
parsePlanData
=
(
planData
)
=>
JSON
.
parse
(
planData
).
map
((
plan
)
=>
({
...
...
@@ -52,7 +52,6 @@ export default ({
const
groups
=
parseGroupData
(
groupData
);
return
{
currentStep
:
STEPS
[
0
],
isSetupForCompany
:
parseBoolean
(
setupForCompany
)
||
!
isNewUser
,
availablePlans
,
selectedPlan
:
determineSelectedPlan
(
planId
,
availablePlans
),
...
...
ee/app/assets/javascripts/
subscriptions/new/components/checkout
/step.vue
→
ee/app/assets/javascripts/
vue_shared/purchase_flow/components
/step.vue
View file @
0b90af66
<
script
>
import
{
GlFormGroup
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
mapActions
,
mapGetters
}
from
'
vuex
'
;
import
activateNextStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql
'
;
import
updateStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql
'
;
import
activeStepQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql
'
;
import
stepListQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql
'
;
import
{
convertToSnakeCase
,
dasherize
}
from
'
~/lib/utils/text_utility
'
;
import
StepHeader
from
'
./step_header.vue
'
;
import
StepSummary
from
'
./step_summary.vue
'
;
...
...
@@ -13,7 +16,7 @@ export default {
StepSummary
,
},
props
:
{
step
:
{
step
Id
:
{
type
:
String
,
required
:
true
,
},
...
...
@@ -31,30 +34,61 @@ export default {
default
:
''
,
},
},
data
()
{
return
{
activeStep
:
{},
stepList
:
[],
loading
:
false
,
};
},
apollo
:
{
activeStep
:
{
query
:
activeStepQuery
,
},
stepList
:
{
query
:
stepListQuery
,
},
},
computed
:
{
isActive
()
{
return
this
.
currentStep
===
this
.
step
;
return
this
.
activeStep
.
id
===
this
.
stepId
;
},
isFinished
()
{
return
this
.
isValid
&&
!
this
.
isActive
;
},
isEditable
()
{
return
this
.
isFinished
&&
this
.
stepIndex
(
this
.
step
)
<
this
.
currentStepIndex
;
const
index
=
this
.
stepList
.
findIndex
(({
id
})
=>
id
===
this
.
stepId
);
const
activeIndex
=
this
.
stepList
.
findIndex
(({
id
})
=>
id
===
this
.
activeStep
.
id
);
return
this
.
isFinished
&&
index
<
activeIndex
;
},
snakeCasedStep
()
{
return
dasherize
(
convertToSnakeCase
(
this
.
step
));
return
dasherize
(
convertToSnakeCase
(
this
.
step
Id
));
},
...
mapGetters
([
'
currentStep
'
,
'
stepIndex
'
,
'
currentStepIndex
'
]),
},
methods
:
{
...
mapActions
([
'
activateStep
'
,
'
activateNextStep
'
]),
nextStep
()
{
if
(
this
.
isValid
)
{
this
.
activateNextStep
();
async
nextStep
()
{
if
(
!
this
.
isValid
)
{
return
;
}
this
.
loading
=
true
;
await
this
.
$apollo
.
mutate
({
mutation
:
activateNextStepMutation
,
})
.
finally
(()
=>
{
this
.
loading
=
false
;
});
},
edit
()
{
this
.
activateStep
(
this
.
step
);
async
edit
()
{
this
.
loading
=
true
;
await
this
.
$apollo
.
mutate
({
mutation
:
updateStepMutation
,
variables
:
{
id
:
this
.
stepId
},
})
.
finally
(()
=>
{
this
.
loading
=
false
;
});
},
},
};
...
...
ee/app/assets/javascripts/
subscriptions/new/components/checkout
/step_header.vue
→
ee/app/assets/javascripts/
vue_shared/purchase_flow/components
/step_header.vue
View file @
0b90af66
File moved
ee/app/assets/javascripts/vue_shared/components/step_order_app.vue
→
ee/app/assets/javascripts/vue_shared/
purchase_flow/
components/step_order_app.vue
View file @
0b90af66
File moved
ee/app/assets/javascripts/
subscriptions/new/components/checkout
/step_summary.vue
→
ee/app/assets/javascripts/
vue_shared/purchase_flow/components
/step_summary.vue
View file @
0b90af66
File moved
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
View file @
0b90af66
...
...
@@ -4,7 +4,7 @@ import { createWrapper } from '@vue/test-utils';
import
initBuyMinutesApp
from
'
ee/subscriptions/buy_minutes
'
;
import
*
as
utils
from
'
ee/subscriptions/buy_minutes/utils
'
;
import
StepOrderApp
from
'
ee/vue_shared/components/step_order_app.vue
'
;
import
StepOrderApp
from
'
ee/vue_shared/
purchase_flow/
components/step_order_app.vue
'
;
import
{
mockCiMinutesPlans
,
mockParsedCiMinutesPlans
}
from
'
./mock_data
'
;
jest
.
mock
(
'
ee/subscriptions/buy_minutes/utils
'
);
...
...
ee/spec/frontend/subscriptions/new/components/checkout/billing_address_spec.js
View file @
0b90af66
import
{
mount
}
from
'
@vue/test-utils
'
;
import
Vue
,
{
nextTick
}
from
'
vue
'
;
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Vuex
from
'
vuex
'
;
import
Component
from
'
ee/subscriptions/new/components/checkout/billing_address.vue
'
;
import
Step
from
'
ee/subscriptions/new/components/checkout/step.vue
'
;
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
'
;
import
activateNextStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql
'
;
import
{
createMockApolloProvider
}
from
'
ee_jest/vue_shared/purchase_flow/spec_helper
'
;
Vue
.
use
(
Vuex
);
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
localVue
.
use
(
VueApollo
);
describe
(
'
Billing Address
'
,
()
=>
{
let
store
;
let
wrapper
;
let
mockApolloProvider
;
const
actionMocks
=
{
fetchCountries
:
jest
.
fn
(),
fetchStates
:
jest
.
fn
(),
};
const
createComponent
=
()
=>
{
function
activateNextStep
()
{
return
mockApolloProvider
.
clients
.
defaultClient
.
mutate
({
mutation
:
activateNextStepMutation
,
});
}
function
createStore
()
{
const
{
actions
,
...
storeConfig
}
=
getStoreConfig
();
store
=
new
Vuex
.
Store
({
return
new
Vuex
.
Store
({
...
storeConfig
,
actions
:
{
...
actions
,
...
actionMocks
},
});
}
wrapper
=
mount
(
Component
,
{
store
,
function
createComponent
(
options
=
{})
{
return
mount
(
BillingAddress
,
{
localVue
,
...
options
,
});
}
;
}
beforeEach
(()
=>
{
createComponent
();
store
=
createStore
();
mockApolloProvider
=
createMockApolloProvider
(
STEPS
);
wrapper
=
createComponent
({
store
,
apolloProvider
:
mockApolloProvider
});
});
afterEach
(()
=>
{
...
...
@@ -110,14 +128,15 @@ describe('Billing Address', () => {
});
describe
(
'
showing the summary
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(
async
()
=>
{
store
.
commit
(
types
.
UPDATE_COUNTRY
,
'
country
'
);
store
.
commit
(
types
.
UPDATE_STREET_ADDRESS_LINE_ONE
,
'
address line 1
'
);
store
.
commit
(
types
.
UPDATE_STREET_ADDRESS_LINE_TWO
,
'
address line 2
'
);
store
.
commit
(
types
.
UPDATE_COUNTRY_STATE
,
'
state
'
);
store
.
commit
(
types
.
UPDATE_CITY
,
'
city
'
);
store
.
commit
(
types
.
UPDATE_ZIP_CODE
,
'
zip
'
);
store
.
commit
(
types
.
UPDATE_CURRENT_STEP
,
'
nextStep
'
);
await
activateNextStep
();
await
activateNextStep
();
});
it
(
'
should show the entered address line 1
'
,
()
=>
{
...
...
ee/spec/frontend/subscriptions/new/components/checkout/confirm_order_spec.js
View file @
0b90af66
import
{
GlButton
,
GlLoadingIcon
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Vuex
from
'
vuex
'
;
import
Api
from
'
ee/api
'
;
import
Component
from
'
ee/subscriptions/new/components/checkout/confirm_order.vue
'
;
import
ConfirmOrder
from
'
ee/subscriptions/new/components/checkout/confirm_order.vue
'
;
import
{
STEPS
}
from
'
ee/subscriptions/new/constants
'
;
import
createStore
from
'
ee/subscriptions/new/store
'
;
import
*
as
types
from
'
ee/subscriptions/new/store/mutation_types
'
;
import
updateStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql
'
;
import
{
createMockApolloProvider
}
from
'
ee_jest/vue_shared/purchase_flow/spec_helper
'
;
describe
(
'
Confirm Order
'
,
()
=>
{
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
localVue
.
use
(
VueApollo
);
let
wrapper
;
let
mockApolloProvider
;
jest
.
mock
(
'
ee/api.js
'
);
const
store
=
createStore
();
const
createComponent
=
(
opts
=
{})
=>
{
wrapper
=
shallowMount
(
Component
,
{
function
activateStep
(
stepId
)
{
return
mockApolloProvider
.
clients
.
defaultClient
.
mutate
({
mutation
:
updateStepMutation
,
variables
:
{
id
:
stepId
},
});
}
function
createComponent
(
options
=
{})
{
return
shallowMount
(
ConfirmOrder
,
{
localVue
,
store
,
...
opts
,
...
opt
ion
s
,
});
}
;
}
const
findConfirmButton
=
()
=>
wrapper
.
find
(
GlButton
);
const
findLoadingIcon
=
()
=>
wrapper
.
find
(
GlLoadingIcon
);
beforeEach
(()
=>
{
createComponent
();
mockApolloProvider
=
createMockApolloProvider
(
STEPS
);
wrapper
=
createComponent
({
apolloProvider
:
mockApolloProvider
});
});
afterEach
(()
=>
{
...
...
@@ -36,8 +49,8 @@ describe('Confirm Order', () => {
});
describe
(
'
Active
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
commit
(
types
.
UPDATE_CURRENT_STEP
,
'
confirmOrder
'
);
beforeEach
(
async
()
=>
{
await
activateStep
(
STEPS
[
3
].
id
);
});
it
(
'
button should be visible
'
,
()
=>
{
...
...
@@ -74,8 +87,8 @@ describe('Confirm Order', () => {
});
describe
(
'
Inactive
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
commit
(
types
.
UPDATE_CURRENT_STEP
,
'
otherStep
'
);
beforeEach
(
async
()
=>
{
await
activateStep
(
STEPS
[
1
].
id
);
});
it
(
'
button should not be visible
'
,
()
=>
{
...
...
ee/spec/frontend/subscriptions/new/components/checkout/payment_method_spec.js
View file @
0b90af66
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Vuex
from
'
vuex
'
;
import
Component
from
'
ee/subscriptions/new/components/checkout/payment_method.vue
'
;
import
Step
from
'
ee/subscriptions/new/components/checkout/step.vue
'
;
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
{
createMockApolloProvider
}
from
'
ee_jest/vue_shared/purchase_flow/spec_helper
'
;
describe
(
'
Payment Method
'
,
()
=>
{
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
localVue
.
use
(
VueApollo
);
let
store
;
let
wrapper
;
const
createComponent
=
(
opts
=
{})
=>
{
wrapper
=
mount
(
Component
,
{
function
createComponent
(
options
=
{})
{
return
mount
(
PaymentMethod
,
{
localVue
,
store
,
...
opts
,
...
opt
ion
s
,
});
}
;
}
beforeEach
(()
=>
{
store
=
createStore
();
...
...
@@ -31,7 +35,8 @@ describe('Payment Method', () => {
credit_card_expiration_year
:
2009
,
});
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
});
afterEach
(()
=>
{
...
...
ee/spec/frontend/subscriptions/new/components/checkout/subscription_details_spec.js
View file @
0b90af66
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Vuex
from
'
vuex
'
;
import
Step
from
'
ee/subscriptions/new/components/checkout/step.vue
'
;
import
Component
from
'
ee/subscriptions/new/components/checkout/subscription_details.vue
'
;
import
{
NEW_GROUP
}
from
'
ee/subscriptions/new/constants
'
;
import
{
NEW_GROUP
,
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
{
createMockApolloProvider
}
from
'
ee_jest/vue_shared/purchase_flow/spec_helper
'
;
const
availablePlans
=
[
{
id
:
'
firstPlanId
'
,
code
:
'
bronze
'
,
price_per_year
:
48
,
name
:
'
bronze
'
},
{
id
:
'
secondPlanId
'
,
code
:
'
silver
'
,
price_per_year
:
228
,
name
:
'
silver
'
},
];
const
groupData
=
[
{
id
:
132
,
name
:
'
My first group
'
,
users
:
3
},
{
id
:
483
,
name
:
'
My second group
'
,
users
:
12
},
];
const
defaultInitialStoreData
=
{
availablePlans
:
JSON
.
stringify
(
availablePlans
),
groupData
:
JSON
.
stringify
(
groupData
),
planId
:
'
secondPlanId
'
,
namespaceId
:
null
,
setupForCompany
:
'
true
'
,
fullName
:
'
Full Name
'
,
};
describe
(
'
Subscription Details
'
,
()
=>
{
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
localVue
.
use
(
VueApollo
);
let
store
;
let
wrapper
;
const
availablePlans
=
[
{
id
:
'
firstPlanId
'
,
code
:
'
bronze
'
,
price_per_year
:
48
,
name
:
'
bronze
'
},
{
id
:
'
secondPlanId
'
,
code
:
'
silver
'
,
price_per_year
:
228
,
name
:
'
silver
'
},
];
const
groupData
=
[
{
id
:
132
,
name
:
'
My first group
'
,
users
:
3
},
{
id
:
483
,
name
:
'
My second group
'
,
users
:
12
},
];
let
initialNamespaceId
=
null
;
const
initialData
=
(
namespaceId
)
=>
{
return
{
availablePlans
:
JSON
.
stringify
(
availablePlans
),
groupData
:
JSON
.
stringify
(
groupData
),
planId
:
'
secondPlanId
'
,
namespaceId
,
setupForCompany
:
'
true
'
,
fullName
:
'
Full Name
'
,
};
};
const
createComponent
=
()
=>
{
wrapper
=
mount
(
Component
,
{
function
createComponent
(
options
=
{})
{
const
{
apolloProvider
,
store
}
=
options
;
return
mount
(
Component
,
{
localVue
,
store
,
apolloProvider
,
stubs
:
{
Step
,
},
});
}
;
}
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
(()
=>
{
store
=
createStore
(
initialData
(
initialNamespaceId
));
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
A new user setting up for personal use
'
,
()
=>
{
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
const
store
=
createStore
(
defaultInitialStoreData
);
store
.
state
.
isNewUser
=
true
;
store
.
state
.
isSetupForCompany
=
false
;
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
it
(
'
should not display an input field for the company or group name
'
,
()
=>
{
...
...
@@ -85,8 +87,11 @@ describe('Subscription Details', () => {
describe
(
'
A new user setting up for a company or group
'
,
()
=>
{
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
const
store
=
createStore
(
defaultInitialStoreData
);
store
.
state
.
isNewUser
=
true
;
store
.
state
.
groupData
=
[];
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
it
(
'
should display an input field for the company or group name
'
,
()
=>
{
...
...
@@ -112,8 +117,11 @@ describe('Subscription Details', () => {
describe
(
'
An existing user without any groups
'
,
()
=>
{
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
const
store
=
createStore
(
defaultInitialStoreData
);
store
.
state
.
isNewUser
=
false
;
store
.
state
.
groupData
=
[];
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
it
(
'
should display an input field for the company or group name
'
,
()
=>
{
...
...
@@ -138,8 +146,13 @@ describe('Subscription Details', () => {
});
describe
(
'
An existing user with groups
'
,
()
=>
{
let
store
;
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
store
=
createStore
(
defaultInitialStoreData
);
store
.
state
.
isNewUser
=
false
;
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
it
(
'
should not display an input field for the company or group name
'
,
()
=>
{
...
...
@@ -196,9 +209,13 @@ describe('Subscription Details', () => {
});
describe
(
'
An existing user coming from group billing page
'
,
()
=>
{
let
store
;
beforeEach
(()
=>
{
initialNamespaceId
=
'
132
'
;
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
store
=
createStore
({
...
defaultInitialStoreData
,
namespaceId
:
'
132
'
});
store
.
state
.
isNewUser
=
false
;
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
it
(
'
should not display an input field for the company or group name
'
,
()
=>
{
...
...
@@ -246,6 +263,13 @@ describe('Subscription Details', () => {
describe
(
'
validations
'
,
()
=>
{
const
isStepValid
=
()
=>
wrapper
.
find
(
Step
).
props
(
'
isValid
'
);
let
store
;
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
);
store
=
createStore
(
defaultInitialStoreData
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
});
});
describe
(
'
when setting up for a company
'
,
()
=>
{
beforeEach
(()
=>
{
...
...
@@ -331,12 +355,16 @@ describe('Subscription Details', () => {
});
describe
(
'
Showing summary
'
,
()
=>
{
let
store
;
beforeEach
(()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
store
=
createStore
(
defaultInitialStoreData
);
store
.
commit
(
types
.
UPDATE_IS_SETUP_FOR_COMPANY
,
true
);
store
.
commit
(
types
.
UPDATE_SELECTED_PLAN
,
'
firstPlanId
'
);
store
.
commit
(
types
.
UPDATE_ORGANIZATION_NAME
,
'
My Organization
'
);
store
.
commit
(
types
.
UPDATE_NUMBER_OF_USERS
,
25
);
store
.
commit
(
types
.
UPDATE_CURRENT_STEP
,
'
nextStep
'
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
,
store
}
);
});
it
(
'
should show the selected plan
'
,
()
=>
{
...
...
ee/spec/frontend/subscriptions/new/store/actions_spec.js
View file @
0b90af66
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
Api
from
'
ee/api
'
;
import
*
as
constants
from
'
ee/subscriptions/new/constants
'
;
import
defaultClient
from
'
ee/subscriptions/new/graphql
'
;
import
*
as
actions
from
'
ee/subscriptions/new/store/actions
'
;
import
activateNextStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/activate_next_step.mutation.graphql
'
;
import
{
useMockLocationHelper
}
from
'
helpers/mock_window_location_helper
'
;
import
testAction
from
'
helpers/vuex_action_helper
'
;
import
createFlash
from
'
~/flash
'
;
...
...
@@ -16,53 +18,18 @@ const {
}
=
Api
;
jest
.
mock
(
'
~/flash
'
);
jest
.
mock
(
'
ee/subscriptions/new/constants
'
,
()
=>
({
STEPS
:
[
'
firstStep
'
,
'
secondStep
'
],
}));
describe
(
'
Subscriptions Actions
'
,
()
=>
{
let
mock
;
beforeEach
(()
=>
{
mock
=
new
MockAdapter
(
axios
);
jest
.
spyOn
(
defaultClient
,
'
mutate
'
);
});
afterEach
(()
=>
{
mock
.
restore
();
});
describe
(
'
activateStep
'
,
()
=>
{
it
(
'
set the currentStep to the provided value
'
,
(
done
)
=>
{
testAction
(
actions
.
activateStep
,
'
secondStep
'
,
{},
[{
type
:
'
UPDATE_CURRENT_STEP
'
,
payload
:
'
secondStep
'
}],
[],
done
,
);
});
it
(
'
does not change the currentStep if provided value is not available
'
,
(
done
)
=>
{
testAction
(
actions
.
activateStep
,
'
thirdStep
'
,
{},
[],
[],
done
);
});
});
describe
(
'
activateNextStep
'
,
()
=>
{
it
(
'
set the currentStep to the next step in the available steps
'
,
(
done
)
=>
{
testAction
(
actions
.
activateNextStep
,
{},
{
currentStepIndex
:
0
},
[{
type
:
'
UPDATE_CURRENT_STEP
'
,
payload
:
'
secondStep
'
}],
[],
done
,
);
});
it
(
'
does not change the currentStep if the current step is the last step
'
,
(
done
)
=>
{
testAction
(
actions
.
activateNextStep
,
{},
{
currentStepIndex
:
1
},
[],
[],
done
);
});
defaultClient
.
mutate
.
mockClear
();
});
describe
(
'
updateSelectedPlan
'
,
()
=>
{
...
...
@@ -553,7 +520,7 @@ describe('Subscriptions Actions', () => {
});
describe
(
'
fetchPaymentMethodDetailsSuccess
'
,
()
=>
{
it
(
'
updates creditCardDetails to the provided data and calls
activateNextStep
'
,
(
done
)
=>
{
it
(
'
updates creditCardDetails to the provided data and calls
defaultClient with activateNextStepMutation
'
,
(
done
)
=>
{
testAction
(
actions
.
fetchPaymentMethodDetailsSuccess
,
{
...
...
@@ -574,8 +541,13 @@ describe('Subscriptions Actions', () => {
},
},
],
[{
type
:
'
activateNextStep
'
}],
done
,
[],
()
=>
{
expect
(
defaultClient
.
mutate
).
toHaveBeenCalledWith
({
mutation
:
activateNextStepMutation
,
});
done
();
},
);
});
});
...
...
ee/spec/frontend/subscriptions/new/store/getters_spec.js
View file @
0b90af66
import
*
as
constants
from
'
ee/subscriptions/new/constants
'
;
import
*
as
getters
from
'
ee/subscriptions/new/store/getters
'
;
constants
.
STEPS
=
[
'
firstStep
'
,
'
secondStep
'
];
const
state
=
{
currentStep
:
'
secondStep
'
,
isSetupForCompany
:
true
,
isNewUser
:
true
,
availablePlans
:
[
...
...
@@ -26,35 +23,6 @@ const state = {
};
describe
(
'
Subscriptions Getters
'
,
()
=>
{
describe
(
'
currentStep
'
,
()
=>
{
it
(
'
returns the states currentStep
'
,
()
=>
{
expect
(
getters
.
currentStep
(
state
)).
toBe
(
'
secondStep
'
);
});
});
describe
(
'
stepIndex
'
,
()
=>
{
it
(
'
returns a function
'
,
()
=>
{
expect
(
getters
.
stepIndex
()).
toBeInstanceOf
(
Function
);
});
it
(
'
returns a function that returns the index of the given step
'
,
()
=>
{
expect
(
getters
.
stepIndex
()(
'
secondStep
'
)).
toBe
(
1
);
});
});
describe
(
'
currentStepIndex
'
,
()
=>
{
it
(
'
returns a function
'
,
()
=>
{
expect
(
getters
.
currentStepIndex
(
state
,
getters
)).
toBeInstanceOf
(
Function
);
});
it
(
'
calls the stepIndex function with the current step name
'
,
()
=>
{
const
stepIndexSpy
=
jest
.
spyOn
(
getters
,
'
stepIndex
'
);
getters
.
currentStepIndex
(
state
,
getters
);
expect
(
stepIndexSpy
).
toHaveBeenCalledWith
(
'
secondStep
'
);
});
});
describe
(
'
selectedPlanText
'
,
()
=>
{
it
(
'
returns the text for selectedPlan
'
,
()
=>
{
expect
(
...
...
ee/spec/frontend/subscriptions/new/store/mutations_spec.js
View file @
0b90af66
...
...
@@ -2,7 +2,6 @@ import * as types from 'ee/subscriptions/new/store/mutation_types';
import
mutations
from
'
ee/subscriptions/new/store/mutations
'
;
const
state
=
()
=>
({
currentStep
:
'
firstStep
'
,
selectedPlan
:
'
firstPlan
'
,
isSetupForCompany
:
true
,
numberOfUsers
:
1
,
...
...
@@ -22,7 +21,6 @@ beforeEach(() => {
describe
(
'
ee/subscriptions/new/store/mutation
'
,
()
=>
{
describe
.
each
`
mutation | value | stateProp
${
types
.
UPDATE_CURRENT_STEP
}
|
${
'
secondStep
'
}
|
${
'
currentStep
'
}
${
types
.
UPDATE_SELECTED_PLAN
}
|
${
'
secondPlan
'
}
|
${
'
selectedPlan
'
}
${
types
.
UPDATE_SELECTED_GROUP
}
|
${
'
selectedGroup
'
}
|
${
'
selectedGroup
'
}
${
types
.
UPDATE_IS_SETUP_FOR_COMPANY
}
|
${
false
}
|
${
'
isSetupForCompany
'
}
...
...
ee/spec/frontend/subscriptions/new/store/state_spec.js
View file @
0b90af66
import
*
as
constants
from
'
ee/subscriptions/new/constants
'
;
import
createState
from
'
ee/subscriptions/new/store/state
'
;
constants
.
STEPS
=
[
'
firstStep
'
,
'
secondStep
'
];
constants
.
TAX_RATE
=
0
;
describe
(
'
projectsSelector default state
'
,
()
=>
{
...
...
@@ -31,10 +30,6 @@ describe('projectsSelector default state', () => {
const
state
=
createState
(
initialData
);
it
(
'
sets the currentStep to the first item of the STEPS constant
'
,
()
=>
{
expect
(
state
.
currentStep
).
toEqual
(
'
firstStep
'
);
});
describe
(
'
availablePlans
'
,
()
=>
{
it
(
'
sets the availablePlans to the provided parsed availablePlans
'
,
()
=>
{
expect
(
state
.
availablePlans
).
toEqual
([
...
...
ee/spec/frontend/
subscriptions/new/components/checkout
/step_spec.js
→
ee/spec/frontend/
vue_shared/purchase_flow/components
/step_spec.js
View file @
0b90af66
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
Component
from
'
ee/subscriptions/new/components/checkout/step.vue
'
;
import
StepSummary
from
'
ee/subscriptions/new/components/checkout/step_summary.vue
'
;
import
*
as
constants
from
'
ee/subscriptions/new/constants
'
;
import
createStore
from
'
ee/subscriptions/new/store
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
StepSummary
from
'
ee/vue_shared/purchase_flow/components/step_summary.vue
'
;
import
updateStepMutation
from
'
ee/vue_shared/purchase_flow/graphql/mutations/update_active_step.mutation.graphql
'
;
import
{
STEPS
}
from
'
../mock_data
'
;
import
{
createMockApolloProvider
}
from
'
../spec_helper
'
;
describe
(
'
Step
'
,
()
=>
{
const
localVue
=
createLocalVue
();
localVue
.
use
(
Vuex
);
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
let
store
;
describe
(
'
Step
'
,
()
=>
{
let
wrapper
;
const
initialProps
=
{
step
:
'
secondStep
'
,
step
Id
:
STEPS
[
1
].
id
,
isValid
:
true
,
title
:
'
title
'
,
nextStepButtonText
:
'
next
'
,
};
const
createComponent
=
(
propsData
)
=>
{
wrapper
=
shallowMount
(
Component
,
{
propsData
:
{
...
initialProps
,
...
propsData
},
function
activateFirstStep
(
apolloProvider
)
{
return
apolloProvider
.
clients
.
defaultClient
.
mutate
({
mutation
:
updateStepMutation
,
variables
:
{
id
:
STEPS
[
0
].
id
},
});
}
function
createComponent
(
options
=
{})
{
const
{
apolloProvider
,
propsData
}
=
options
;
return
shallowMount
(
Step
,
{
localVue
,
store
,
propsData
:
{
...
initialProps
,
...
propsData
},
apolloProvider
,
});
};
const
activatePreviousStep
=
()
=>
{
store
.
dispatch
(
'
activateStep
'
,
'
firstStep
'
);
};
constants
.
STEPS
=
[
'
firstStep
'
,
'
secondStep
'
];
beforeEach
(()
=>
{
store
=
createStore
();
store
.
dispatch
(
'
activateStep
'
,
'
secondStep
'
);
});
}
afterEach
(()
=>
{
wrapper
.
destroy
();
...
...
@@ -45,42 +41,47 @@ describe('Step', () => {
describe
(
'
Step Body
'
,
()
=>
{
it
(
'
should display the step body when this step is the current step
'
,
()
=>
{
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
'
.card > div
'
).
attributes
(
'
style
'
)).
toBeUndefined
();
});
it
(
'
should not display the step body when this step is not the current step
'
,
()
=>
{
activatePreviousStep
();
createComponent
();
it
(
'
should not display the step body when this step is not the current step
'
,
async
()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
await
activateFirstStep
(
mockApollo
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
'
.card > div
'
).
attributes
(
'
style
'
)).
toBe
(
'
display: none;
'
);
});
});
describe
(
'
Step Summary
'
,
()
=>
{
it
(
'
should be shown when this step is valid and not active
'
,
()
=>
{
activatePreviousStep
(
);
createComponent
(
);
it
(
'
should be shown when this step is valid and not active
'
,
async
()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
await
activateFirstStep
(
mockApollo
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
true
);
});
it
(
'
should not be shown when this step is not valid and not active
'
,
()
=>
{
activatePreviousStep
();
createComponent
({
isValid
:
false
});
it
(
'
should not be shown when this step is not valid and not active
'
,
async
()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
await
activateFirstStep
(
mockApollo
);
wrapper
=
createComponent
({
propsData
:
{
isValid
:
false
},
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
false
);
});
it
(
'
should not be shown when this step is valid and active
'
,
()
=>
{
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
false
);
});
it
(
'
should not be shown when this step is not valid and active
'
,
()
=>
{
createComponent
({
isValid
:
false
});
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
propsData
:
{
isValid
:
false
},
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
false
);
});
...
...
@@ -88,22 +89,25 @@ describe('Step', () => {
describe
(
'
isEditable
'
,
()
=>
{
it
(
'
should set the isEditable property to true when this step is finished and comes before the current step
'
,
()
=>
{
createComponent
({
step
:
'
firstStep
'
});
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
propsData
:
{
stepId
:
STEPS
[
0
].
id
},
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
props
(
'
isEditable
'
)).
toBe
(
true
);
});
});
describe
(
'
Showing the summary
'
,
()
=>
{
it
(
'
shows the summary when this step is finished
'
,
()
=>
{
activatePreviousStep
();
createComponent
();
it
(
'
shows the summary when this step is finished
'
,
async
()
=>
{
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
await
activateFirstStep
(
mockApollo
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
true
);
});
it
(
'
does not show the summary when this step is not finished
'
,
()
=>
{
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
StepSummary
).
exists
()).
toBe
(
false
);
});
...
...
@@ -111,25 +115,32 @@ describe('Step', () => {
describe
(
'
Next button
'
,
()
=>
{
it
(
'
shows the next button when the text was passed
'
,
()
=>
{
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
text
()).
toBe
(
'
next
'
);
});
it
(
'
does not show the next button when no text was passed
'
,
()
=>
{
createComponent
({
nextStepButtonText
:
''
});
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
propsData
:
{
nextStepButtonText
:
''
},
apolloProvider
:
mockApollo
,
});
expect
(
wrapper
.
text
()).
toBe
(
''
);
});
it
(
'
is disabled when this step is not valid
'
,
()
=>
{
createComponent
({
isValid
:
false
});
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
propsData
:
{
isValid
:
false
},
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
GlButton
).
attributes
(
'
disabled
'
)).
toBe
(
'
true
'
);
});
it
(
'
is enabled when this step is valid
'
,
()
=>
{
createComponent
();
const
mockApollo
=
createMockApolloProvider
(
STEPS
,
1
);
wrapper
=
createComponent
({
apolloProvider
:
mockApollo
});
expect
(
wrapper
.
find
(
GlButton
).
attributes
(
'
disabled
'
)).
toBeUndefined
();
});
...
...
ee/spec/frontend/vue_shared/purchase_flow/spec_helper.js
0 → 100644
View file @
0b90af66
import
activeStepQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/active_step.query.graphql
'
;
import
stepListQuery
from
'
ee/vue_shared/purchase_flow/graphql/queries/step_list.query.graphql
'
;
import
resolvers
from
'
ee/vue_shared/purchase_flow/graphql/resolvers
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
export
function
createMockApolloProvider
(
stepList
,
initialStepIndex
=
0
)
{
const
mockApollo
=
createMockApollo
([],
resolvers
);
mockApollo
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
stepListQuery
,
data
:
{
stepList
},
});
mockApollo
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
activeStepQuery
,
data
:
{
activeStep
:
stepList
[
initialStepIndex
]
},
});
return
mockApollo
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment