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
34a4563e
Commit
34a4563e
authored
Nov 11, 2021
by
Angelo Gulina
Committed by
Douglas Barbosa Alexandre
Nov 11, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Retrieve and use (current) subscription name for finalising the purchase
parent
1b58bdd5
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
298 additions
and
122 deletions
+298
-122
ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue
...s/subscriptions/buy_addons_shared/components/checkout.vue
+3
-3
ee/app/assets/javascripts/subscriptions/buy_addons_shared/constants.js
.../javascripts/subscriptions/buy_addons_shared/constants.js
+5
-0
ee/app/assets/javascripts/subscriptions/buy_addons_shared/utils.js
...sets/javascripts/subscriptions/buy_addons_shared/utils.js
+27
-9
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
.../javascripts/subscriptions/buy_minutes/components/app.vue
+10
-3
ee/app/assets/javascripts/subscriptions/graphql/queries/state.query.graphql
...scripts/subscriptions/graphql/queries/state.query.graphql
+7
-1
ee/app/assets/javascripts/vue_shared/purchase_flow/components/checkout/confirm_order.vue
...hared/purchase_flow/components/checkout/confirm_order.vue
+5
-2
ee/app/controllers/subscriptions_controller.rb
ee/app/controllers/subscriptions_controller.rb
+5
-3
ee/app/helpers/subscriptions_helper.rb
ee/app/helpers/subscriptions_helper.rb
+2
-1
ee/app/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service.rb
...bscriptions/fetch_purchase_eligible_namespaces_service.rb
+6
-2
ee/app/services/subscriptions/create_service.rb
ee/app/services/subscriptions/create_service.rb
+33
-10
ee/app/views/subscriptions/buy_minutes.html.haml
ee/app/views/subscriptions/buy_minutes.html.haml
+1
-1
ee/app/views/subscriptions/buy_storage.html.haml
ee/app/views/subscriptions/buy_storage.html.haml
+1
-1
ee/lib/gitlab/subscription_portal/clients/graphql.rb
ee/lib/gitlab/subscription_portal/clients/graphql.rb
+1
-0
ee/spec/fixtures/create_service_params.json
ee/spec/fixtures/create_service_params.json
+64
-29
ee/spec/frontend/subscriptions/buy_addons_shared/components/order_summary_spec.js
...ptions/buy_addons_shared/components/order_summary_spec.js
+0
-1
ee/spec/frontend/subscriptions/buy_minutes/components/app_spec.js
...frontend/subscriptions/buy_minutes/components/app_spec.js
+24
-4
ee/spec/frontend/subscriptions/buy_minutes/components/checkout/confirm_order_spec.js
...ons/buy_minutes/components/checkout/confirm_order_spec.js
+33
-34
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
+21
-6
ee/spec/helpers/subscriptions_helper_spec.rb
ee/spec/helpers/subscriptions_helper_spec.rb
+3
-1
ee/spec/lib/gitlab/subscription_portal/clients/graphql_spec.rb
...ec/lib/gitlab/subscription_portal/clients/graphql_spec.rb
+1
-0
ee/spec/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service_spec.rb
...ptions/fetch_purchase_eligible_namespaces_service_spec.rb
+10
-8
ee/spec/services/subscriptions/create_service_spec.rb
ee/spec/services/subscriptions/create_service_spec.rb
+22
-1
ee/spec/support/shared_examples/views/subscription_shared_examples.rb
...ort/shared_examples/views/subscription_shared_examples.rb
+14
-2
No files found.
ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue
View file @
34a4563e
...
...
@@ -16,15 +16,15 @@ export default {
},
},
mounted
()
{
this
.
updateSelectedPlan
Id
(
this
.
plan
.
id
);
this
.
updateSelectedPlan
(
this
.
plan
);
},
methods
:
{
updateSelectedPlan
Id
(
planId
)
{
updateSelectedPlan
({
id
,
isAddon
}
)
{
this
.
$apollo
.
mutate
({
mutation
:
updateState
,
variables
:
{
input
:
{
selectedPlan
Id
:
planId
},
input
:
{
selectedPlan
:
{
id
,
isAddon
}
},
},
})
.
catch
((
error
)
=>
{
...
...
ee/app/assets/javascripts/subscriptions/buy_addons_shared/constants.js
View file @
34a4563e
...
...
@@ -8,6 +8,11 @@ export const planTags = {
/* eslint-enable @gitlab/require-i18n-strings */
export
const
CUSTOMERSDOT_CLIENT
=
'
customersDotClient
'
;
export
const
GITLAB_CLIENT
=
'
gitlabClient
'
;
export
const
CUSTOMER_TYPE
=
'
Customer
'
;
export
const
SUBSCRIPTION_TYPE
=
'
Subscription
'
;
export
const
NAMESPACE_TYPE
=
'
Namespace
'
;
export
const
PAYMENT_METHOD_TYPE
=
'
PaymentMethod
'
;
export
const
PLAN_TYPE
=
'
Plan
'
;
export
const
CI_MINUTES_PER_PACK
=
1000
;
export
const
STORAGE_PER_PACK
=
10
;
...
...
ee/app/assets/javascripts/subscriptions/buy_addons_shared/utils.js
View file @
34a4563e
import
{
CUSTOMER_TYPE
,
NAMESPACE_TYPE
,
SUBSCRIPTION_TYPE
,
PAYMENT_METHOD_TYPE
,
PLAN_TYPE
,
}
from
'
ee/subscriptions/buy_addons_shared/constants
'
;
import
{
STEPS
}
from
'
ee/subscriptions/constants
'
;
import
stateQuery
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
{
convertObjectPropsToCamelCase
}
from
'
~/lib/utils/common_utils
'
;
...
...
@@ -11,26 +18,38 @@ function arrayToGraphqlArray(arr, typename) {
}
export
function
writeInitialDataToApolloCache
(
apolloProvider
,
dataset
)
{
const
{
groupData
,
namespaceId
,
redirectAfterSuccess
,
subscriptionQuantity
}
=
dataset
;
const
{
activeSubscriptionName
=
''
,
groupData
,
namespaceId
,
redirectAfterSuccess
,
subscriptionQuantity
,
}
=
dataset
;
// eslint-disable-next-line @gitlab/require-i18n-strings
const
eligibleNamespaces
=
arrayToGraphqlArray
(
JSON
.
parse
(
groupData
),
'
Namespace
'
);
const
eligibleNamespaces
=
arrayToGraphqlArray
(
JSON
.
parse
(
groupData
),
NAMESPACE_TYPE
);
const
quantity
=
subscriptionQuantity
||
1
;
apolloProvider
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
stateQuery
,
data
:
{
activeSubscription
:
{
name
:
activeSubscriptionName
,
__typename
:
SUBSCRIPTION_TYPE
,
},
isNewUser
:
false
,
fullName
:
null
,
isSetupForCompany
:
false
,
selectedPlanId
:
null
,
selectedPlan
:
{
id
:
null
,
isAddon
:
false
,
__typename
:
PLAN_TYPE
,
},
eligibleNamespaces
,
redirectAfterSuccess
,
selectedNamespaceId
:
namespaceId
,
subscription
:
{
quantity
,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename
:
'
Subscription
'
,
__typename
:
SUBSCRIPTION_TYPE
,
},
paymentMethod
:
{
id
:
null
,
...
...
@@ -38,7 +57,7 @@ export function writeInitialDataToApolloCache(apolloProvider, dataset) {
creditCardExpirationYear
:
null
,
creditCardType
:
null
,
creditCardMaskNumber
:
null
,
__typename
:
'
PaymentMethod
'
,
__typename
:
PAYMENT_METHOD_TYPE
,
},
customer
:
{
country
:
null
,
...
...
@@ -48,8 +67,7 @@ export function writeInitialDataToApolloCache(apolloProvider, dataset) {
state
:
null
,
zipCode
:
null
,
company
:
null
,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename
:
'
Customer
'
,
__typename
:
CUSTOMER_TYPE
,
},
activeStep
:
STEPS
[
0
],
stepList
:
STEPS
,
...
...
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
View file @
34a4563e
...
...
@@ -55,6 +55,14 @@ export default {
hasError
:
false
,
};
},
computed
:
{
plan
()
{
return
{
...
this
.
plans
[
0
],
isAddon
:
true
,
};
},
},
methods
:
{
isQuantityValid
(
quantity
)
{
return
Number
.
isFinite
(
quantity
)
&&
quantity
>
0
;
...
...
@@ -102,7 +110,6 @@ export default {
this
.
hasError
=
true
;
return
null
;
}
return
data
.
plans
;
},
error
(
error
)
{
...
...
@@ -122,7 +129,7 @@ export default {
/>
<step-order-app
v-else-if=
"!$apollo.loading"
>
<template
#checkout
>
<checkout
:plan=
"plan
s[0]
"
>
<checkout
:plan=
"plan"
>
<template
#purchase-details
>
<addon-purchase-details
:product-label=
"$options.i18n.productLabel"
...
...
@@ -145,7 +152,7 @@ export default {
</checkout>
</template>
<
template
#order-summary
>
<order-summary
:plan=
"plan
s[0]
"
:title=
"$options.i18n.title"
>
<order-summary
:plan=
"plan"
:title=
"$options.i18n.title"
>
<template
#price-per-unit
="
{ price }">
{{
pricePerUnitLabel
(
price
)
}}
</
template
>
...
...
ee/app/assets/javascripts/subscriptions/graphql/queries/state.query.graphql
View file @
34a4563e
...
...
@@ -5,10 +5,16 @@ query State {
name
users
}
activeSubscription
@client
{
name
}
isNewUser
@client
fullName
@client
isSetupForCompany
@client
selectedPlanId
@client
selectedPlan
@client
{
id
isAddon
}
selectedNamespaceId
@client
redirectAfterSuccess
@client
customer
@client
{
...
...
ee/app/assets/javascripts/vue_shared/purchase_flow/components/checkout/confirm_order.vue
View file @
34a4563e
...
...
@@ -35,11 +35,13 @@ export default {
},
update
(
data
)
{
const
{
customer
}
=
data
;
const
{
name
}
=
data
.
activeSubscription
;
return
{
setup_for_company
:
data
.
isSetupForCompany
,
selected_group
:
data
.
selectedNamespaceId
,
new_user
:
data
.
isNewUser
,
redirect_after_success
:
data
.
redirectAfterSuccess
,
active_subscription
:
name
,
customer
:
{
country
:
customer
.
country
,
address_1
:
customer
.
address1
,
...
...
@@ -50,9 +52,10 @@ export default {
company
:
customer
.
company
,
},
subscription
:
{
plan_id
:
data
.
selectedPlanId
,
payment_method_id
:
data
.
paymentMethod
.
id
,
quantity
:
data
.
subscription
.
quantity
,
is_addon
:
data
.
selectedPlan
.
isAddon
,
plan_id
:
data
.
selectedPlan
.
id
,
payment_method_id
:
data
.
paymentMethod
.
id
,
},
};
},
...
...
ee/app/controllers/subscriptions_controller.rb
View file @
34a4563e
...
...
@@ -36,11 +36,12 @@ class SubscriptionsController < ApplicationController
return
render_404
unless
ci_minutes_plan_data
.
present?
# At the moment of this comment the account id is directly available to the view.
# This might change in the future
given the intention to associate the account id to the namespace.
# This might change in the future given the intention to associate the account id to the namespace.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/338546#note_684762160
result
=
find_group
(
plan_id:
ci_minutes_plan_data
[
"id"
])
@group
=
result
[
:namespace
]
@account_id
=
result
[
:account_id
]
@active_subscription
=
result
[
:active_subscription
]
return
render_404
if
@group
.
nil?
...
...
@@ -51,11 +52,12 @@ class SubscriptionsController < ApplicationController
return
render_404
unless
storage_plan_data
.
present?
# At the moment of this comment the account id is directly available to the view.
# This might change in the future
given the intention to associate the account id to the namespace.
# This might change in the future given the intention to associate the account id to the namespace.
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/338546#note_684762160
result
=
find_group
(
plan_id:
storage_plan_data
[
"id"
])
@group
=
result
[
:namespace
]
@account_id
=
result
[
:account_id
]
@active_subscription
=
result
[
:active_subscription
]
return
render_404
if
@group
.
nil?
...
...
@@ -110,7 +112,7 @@ class SubscriptionsController < ApplicationController
end
def
subscription_params
params
.
require
(
:subscription
).
permit
(
:plan_id
,
:
payment_method_id
,
:quantity
,
:source
)
params
.
require
(
:subscription
).
permit
(
:plan_id
,
:
is_addon
,
:payment_method_id
,
:quantity
,
:source
).
merge
(
params
.
permit
(
:active_subscription
)
)
end
def
find_group
(
plan_id
:)
...
...
ee/app/helpers/subscriptions_helper.rb
View file @
34a4563e
...
...
@@ -16,8 +16,9 @@ module SubscriptionsHelper
}
end
def
buy_addon_data
(
group
,
account_id
,
anchor
,
purchased_product
)
def
buy_addon_data
(
group
,
account_id
,
a
ctive_subscription
,
a
nchor
,
purchased_product
)
{
active_subscription:
active_subscription
,
group_data:
[
present_group
(
group
,
account_id
)].
to_json
,
namespace_id:
params
[
:selected_group
],
redirect_after_success:
group_usage_quotas_path
(
group
,
anchor:
anchor
,
purchased_product:
purchased_product
),
...
...
ee/app/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service.rb
View file @
34a4563e
...
...
@@ -25,10 +25,14 @@ module GitlabSubscriptions
return
missing_plan_error
if
plan_id
.
nil?
&&
any_self_service_plan
.
nil?
if
response
[
:success
]
&&
response
[
:data
]
eligible_namespaces
=
response
[
:data
].
to_h
{
|
data
|
[
data
[
"id"
],
data
[
"accountId"
]]
}
eligible_namespaces
=
response
[
:data
].
to_h
{
|
data
|
[
data
[
"id"
],
[
data
[
"accountId"
],
data
[
'subscription'
]
]]
}
data
=
namespaces
.
each_with_object
([])
do
|
namespace
,
acc
|
if
eligible_namespaces
.
include?
(
namespace
.
id
)
acc
<<
{
namespace:
namespace
,
account_id:
eligible_namespaces
[
namespace
.
id
]
}
acc
<<
{
namespace:
namespace
,
account_id:
eligible_namespaces
[
namespace
.
id
][
0
],
active_subscription:
eligible_namespaces
[
namespace
.
id
][
1
]
}
end
end
...
...
ee/app/services/subscriptions/create_service.rb
View file @
34a4563e
...
...
@@ -25,10 +25,7 @@ module Subscriptions
# We can't use an email from GL.com because it may differ from the billing email.
# Instead we use the email received from the CustomersDot as a billing email.
customer_data
=
response
.
with_indifferent_access
[
:data
][
:customer
]
billing_email
=
customer_data
[
:email
]
token
=
customer_data
[
:authentication_token
]
response
=
client
.
create_subscription
(
create_subscription_params
,
billing_email
,
token
)
response
=
create_subscription
(
customer_data
)
OnboardingProgressService
.
new
(
@group
).
execute
(
action: :subscription_created
)
if
response
[
:success
]
...
...
@@ -73,15 +70,20 @@ module Subscriptions
}
end
def
create_subscription_params
def
create_subscription
(
customer_data
)
# When purchasing an add on, we don't want to send create_subscription_params
# in order to avoid amending the main product. Note that this will go away
# when fully transitioning the flow to GraphQL
create_params
=
add_on?
?
create_addon_params
:
create_subscription_params
billing_email
,
token
=
customer_data
.
values_at
(
:email
,
:authentication_token
)
client
.
create_subscription
(
create_params
,
billing_email
,
token
)
end
def
create_params
{
plan_id:
subscription_params
[
:plan_id
],
payment_method_id:
subscription_params
[
:payment_method_id
],
products:
{
main:
{
quantity:
subscription_params
[
:quantity
]
}
},
gl_namespace_id:
@group
.
id
,
gl_namespace_name:
@group
.
name
,
preview:
'false'
,
...
...
@@ -89,6 +91,27 @@ module Subscriptions
}
end
def
create_addon_params
{
active_subscription:
subscription_params
[
:active_subscription
],
quantity:
subscription_params
[
:quantity
]
}.
merge
(
create_params
)
end
def
create_subscription_params
{
products:
{
main:
{
quantity:
subscription_params
[
:quantity
]
}
}
}.
merge
(
create_params
)
end
def
add_on?
Gitlab
::
Utils
.
to_boolean
(
subscription_params
[
:is_addon
],
default:
false
)
end
def
country_code
(
country
)
World
.
alpha3_from_alpha2
(
country
)
end
...
...
ee/app/views/subscriptions/buy_minutes.html.haml
View file @
34a4563e
...
...
@@ -2,4 +2,4 @@
-
content_for
:page_specific_javascripts
do
=
render
"layouts/one_trust"
#js-buy-minutes
{
data:
buy_addon_data
(
@group
,
@account_id
,
'pipelines-quota-tab'
,
s_
(
'Checkout|CI minutes'
))
}
#js-buy-minutes
{
data:
buy_addon_data
(
@group
,
@account_id
,
@active_subscription
,
'pipelines-quota-tab'
,
s_
(
'Checkout|CI minutes'
))
}
ee/app/views/subscriptions/buy_storage.html.haml
View file @
34a4563e
...
...
@@ -2,4 +2,4 @@
-
content_for
:page_specific_javascripts
do
=
render
"layouts/one_trust"
#js-buy-storage
{
data:
buy_addon_data
(
@group
,
@account_id
,
'storage-quota-tab'
,
s_
(
'Checkout|a storage subscription'
))
}
#js-buy-storage
{
data:
buy_addon_data
(
@group
,
@account_id
,
@active_subscription
,
'storage-quota-tab'
,
s_
(
'Checkout|a storage subscription'
))
}
ee/lib/gitlab/subscription_portal/clients/graphql.rb
View file @
34a4563e
...
...
@@ -124,6 +124,7 @@ module Gitlab
namespaceEligibility(customerUid: $customerUid, namespaces: $namespaces, planId: $planId, eligibleForPurchase: $eligibleForPurchase) {
id
accountId: zuoraAccountId
subscription { name }
}
}
GQL
...
...
ee/spec/fixtures/create_service_params.json
View file @
34a4563e
{
"customer"
:
{
"provider"
:
"gitlab"
,
"uid"
:
111
,
"credentials"
:
{
"token"
:
"foo_token"
},
[
{
"customer"
:
{
"country"
:
"NLD"
,
"address_1"
:
"Address line 1"
,
"address_2"
:
"Address line 2"
,
"city"
:
"City"
,
"state"
:
"State"
,
"zip_code"
:
"Zip code"
,
"company"
:
"My organization"
"provider"
:
"gitlab"
,
"uid"
:
111
,
"credentials"
:
{
"token"
:
"foo_token"
},
"customer"
:
{
"country"
:
"NLD"
,
"address_1"
:
"Address line 1"
,
"address_2"
:
"Address line 2"
,
"city"
:
"City"
,
"state"
:
"State"
,
"zip_code"
:
"Zip code"
,
"company"
:
"My organization"
},
"info"
:
{
"first_name"
:
"First name"
,
"last_name"
:
"Last name"
,
"email"
:
"first.last@gitlab.com"
}
},
"info"
:
{
"first_name"
:
"First name"
,
"last_name"
:
"Last name"
,
"email"
:
"first.last@gitlab.com"
"subscription"
:
{
"plan_id"
:
"Plan ID"
,
"payment_method_id"
:
"Payment method ID"
,
"products"
:
{
"main"
:
{
"quantity"
:
123
}
},
"gl_namespace_id"
:
222
,
"gl_namespace_name"
:
"Group name"
,
"preview"
:
"false"
,
"source"
:
"some_source"
}
},
"subscription"
:
{
"plan_id"
:
"Plan ID"
,
"payment_method_id"
:
"Payment method ID"
,
"products"
:
{
"main"
:
{
"quantity"
:
123
{
"customer"
:
{
"provider"
:
"gitlab"
,
"uid"
:
111
,
"credentials"
:
{
"token"
:
"foo_token"
},
"customer"
:
{
"country"
:
"NLD"
,
"address_1"
:
"Address line 1"
,
"address_2"
:
"Address line 2"
,
"city"
:
"City"
,
"state"
:
"State"
,
"zip_code"
:
"Zip code"
,
"company"
:
"My organization"
},
"info"
:
{
"first_name"
:
"First name"
,
"last_name"
:
"Last name"
,
"email"
:
"first.last@gitlab.com"
}
},
"gl_namespace_id"
:
222
,
"gl_namespace_name"
:
"Group name"
,
"preview"
:
"false"
,
"source"
:
"some_source"
"subscription"
:
{
"plan_id"
:
"Add-on Plan ID"
,
"payment_method_id"
:
"Payment method ID"
,
"quantity"
:
111
,
"active_subscription"
:
"A-000000"
,
"gl_namespace_id"
:
222
,
"gl_namespace_name"
:
"Group name"
,
"preview"
:
"false"
,
"source"
:
"some_source"
}
}
}
]
ee/spec/frontend/subscriptions/buy_addons_shared/components/order_summary_spec.js
View file @
34a4563e
...
...
@@ -59,7 +59,6 @@ describe('Order Summary', () => {
beforeEach
(()
=>
{
createComponent
({
subscription
:
{
quantity
:
1
},
selectedPlanId
:
'
ciMinutesPackPlanId
'
,
});
});
...
...
ee/spec/frontend/subscriptions/buy_minutes/components/app_spec.js
View file @
34a4563e
import
{
GlEmptyState
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
pick
}
from
'
lodash
'
;
import
{
I18N_CI_MINUTES_TITLE
,
planTags
}
from
'
ee/subscriptions/buy_addons_shared/constants
'
;
import
Checkout
from
'
ee/subscriptions/buy_addons_shared/components/checkout.vue
'
;
import
AddonPurchaseDetails
from
'
ee/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue
'
;
import
OrderSummary
from
'
ee/subscriptions/buy_addons_shared/components/order_summary.vue
'
;
...
...
@@ -9,8 +11,8 @@ import App from 'ee/subscriptions/buy_minutes/components/app.vue';
import
StepOrderApp
from
'
ee/vue_shared/purchase_flow/components/step_order_app.vue
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
planTags
}
from
'
../../../../../app/assets/javascripts/subscriptions/buy_addons_shared/constants
'
;
import
{
createMockApolloProvider
}
from
'
../spec_helper
'
;
import
{
mockCiMinutesPlans
}
from
'
../mock_data
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
...
...
@@ -32,24 +34,42 @@ describe('App', () => {
});
}
const
getCiMinutePlan
=
()
=>
pick
(
mockCiMinutesPlans
[
0
],
[
'
id
'
,
'
code
'
,
'
pricePerYear
'
,
'
name
'
]);
const
findCheckout
=
()
=>
wrapper
.
findComponent
(
Checkout
);
const
findOrderSummary
=
()
=>
wrapper
.
findComponent
(
OrderSummary
);
const
findPriceLabel
=
()
=>
wrapper
.
findByTestId
(
'
price-per-unit
'
);
const
findQuantityText
=
()
=>
wrapper
.
findByTestId
(
'
addon-quantity-text
'
);
const
findSummaryLabel
=
()
=>
wrapper
.
findByTestId
(
'
summary-label
'
);
const
findSummaryTotal
=
()
=>
wrapper
.
findByTestId
(
'
summary-total
'
);
const
findPriceLabel
=
()
=>
wrapper
.
findByTestId
(
'
price-per-unit
'
);
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
when data is received
'
,
()
=>
{
it
(
'
should display the StepOrderApp
'
,
async
()
=>
{
beforeEach
(
()
=>
{
const
mockApollo
=
createMockApolloProvider
();
wrapper
=
createComponent
(
mockApollo
);
await
waitForPromises
();
return
waitForPromises
();
});
it
(
'
should display the StepOrderApp
'
,
()
=>
{
expect
(
wrapper
.
findComponent
(
StepOrderApp
).
exists
()).
toBe
(
true
);
expect
(
wrapper
.
findComponent
(
GlEmptyState
).
exists
()).
toBe
(
false
);
});
it
(
'
provides the correct props to checkout
'
,
()
=>
{
expect
(
findCheckout
().
props
()).
toMatchObject
({
plan
:
{
...
getCiMinutePlan
,
isAddon
:
true
},
});
});
it
(
'
provides the correct props to order summary
'
,
()
=>
{
expect
(
findOrderSummary
().
props
()).
toMatchObject
({
plan
:
{
...
getCiMinutePlan
,
isAddon
:
true
},
title
:
I18N_CI_MINUTES_TITLE
,
});
});
});
describe
(
'
when data is not received
'
,
()
=>
{
...
...
ee/spec/frontend/subscriptions/buy_minutes/components/checkout/confirm_order_spec.js
View file @
34a4563e
...
...
@@ -6,7 +6,10 @@ import { STEPS } from 'ee/subscriptions/constants';
import
stateQuery
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
ConfirmOrder
from
'
ee/vue_shared/purchase_flow/components/checkout/confirm_order.vue
'
;
import
{
GENERAL_ERROR_MESSAGE
}
from
'
ee/vue_shared/purchase_flow/constants
'
;
import
{
stateData
as
initialStateData
}
from
'
ee_jest/subscriptions/buy_minutes/mock_data
'
;
import
{
stateData
as
initialStateData
,
subscriptionName
,
}
from
'
ee_jest/subscriptions/buy_minutes/mock_data
'
;
import
{
createMockApolloProvider
}
from
'
ee_jest/vue_shared/purchase_flow/spec_helper
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
flash
from
'
~/flash
'
;
...
...
@@ -40,17 +43,13 @@ describe('Confirm Order', () => {
wrapper
.
destroy
();
});
describe
(
'
Active
'
,
()
=>
{
describe
(
'
when rendering
'
,
()
=>
{
describe
(
'
when receiving proper step data
'
,
()
=>
{
beforeEach
(()
=>
{
mockApolloProvider
=
createMockApolloProvider
(
STEPS
,
3
);
createComponent
({
apolloProvider
:
mockApolloProvider
});
});
it
(
'
button should be visible
'
,
()
=>
{
expect
(
findConfirmButton
().
exists
()).
toBe
(
true
);
});
it
(
'
shows the text "Confirm purchase"
'
,
()
=>
{
expect
(
findConfirmButton
().
text
()).
toBe
(
'
Confirm purchase
'
);
});
...
...
@@ -60,7 +59,7 @@ describe('Confirm Order', () => {
});
});
describe
(
'
Clicking the button
'
,
()
=>
{
describe
(
'
when confirming the order
'
,
()
=>
{
beforeEach
(()
=>
{
mockApolloProvider
=
createMockApolloProvider
([]);
mockApolloProvider
.
clients
.
defaultClient
.
cache
.
writeQuery
({
...
...
@@ -74,9 +73,10 @@ describe('Confirm Order', () => {
it
(
'
calls the confirmOrder API method with the correct params
'
,
()
=>
{
expect
(
Api
.
confirmOrder
).
toHaveBeenCalledTimes
(
1
);
expect
(
Api
.
confirmOrder
.
mock
.
calls
[
0
][
0
]).
to
MatchObject
({
expect
(
Api
.
confirmOrder
.
mock
.
calls
[
0
][
0
]).
to
Equal
({
setup_for_company
:
true
,
selected_group
:
'
30
'
,
active_subscription
:
subscriptionName
,
new_user
:
false
,
redirect_after_success
:
'
/path/to/redirect/
'
,
customer
:
{
...
...
@@ -90,6 +90,7 @@ describe('Confirm Order', () => {
},
subscription
:
{
plan_id
:
null
,
is_addon
:
true
,
payment_method_id
:
null
,
quantity
:
1
,
},
...
...
@@ -105,35 +106,33 @@ describe('Confirm Order', () => {
});
});
describe
(
'
Order confirmation
'
,
()
=>
{
describe
(
'
when the confirmation succeeds
'
,
()
=>
{
const
location
=
'
group/location/path
'
;
describe
(
'
when confirming the purchase
'
,
()
=>
{
const
location
=
'
group/location/path
'
;
beforeEach
(()
=>
{
mockApolloProvider
=
createMockApolloProvider
(
STEPS
,
3
);
createComponent
({
apolloProvider
:
mockApolloProvider
});
});
beforeEach
(()
=>
{
mockApolloProvider
=
createMockApolloProvider
(
STEPS
,
3
);
createComponent
({
apolloProvider
:
mockApolloProvider
});
});
it
(
'
should redirect to the location
'
,
async
()
=>
{
Api
.
confirmOrder
=
jest
.
fn
().
mockResolvedValueOnce
({
data
:
{
location
}
});
findConfirmButton
().
vm
.
$emit
(
'
click
'
);
await
flushPromises
();
it
(
'
redirects to the location if it succeeds
'
,
async
()
=>
{
Api
.
confirmOrder
=
jest
.
fn
().
mockResolvedValueOnce
({
data
:
{
location
}
});
findConfirmButton
().
vm
.
$emit
(
'
click
'
);
await
flushPromises
();
expect
(
UrlUtility
.
redirectTo
).
toHaveBeenCalledTimes
(
1
);
expect
(
UrlUtility
.
redirectTo
).
toHaveBeenCalledWith
(
location
);
});
expect
(
UrlUtility
.
redirectTo
).
toHaveBeenCalledTimes
(
1
);
expect
(
UrlUtility
.
redirectTo
).
toHaveBeenCalledWith
(
location
);
});
it
(
'
shows an error if it fails
'
,
async
()
=>
{
const
errors
=
'
an error
'
;
Api
.
confirmOrder
=
jest
.
fn
().
mockResolvedValueOnce
({
data
:
{
errors
}
});
findConfirmButton
().
vm
.
$emit
(
'
click
'
);
await
flushPromises
();
it
(
'
shows an error
'
,
async
()
=>
{
const
errors
=
'
an error
'
;
Api
.
confirmOrder
=
jest
.
fn
().
mockResolvedValueOnce
({
data
:
{
errors
}
});
findConfirmButton
().
vm
.
$emit
(
'
click
'
);
await
flushPromises
();
expect
(
flash
.
mock
.
calls
[
0
][
0
]).
toMatchObject
({
message
:
GENERAL_ERROR_MESSAGE
,
captureError
:
true
,
error
:
new
Error
(
JSON
.
stringify
(
errors
)),
});
expect
(
flash
.
mock
.
calls
[
0
][
0
]).
toMatchObject
({
message
:
GENERAL_ERROR_MESSAGE
,
captureError
:
true
,
error
:
new
Error
(
JSON
.
stringify
(
errors
)),
});
});
});
...
...
@@ -163,7 +162,7 @@ describe('Confirm Order', () => {
});
});
describe
(
'
I
nactive
'
,
()
=>
{
describe
(
'
when i
nactive
'
,
()
=>
{
it
(
'
does not show buttons
'
,
()
=>
{
mockApolloProvider
=
createMockApolloProvider
(
STEPS
,
1
);
createComponent
({
apolloProvider
:
mockApolloProvider
});
...
...
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
View file @
34a4563e
import
{
STEPS
}
from
'
ee/subscriptions/constants
'
;
import
{
CUSTOMER_TYPE
,
NAMESPACE_TYPE
,
PAYMENT_METHOD_TYPE
,
PLAN_TYPE
,
SUBSCRIPTION_TYPE
,
}
from
'
ee/subscriptions/buy_addons_shared/constants
'
;
export
const
accountId
=
'
111111111111
'
;
export
const
subscriptionName
=
'
A-000000000
'
;
export
const
mockCiMinutesPlans
=
[
{
...
...
@@ -8,7 +16,7 @@ export const mockCiMinutesPlans = [
code
:
'
ci_minutes
'
,
pricePerYear
:
10
,
name
:
'
CI minutes pack
'
,
__typename
:
'
Plan
'
,
__typename
:
PLAN_TYPE
,
},
];
...
...
@@ -19,7 +27,7 @@ export const mockNamespaces = `
export
const
mockParsedNamespaces
=
JSON
.
parse
(
mockNamespaces
).
map
((
namespace
)
=>
({
...
namespace
,
__typename
:
'
Namespace
'
,
__typename
:
NAMESPACE_TYPE
,
}));
export
const
mockNewUser
=
'
false
'
;
...
...
@@ -35,18 +43,25 @@ export const stateData = {
eligibleNamespaces
:
[],
subscription
:
{
quantity
:
1
,
__typename
:
'
Subscription
'
,
__typename
:
SUBSCRIPTION_TYPE
,
},
activeSubscription
:
{
name
:
subscriptionName
,
__typename
:
SUBSCRIPTION_TYPE
,
},
redirectAfterSuccess
:
'
/path/to/redirect/
'
,
selectedNamespaceId
:
'
30
'
,
selectedPlanId
:
null
,
selectedPlan
:
{
id
:
null
,
isAddon
:
true
,
},
paymentMethod
:
{
id
:
null
,
creditCardExpirationMonth
:
null
,
creditCardExpirationYear
:
null
,
creditCardType
:
null
,
creditCardMaskNumber
:
null
,
__typename
:
'
PaymentMethod
'
,
__typename
:
PAYMENT_METHOD_TYPE
,
},
customer
:
{
country
:
null
,
...
...
@@ -56,7 +71,7 @@ export const stateData = {
state
:
null
,
zipCode
:
null
,
company
:
null
,
__typename
:
'
Customer
'
,
__typename
:
CUSTOMER_TYPE
,
},
fullName
:
'
Full Name
'
,
isNewUser
:
false
,
...
...
ee/spec/helpers/subscriptions_helper_spec.rb
View file @
34a4563e
...
...
@@ -134,11 +134,12 @@ RSpec.describe SubscriptionsHelper do
end
describe
'#buy_addon_data'
do
subject
(
:buy_addon_data
)
{
helper
.
buy_addon_data
(
group
,
account_id
,
anchor
,
purchased_product
)
}
subject
(
:buy_addon_data
)
{
helper
.
buy_addon_data
(
group
,
account_id
,
a
ctive_subscription
,
a
nchor
,
purchased_product
)
}
let_it_be
(
:group
)
{
create
(
:group
,
name:
'My Namespace'
)
}
let_it_be
(
:user
)
{
create
(
:user
,
name:
'First Last'
)
}
let_it_be
(
:account_id
)
{
'111111111111'
}
let_it_be
(
:active_subscription
)
{
{
name:
'S-000000000'
}
}
let
(
:anchor
)
{
'pipelines-quota-tab'
}
let
(
:purchased_product
)
{
'CI Minutes'
}
...
...
@@ -150,6 +151,7 @@ RSpec.describe SubscriptionsHelper do
end
it
{
is_expected
.
to
include
(
namespace_id:
group
.
id
.
to_s
)
}
it
{
is_expected
.
to
include
(
active_subscription:
active_subscription
)
}
it
{
is_expected
.
to
include
(
source:
'some_source'
)
}
it
{
is_expected
.
to
include
(
group_data:
%Q{[{"id":
#{
group
.
id
}
,"account_id":"
#{
account_id
}
","name":"My Namespace","users":1,"guests":0}]}
)
}
it
{
is_expected
.
to
include
(
redirect_after_success:
group_usage_quotas_path
(
group
,
anchor:
anchor
,
purchased_product:
purchased_product
))
}
...
...
ee/spec/lib/gitlab/subscription_portal/clients/graphql_spec.rb
View file @
34a4563e
...
...
@@ -323,6 +323,7 @@ RSpec.describe Gitlab::SubscriptionPortal::Clients::Graphql do
namespaceEligibility(customerUid: $customerUid, namespaces: $namespaces, planId: $planId, eligibleForPurchase: $eligibleForPurchase) {
id
accountId: zuoraAccountId
subscription { name }
}
}
GQL
...
...
ee/spec/services/gitlab_subscriptions/fetch_purchase_eligible_namespaces_service_spec.rb
View file @
34a4563e
...
...
@@ -67,13 +67,15 @@ RSpec.describe GitlabSubscriptions::FetchPurchaseEligibleNamespacesService do
end
context
'when all the namespaces are eligible'
do
let
(
:subscription_name
)
{
'S-000000'
}
before
do
allow
(
Gitlab
::
SubscriptionPortal
::
Client
)
.
to
receive
(
:filter_purchase_eligible_namespaces
)
.
with
(
user
,
[
namespace_1
,
namespace_2
],
plan_id:
'test'
,
any_self_service_plan:
nil
)
.
and_return
(
success:
true
,
data:
[
{
'id'
=>
namespace_1
.
id
,
'accountId'
=>
nil
},
{
'id'
=>
namespace_2
.
id
,
'accountId'
=>
nil
}
{
'id'
=>
namespace_1
.
id
,
'accountId'
=>
nil
,
'subscription'
=>
{
'name'
=>
subscription_name
}
},
{
'id'
=>
namespace_2
.
id
,
'accountId'
=>
nil
,
'subscription'
=>
nil
}
])
end
...
...
@@ -83,8 +85,8 @@ RSpec.describe GitlabSubscriptions::FetchPurchaseEligibleNamespacesService do
expect
(
result
).
to
be_success
expect
(
result
.
payload
).
to
match_array
[
namespace_result
(
namespace_1
,
nil
),
namespace_result
(
namespace_2
,
nil
)
namespace_result
(
namespace_1
,
nil
,
{
'name'
=>
subscription_name
}
),
namespace_result
(
namespace_2
,
nil
,
nil
)
]
end
end
...
...
@@ -105,7 +107,7 @@ RSpec.describe GitlabSubscriptions::FetchPurchaseEligibleNamespacesService do
expect
(
result
).
to
be_success
expect
(
result
.
payload
).
to
match_array
[
namespace_result
(
namespace_1
,
account_id
)
namespace_result
(
namespace_1
,
account_id
,
nil
)
]
end
end
...
...
@@ -124,7 +126,7 @@ RSpec.describe GitlabSubscriptions::FetchPurchaseEligibleNamespacesService do
expect
(
result
).
to
be_success
expect
(
result
.
payload
).
to
match_array
[
namespace_result
(
namespace_1
,
nil
)
namespace_result
(
namespace_1
,
nil
,
nil
)
]
end
end
...
...
@@ -132,7 +134,7 @@ RSpec.describe GitlabSubscriptions::FetchPurchaseEligibleNamespacesService do
private
def
namespace_result
(
namespace
,
account_id
)
{
namespace:
namespace
,
account_id:
account_id
}
def
namespace_result
(
namespace
,
account_id
,
active_subscription
)
{
namespace:
namespace
,
account_id:
account_id
,
active_subscription:
active_subscription
}
end
end
ee/spec/services/subscriptions/create_service_spec.rb
View file @
34a4563e
...
...
@@ -32,7 +32,7 @@ RSpec.describe Subscriptions::CreateService do
let_it_be
(
:customer_email
)
{
'first.last@gitlab.com'
}
let_it_be
(
:client
)
{
Gitlab
::
SubscriptionPortal
::
Client
}
let_it_be
(
:create_service_params
)
{
Gitlab
::
Json
.
parse
(
fixture_file
(
'create_service_params.json'
,
dir:
'ee'
)).
deep_symbolize_keys
}
let_it_be
(
:create_service_params
)
{
Gitlab
::
Json
.
parse
(
fixture_file
(
'create_service_params.json'
,
dir:
'ee'
))
[
0
]
.
deep_symbolize_keys
}
describe
'#execute'
do
before
do
...
...
@@ -123,6 +123,27 @@ RSpec.describe Subscriptions::CreateService do
execute
end
context
'with add-on purchase'
do
let_it_be
(
:subscription_params
)
do
{
is_addon:
true
,
active_subscription:
'A-000000'
,
plan_id:
'Add-on Plan ID'
,
payment_method_id:
'Payment method ID'
,
quantity:
111
,
source:
'some_source'
}
end
it
'passes the correct parameters for creating a subscription'
do
create_service_addon_params
=
Gitlab
::
Json
.
parse
(
fixture_file
(
'create_service_params.json'
,
dir:
'ee'
))[
1
].
deep_symbolize_keys
expect
(
client
).
to
receive
(
:create_subscription
).
with
(
create_service_addon_params
[
:subscription
],
customer_email
,
'token'
)
execute
end
end
it_behaves_like
'records an onboarding progress action'
,
:subscription_created
do
let
(
:namespace
)
{
group
}
end
...
...
ee/spec/support/shared_examples/views/subscription_shared_examples.rb
View file @
34a4563e
...
...
@@ -21,8 +21,13 @@ RSpec.shared_examples_for 'subscription form data' do |js_selector|
end
RSpec
.
shared_examples_for
'buy minutes addon form data'
do
|
js_selector
|
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:account_id
)
{
'111111111111'
}
let_it_be
(
:active_subscription
)
{
{
name:
'S-000000000'
}
}
before
do
allow
(
view
).
to
receive
(
:buy_addon_data
).
and_return
(
allow
(
view
).
to
receive
(
:buy_addon_data
).
with
(
@group
,
@account_id
,
@active_subscription
,
'pipelines-quota-tab'
,
s_
(
'Checkout|CI minutes'
)).
and_return
(
active_subscription:
active_subscription
,
group_data:
'[{"id":"ci_minutes_plan_id","code":"ci_minutes","price_per_year":10.0}]'
,
namespace_id:
'1'
,
plan_id:
'ci_minutes_plan_id'
,
...
...
@@ -33,6 +38,7 @@ RSpec.shared_examples_for 'buy minutes addon form data' do |js_selector|
subject
{
render
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-active-subscription-name='S-000000000']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-group-data='[{
\"
id
\"
:
\"
ci_minutes_plan_id
\"
,
\"
code
\"
:
\"
ci_minutes
\"
,
\"
price_per_year
\"
:10.0}]']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-plan-id='ci_minutes_plan_id']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-namespace-id='1']"
)
}
...
...
@@ -41,8 +47,13 @@ RSpec.shared_examples_for 'buy minutes addon form data' do |js_selector|
end
RSpec
.
shared_examples_for
'buy storage addon form data'
do
|
js_selector
|
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:account_id
)
{
'111111111111'
}
let_it_be
(
:active_subscription
)
{
{
name:
'S-000000000'
}
}
before
do
allow
(
view
).
to
receive
(
:buy_addon_data
).
and_return
(
allow
(
view
).
to
receive
(
:buy_addon_data
).
with
(
@group
,
@account_id
,
@active_subscription
,
'storage-quota-tab'
,
s_
(
'Checkout|a storage subscription'
)).
and_return
(
active_subscription:
active_subscription
,
group_data:
'[{"id":"storage_plan_id","code":"storage","price_per_year":10.0}]'
,
namespace_id:
'2'
,
plan_id:
'storage_plan_id'
,
...
...
@@ -53,6 +64,7 @@ RSpec.shared_examples_for 'buy storage addon form data' do |js_selector|
subject
{
render
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-active-subscription-name='S-000000000']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-group-data='[{
\"
id
\"
:
\"
storage_plan_id
\"
,
\"
code
\"
:
\"
storage
\"
,
\"
price_per_year
\"
:10.0}]']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-plan-id='storage_plan_id']"
)
}
it
{
is_expected
.
to
have_selector
(
"
#{
js_selector
}
[data-namespace-id='2']"
)
}
...
...
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