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
adc61522
Commit
adc61522
authored
Apr 21, 2021
by
Vitaly Slobodin
Committed by
Scott Hampton
Apr 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create a copy of purchase a sub app based on GQL
parent
b011b740
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
889 additions
and
33 deletions
+889
-33
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
.../javascripts/subscriptions/buy_minutes/components/app.vue
+5
-1
ee/app/assets/javascripts/subscriptions/buy_minutes/components/checkout.vue
...scripts/subscriptions/buy_minutes/components/checkout.vue
+36
-0
ee/app/assets/javascripts/subscriptions/buy_minutes/components/checkout/subscription_details.vue
.../buy_minutes/components/checkout/subscription_details.vue
+241
-0
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/namespaces.query.graphql
...ions/buy_minutes/graphql/queries/namespaces.query.graphql
+0
-5
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/plans.query.graphql
...criptions/buy_minutes/graphql/queries/plans.query.graphql
+0
-3
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/seed.query.graphql
...scriptions/buy_minutes/graphql/queries/seed.query.graphql
+0
-9
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/resolvers.js
...avascripts/subscriptions/buy_minutes/graphql/resolvers.js
+12
-0
ee/app/assets/javascripts/subscriptions/buy_minutes/index.js
ee/app/assets/javascripts/subscriptions/buy_minutes/index.js
+44
-13
ee/app/assets/javascripts/subscriptions/graphql/mutations/update_state.mutation.graphql
...criptions/graphql/mutations/update_state.mutation.graphql
+3
-0
ee/app/assets/javascripts/subscriptions/graphql/queries/state.query.graphql
...scripts/subscriptions/graphql/queries/state.query.graphql
+38
-0
ee/spec/frontend/subscriptions/buy_minutes/components/checkout/subscription_details_spec.js
..._minutes/components/checkout/subscription_details_spec.js
+387
-0
ee/spec/frontend/subscriptions/buy_minutes/components/checkout_spec.js
...end/subscriptions/buy_minutes/components/checkout_spec.js
+77
-0
ee/spec/frontend/subscriptions/buy_minutes/graphql/resolvers_spec.js
...ntend/subscriptions/buy_minutes/graphql/resolvers_spec.js
+0
-0
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
+5
-2
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
+41
-0
No files found.
ee/app/assets/javascripts/subscriptions/buy_minutes/components/app.vue
View file @
adc61522
<
script
>
import
StepOrderApp
from
'
ee/vue_shared/purchase_flow/components/step_order_app.vue
'
;
import
Checkout
from
'
./checkout.vue
'
;
export
default
{
components
:
{
Checkout
,
StepOrderApp
,
},
};
</
script
>
<
template
>
<step-order-app>
<template
#checkout
></
template
>
<template
#checkout
>
<checkout
/>
</
template
>
<
template
#order-summary
></
template
>
</step-order-app>
</template>
ee/app/assets/javascripts/subscriptions/buy_minutes/components/checkout.vue
0 → 100644
View file @
adc61522
<
script
>
import
ProgressBar
from
'
ee/registrations/components/progress_bar.vue
'
;
import
{
STEPS
,
SUBSCRIPTON_FLOW_STEPS
}
from
'
ee/registrations/constants
'
;
import
STATE_QUERY
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
{
s__
}
from
'
~/locale
'
;
import
SubscriptionDetails
from
'
./checkout/subscription_details.vue
'
;
export
default
{
components
:
{
ProgressBar
,
SubscriptionDetails
},
apollo
:
{
state
:
{
query
:
STATE_QUERY
,
},
},
computed
:
{
isNewUser
()
{
return
this
.
state
.
isNewUser
;
},
},
currentStep
:
STEPS
.
checkout
,
steps
:
SUBSCRIPTON_FLOW_STEPS
,
i18n
:
{
checkout
:
s__
(
'
Checkout|Checkout
'
),
},
};
</
script
>
<
template
>
<div
class=
"checkout gl-flex gl-flex-column gl-justify-content-between w-100"
>
<div
class=
"full-width"
>
<progress-bar
v-if=
"isNewUser"
:steps=
"$options.steps"
:current-step=
"$options.currentStep"
/>
<div
class=
"flash-container"
></div>
<h2
class=
"gl-mt-4 gl-mb-3 gl-mb-lg-5"
>
{{
$options
.
i18n
.
checkout
}}
</h2>
<subscription-details
/>
</div>
</div>
</
template
>
ee/app/assets/javascripts/subscriptions/buy_minutes/components/checkout/subscription_details.vue
0 → 100644
View file @
adc61522
<
script
>
import
{
GlFormGroup
,
GlFormSelect
,
GlFormInput
,
GlSprintf
,
GlLink
}
from
'
@gitlab/ui
'
;
import
{
isEmpty
}
from
'
lodash
'
;
import
UPDATE_STATE
from
'
ee/subscriptions/graphql/mutations/update_state.mutation.graphql
'
;
import
STATE_QUERY
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
{
NEW_GROUP
,
STEPS
}
from
'
ee/subscriptions/new/constants
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
{
sprintf
,
s__
,
__
}
from
'
~/locale
'
;
import
autofocusonshow
from
'
~/vue_shared/directives/autofocusonshow
'
;
export
default
{
components
:
{
GlFormGroup
,
GlFormSelect
,
GlFormInput
,
GlSprintf
,
GlLink
,
Step
,
},
directives
:
{
autofocusonshow
,
},
apollo
:
{
state
:
{
query
:
STATE_QUERY
,
},
},
computed
:
{
subscription
()
{
return
this
.
state
.
subscription
;
},
plans
()
{
return
this
.
state
.
plans
;
},
namespaces
()
{
return
this
.
state
.
namespaces
;
},
selectedPlanModel
:
{
get
()
{
return
this
.
subscription
.
planId
;
},
set
(
planId
)
{
this
.
updateSubscription
({
subscription
:
{
planId
}
});
},
},
selectedGroupModel
:
{
get
()
{
return
this
.
subscription
.
namespaceId
;
},
set
(
namespaceId
)
{
const
quantity
=
this
.
namespaces
.
find
((
namespace
)
=>
namespace
.
id
===
namespaceId
)?.
users
||
1
;
this
.
updateSubscription
({
subscription
:
{
namespaceId
,
quantity
}
});
},
},
numberOfUsersModel
:
{
get
()
{
return
this
.
selectedGroupUsers
||
1
;
},
set
(
number
)
{
this
.
updateSubscription
({
subscription
:
{
quantity
:
number
}
});
},
},
companyModel
:
{
get
()
{
return
this
.
state
.
customer
.
company
;
},
set
(
company
)
{
this
.
updateSubscription
({
customer
:
{
company
}
});
},
},
selectedPlan
()
{
return
this
.
state
.
plans
.
find
((
plan
)
=>
plan
.
code
===
this
.
subscription
.
planId
);
},
selectedPlanTextLine
()
{
return
sprintf
(
this
.
$options
.
i18n
.
selectedPlan
,
{
selectedPlanText
:
this
.
selectedPlan
.
code
});
},
selectedGroupUsers
()
{
return
(
this
.
namespaces
.
find
((
namespace
)
=>
namespace
.
id
===
this
.
subscription
.
namespaceId
)
?.
users
||
1
);
},
isGroupSelected
()
{
return
this
.
subscription
.
namespaceId
!==
null
;
},
isNumberOfUsersValid
()
{
return
(
this
.
subscription
.
quantity
>
0
&&
this
.
subscription
.
quantity
>=
this
.
selectedGroupUsers
);
},
isValid
()
{
if
(
this
.
state
.
isSetupForCompany
)
{
return
(
!
isEmpty
(
this
.
subscription
.
planId
)
&&
(
!
isEmpty
(
this
.
state
.
customer
.
company
)
||
this
.
isNewGroupSelected
)
&&
this
.
isNumberOfUsersValid
);
}
return
!
isEmpty
(
this
.
subscription
.
planId
)
&&
this
.
subscription
.
quantity
===
1
;
},
isShowingGroupSelector
()
{
return
!
this
.
state
.
isNewUser
&&
this
.
namespaces
.
length
;
},
isNewGroupSelected
()
{
return
this
.
subscription
.
namespaceId
===
NEW_GROUP
;
},
isShowingNameOfCompanyInput
()
{
return
this
.
state
.
isSetupForCompany
&&
(
!
this
.
namespaces
.
length
||
this
.
isNewGroupSelected
);
},
groupOptionsWithDefault
()
{
return
[
{
name
:
this
.
$options
.
i18n
.
groupSelectPrompt
,
id
:
null
,
},
...
this
.
namespaces
,
{
name
:
this
.
$options
.
i18n
.
groupSelectCreateNewOption
,
id
:
NEW_GROUP
,
},
];
},
groupSelectDescription
()
{
return
this
.
isNewGroupSelected
?
this
.
$options
.
i18n
.
createNewGroupDescription
:
this
.
$options
.
i18n
.
selectedGroupDescription
;
},
},
methods
:
{
updateSubscription
(
payload
=
{})
{
this
.
$apollo
.
mutate
({
mutation
:
UPDATE_STATE
,
variables
:
{
input
:
payload
,
},
});
},
toggleIsSetupForCompany
()
{
this
.
updateSubscription
({
isSetupForCompany
:
!
this
.
state
.
isSetupForCompany
});
},
},
i18n
:
{
stepTitle
:
s__
(
'
Checkout|Subscription details
'
),
nextStepButtonText
:
s__
(
'
Checkout|Continue to billing
'
),
selectedPlanLabel
:
s__
(
'
Checkout|GitLab plan
'
),
selectedGroupLabel
:
s__
(
'
Checkout|GitLab group
'
),
groupSelectPrompt
:
__
(
'
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
'
),
numberOfUsersLabel
:
s__
(
'
Checkout|Number of users
'
),
needMoreUsersLink
:
s__
(
'
Checkout|Need more users? Purchase GitLab for your %{company}.
'
),
companyOrTeam
:
s__
(
'
Checkout|company or team
'
),
selectedPlan
:
s__
(
'
Checkout|%{selectedPlanText} plan
'
),
group
:
__
(
'
Group
'
),
users
:
__
(
'
Users
'
),
},
stepId
:
STEPS
[
0
].
id
,
};
</
script
>
<
template
>
<step
:step-id=
"$options.stepId"
:title=
"$options.i18n.stepTitle"
:is-valid=
"isValid"
:next-step-button-text=
"$options.i18n.nextStepButtonText"
>
<template
#body
>
<gl-form-group
:label=
"$options.i18n.selectedPlanLabel"
label-size=
"sm"
class=
"mb-3"
>
<gl-form-select
v-model=
"selectedPlanModel"
v-autofocusonshow
:options=
"plans"
value-field=
"code"
text-field=
"name"
data-qa-selector=
"plan_name"
/>
</gl-form-group>
<gl-form-group
v-if=
"isShowingGroupSelector"
:label=
"$options.i18n.selectedGroupLabel"
:description=
"groupSelectDescription"
label-size=
"sm"
class=
"mb-3"
>
<gl-form-select
ref=
"group-select"
v-model=
"selectedGroupModel"
:options=
"groupOptionsWithDefault"
value-field=
"id"
text-field=
"name"
data-qa-selector=
"group_name"
/>
</gl-form-group>
<gl-form-group
v-if=
"isShowingNameOfCompanyInput"
:label=
"$options.i18n.organizationNameLabel"
label-size=
"sm"
class=
"mb-3"
>
<gl-form-input
ref=
"organization-name"
v-model=
"companyModel"
type=
"text"
/>
</gl-form-group>
<div
class=
"combined d-flex"
>
<gl-form-group
:label=
"$options.i18n.numberOfUsersLabel"
label-size=
"sm"
class=
"number"
>
<gl-form-input
ref=
"number-of-users"
v-model.number=
"numberOfUsersModel"
type=
"number"
:min=
"selectedGroupUsers"
:disabled=
"!state.isSetupForCompany"
data-qa-selector=
"number_of_users"
/>
</gl-form-group>
<gl-form-group
v-if=
"!state.isSetupForCompany"
ref=
"company-link"
class=
"label ml-3 align-self-end"
>
<gl-sprintf
:message=
"$options.i18n.needMoreUsersLink"
>
<template
#company
>
<gl-link
@
click=
"toggleIsSetupForCompany"
>
{{
$options
.
i18n
.
companyOrTeam
}}
</gl-link>
</
template
>
</gl-sprintf>
</gl-form-group>
</div>
</template>
<
template
#summary
>
<strong
ref=
"summary-line-1"
>
{{
selectedPlanTextLine
}}
</strong>
<div
v-if=
"state.isSetupForCompany"
ref=
"summary-line-2"
>
{{
$options
.
i18n
.
group
}}
:
{{
customer
.
company
||
selectedGroupName
}}
</div>
<div
ref=
"summary-line-3"
>
{{
$options
.
i18n
.
users
}}
:
{{
subscription
.
quantity
}}
</div>
</
template
>
</step>
</template>
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/namespaces.query.graphql
deleted
100644 → 0
View file @
b011b740
query
getNamespaces
{
namespaces
@client
{
id
}
}
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/plans.query.graphql
deleted
100644 → 0
View file @
b011b740
query
getPlans
{
plans
@client
}
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/queries/seed.query.graphql
deleted
100644 → 0
View file @
b011b740
query
seed
{
seed
@client
{
plans
namespaces
newUser
fullName
setupForCompany
}
}
ee/app/assets/javascripts/subscriptions/buy_minutes/graphql/resolvers.js
View file @
adc61522
import
{
produce
}
from
'
immer
'
;
import
{
merge
}
from
'
lodash
'
;
import
Api
from
'
ee/api
'
;
import
*
as
SubscriptionsApi
from
'
ee/api/subscriptions_api
'
;
import
{
ERROR_FETCHING_COUNTRIES
,
ERROR_FETCHING_STATES
}
from
'
ee/subscriptions/constants
'
;
import
STATE_QUERY
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
createFlash
from
'
~/flash
'
;
// NOTE: These resolvers are temporary and will be removed in the future.
...
...
@@ -30,5 +33,14 @@ export const resolvers = {
purchaseMinutes
:
(
_
,
{
groupId
,
customer
,
subscription
})
=>
{
return
SubscriptionsApi
.
createSubscription
(
groupId
,
customer
,
subscription
);
},
updateState
:
(
_
,
{
input
},
{
cache
})
=>
{
const
{
state
:
oldState
}
=
cache
.
readQuery
({
query
:
STATE_QUERY
});
const
state
=
produce
(
oldState
,
(
draftState
)
=>
{
merge
(
draftState
,
input
);
});
cache
.
writeQuery
({
query
:
STATE_QUERY
,
data
:
{
state
}
});
},
},
};
ee/app/assets/javascripts/subscriptions/buy_minutes/index.js
View file @
adc61522
import
Vue
from
'
vue
'
;
import
App
from
'
ee/subscriptions/buy_minutes/components/app.vue
'
;
import
{
STEPS
}
from
'
ee/subscriptions/new/constants
'
;
import
ensureData
from
'
~/ensure_data
'
;
import
{
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
App
from
'
./components/app.vue
'
;
import
{
convertObjectPropsToCamelCase
,
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
stateQuery
from
'
../graphql/queries/state.query.graphql
'
;
import
apolloProvider
from
'
./graphql
'
;
import
seedQuery
from
'
./graphql/queries/seed.query.graphql
'
;
import
{
parseData
}
from
'
./utils
'
;
const
arrayToGraphqlArray
=
(
arr
,
typename
)
=>
Array
.
from
(
arr
,
(
item
)
=>
Object
.
assign
(
item
,
{
__typename
:
typename
}));
Array
.
from
(
arr
,
(
item
)
=>
Object
.
assign
(
convertObjectPropsToCamelCase
(
item
,
{
deep
:
true
}),
{
__typename
:
typename
}),
);
const
writeInitialDataToApolloProvider
=
(
dataset
)
=>
{
const
{
newUser
,
fullName
,
setupForCompany
}
=
dataset
;
// eslint-disable-next-line @gitlab/require-i18n-strings
const
plans
=
arrayToGraphqlArray
(
JSON
.
parse
(
dataset
.
ciMinutesPlans
),
'
Plan
'
);
// eslint-disable-next-line @gitlab/require-i18n-strings
const
namespaces
=
arrayToGraphqlArray
(
JSON
.
parse
(
dataset
.
groupData
),
'
Namespace
'
);
const
isNewUser
=
parseBoolean
(
dataset
.
newUser
);
const
isSetupForCompany
=
parseBoolean
(
dataset
.
setupForCompany
)
||
!
isNewUser
;
apolloProvider
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
s
eed
Query
,
query
:
s
tate
Query
,
data
:
{
// eslint-disable-next-line @gitlab/require-i18n-strings
plans
:
arrayToGraphqlArray
(
JSON
.
parse
(
dataset
.
ciMinutesPlans
),
'
Plan
'
),
// eslint-disable-next-line @gitlab/require-i18n-strings
namespaces
:
arrayToGraphqlArray
(
JSON
.
parse
(
dataset
.
groupData
),
'
Namespace
'
),
newUser
:
parseBoolean
(
newUser
),
setupForCompany
:
parseBoolean
(
setupForCompany
),
fullName
,
state
:
{
isNewUser
,
isSetupForCompany
,
plans
,
namespaces
,
fullName
:
dataset
.
fullName
,
subscription
:
{
planId
:
plans
[
0
].
code
,
paymentMethodId
:
null
,
quantity
:
1
,
namespaceId
:
null
,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename
:
'
Subscription
'
,
},
customer
:
{
country
:
null
,
address1
:
null
,
address2
:
null
,
city
:
null
,
state
:
null
,
zipCode
:
null
,
company
:
null
,
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename
:
'
Customer
'
,
},
// eslint-disable-next-line @gitlab/require-i18n-strings
__typename
:
'
State
'
,
},
activeStep
:
STEPS
[
0
],
stepList
:
STEPS
,
},
});
};
...
...
ee/app/assets/javascripts/subscriptions/graphql/mutations/update_state.mutation.graphql
0 → 100644
View file @
adc61522
mutation
UpdateState
(
$input
:
UpdateStateInput
!)
{
updateState
(
input
:
$input
)
@client
}
ee/app/assets/javascripts/subscriptions/graphql/queries/state.query.graphql
0 → 100644
View file @
adc61522
query
state
{
state
@client
{
plans
{
name
code
pricePerYear
}
namespaces
{
id
name
users
}
isNewUser
fullName
isSetupForCompany
customer
{
country
address1
address2
city
state
zipCode
company
}
subscription
{
planId
paymentMethodId
quantity
namespaceId
}
}
activeStep
@client
{
id
}
stepList
@client
{
id
}
}
ee/spec/frontend/subscriptions/buy_minutes/components/checkout/subscription_details_spec.js
0 → 100644
View file @
adc61522
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
merge
}
from
'
lodash
'
;
import
{
nextTick
}
from
'
vue
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
SubscriptionDetails
from
'
ee/subscriptions/buy_minutes/components/checkout/subscription_details.vue
'
;
import
subscriptionsResolvers
from
'
ee/subscriptions/buy_minutes/graphql/resolvers
'
;
import
stateQuery
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
{
NEW_GROUP
}
from
'
ee/subscriptions/new/constants
'
;
import
Step
from
'
ee/vue_shared/purchase_flow/components/step.vue
'
;
import
purchaseFlowResolvers
from
'
ee/vue_shared/purchase_flow/graphql/resolvers
'
;
import
{
stateData
as
initialStateData
,
namespaces
as
defaultNamespaces
,
}
from
'
ee_jest/subscriptions/buy_minutes/mock_data
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
describe
(
'
Subscription Details
'
,
()
=>
{
const
resolvers
=
{
...
purchaseFlowResolvers
,
...
subscriptionsResolvers
};
let
wrapper
;
const
createMockApolloProvider
=
(
stateData
=
{})
=>
{
const
mockApollo
=
createMockApollo
([],
resolvers
);
const
data
=
merge
({},
initialStateData
,
stateData
);
mockApollo
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
stateQuery
,
data
,
});
return
mockApollo
;
};
const
createComponent
=
(
stateData
=
{})
=>
{
const
apolloProvider
=
createMockApolloProvider
(
stateData
);
return
mount
(
SubscriptionDetails
,
{
localVue
,
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
'
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
(
'
A new user setting up for personal use
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isNewUser
:
true
,
isSetupForCompany
:
false
}
});
});
it
(
'
should not display an input field for the company or group name
'
,
()
=>
{
expect
(
organizationNameInput
().
exists
()).
toBe
(
false
);
});
it
(
'
should not display the group select
'
,
()
=>
{
expect
(
groupSelect
().
exists
()).
toBe
(
false
);
});
it
(
'
should disable the number of users input field
'
,
()
=>
{
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
'
,
()
=>
{
expect
(
companyLink
().
exists
()).
toBe
(
true
);
});
});
describe
(
'
A new user setting up for a company or group
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isNewUser
:
true
,
isSetupForCompany
:
true
,
namespaces
:
[]
},
});
});
it
(
'
should display an input field for the company or group name
'
,
()
=>
{
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
'
,
()
=>
{
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
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isNewUser
:
false
,
namespaces
:
[]
},
});
});
it
(
'
should display an input field for the company or group name
'
,
()
=>
{
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
'
,
()
=>
{
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 with groups
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isNewUser
:
false
,
namespaces
:
defaultNamespaces
}
});
});
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
(()
=>
{
wrapper
=
createComponent
({
state
:
{
subscription
:
{
namespaceId
:
483
},
namespaces
:
defaultNamespaces
},
});
});
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
(
'
selecting "Create a new group
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
subscription
:
{
namespaceId
:
NEW_GROUP
},
namespaces
:
defaultNamespaces
},
});
});
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
(
'
An existing user coming from group billing page
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isNewUser
:
false
,
isSetupForCompany
:
true
,
subscription
:
{
namespaceId
:
132
},
namespaces
:
defaultNamespaces
,
},
});
});
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 3
'
,
()
=>
{
expect
(
numberOfUsersInput
().
attributes
(
'
min
'
)).
toBe
(
'
3
'
);
});
it
(
'
should set the selected group to initial namespace id
'
,
()
=>
{
expect
(
groupSelect
().
element
.
value
).
toBe
(
'
132
'
);
});
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
(()
=>
{
wrapper
=
createComponent
({
state
:
{
subscription
:
{
namespaceId
:
483
},
namespaces
:
defaultNamespaces
},
});
});
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
'
);
});
it
(
'
should set the selected group to the user selected namespace id
'
,
()
=>
{
expect
(
groupSelect
().
element
.
value
).
toBe
(
'
483
'
);
});
});
});
describe
(
'
validations
'
,
()
=>
{
const
isStepValid
=
()
=>
wrapper
.
find
(
Step
).
props
(
'
isValid
'
);
describe
(
'
when setting up for a company
'
,
()
=>
{
it
(
'
should be valid
'
,
()
=>
{
wrapper
=
createComponent
({
state
:
{
subscription
:
{
planId
:
'
firstPlanId
'
,
namespaceId
:
483
,
quantity
:
14
},
customer
:
{
company
:
'
Organization name
'
},
},
});
expect
(
isStepValid
()).
toBe
(
true
);
});
it
(
'
should be invalid when no plan is selected
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
true
,
subscription
:
{
planId
:
null
,
namespaceId
:
483
,
quantity
:
14
},
customer
:
{
company
:
'
Organization name
'
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
it
(
'
should be invalid when no organization name is given, and no group is selected
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
true
,
subscription
:
{
namespaceId
:
null
},
customer
:
{
company
:
null
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
it
(
'
should be invalid when number of users is 0
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
true
,
subscription
:
{
quantity
:
0
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
it
(
'
should be invalid when number of users is smaller than the selected group users
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
true
,
subscription
:
{
namespaceId
:
483
,
quantity
:
10
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
});
describe
(
'
when not setting up for a company
'
,
()
=>
{
beforeEach
(()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
false
,
subscription
:
{
planId
:
'
firstPlanId
'
,
namespaceId
:
483
,
quantity
:
1
},
customer
:
{
company
:
'
Organization name
'
},
},
});
});
it
(
'
should be valid
'
,
()
=>
{
expect
(
isStepValid
()).
toBe
(
true
);
});
it
(
'
should be invalid when no plan is selected
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
false
,
subscription
:
{
planId
:
null
,
namespaceId
:
483
,
quantity
:
1
},
customer
:
{
company
:
'
Organization name
'
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
it
(
'
should be invalid when no number of users is 0
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
false
,
subscription
:
{
planId
:
'
firstPlanId
'
,
namespaceId
:
483
,
quantity
:
0
},
customer
:
{
company
:
'
Organization name
'
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
it
(
'
should be invalid when no number of users is greater than 1
'
,
async
()
=>
{
wrapper
=
createComponent
({
state
:
{
isSetupForCompany
:
false
,
subscription
:
{
planId
:
'
firstPlanId
'
,
namespaceId
:
483
,
quantity
:
2
},
customer
:
{
company
:
'
Organization name
'
},
},
});
await
nextTick
();
expect
(
isStepValid
()).
toBe
(
false
);
});
});
});
});
ee/spec/frontend/subscriptions/buy_minutes/components/checkout_spec.js
0 → 100644
View file @
adc61522
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
merge
}
from
'
lodash
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
ProgressBar
from
'
ee/registrations/components/progress_bar.vue
'
;
import
Checkout
from
'
ee/subscriptions/buy_minutes/components/checkout.vue
'
;
import
subscriptionsResolvers
from
'
ee/subscriptions/buy_minutes/graphql/resolvers
'
;
import
stateQuery
from
'
ee/subscriptions/graphql/queries/state.query.graphql
'
;
import
purchaseFlowResolvers
from
'
ee/vue_shared/purchase_flow/graphql/resolvers
'
;
import
{
stateData
as
initialStateData
}
from
'
ee_jest/subscriptions/buy_minutes/mock_data
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
const
localVue
=
createLocalVue
();
localVue
.
use
(
VueApollo
);
describe
(
'
Checkout
'
,
()
=>
{
const
resolvers
=
{
...
purchaseFlowResolvers
,
...
subscriptionsResolvers
};
let
wrapper
;
const
createMockApolloProvider
=
(
stateData
=
{})
=>
{
const
mockApollo
=
createMockApollo
([],
resolvers
);
const
data
=
merge
({},
initialStateData
,
stateData
);
mockApollo
.
clients
.
defaultClient
.
cache
.
writeQuery
({
query
:
stateQuery
,
data
,
});
return
mockApollo
;
};
const
createComponent
=
(
stateData
=
{})
=>
{
const
apolloProvider
=
createMockApolloProvider
(
stateData
);
wrapper
=
shallowMount
(
Checkout
,
{
apolloProvider
,
localVue
,
});
};
const
findProgressBar
=
()
=>
wrapper
.
find
(
ProgressBar
);
afterEach
(()
=>
{
wrapper
.
destroy
();
});
describe
.
each
([
[
true
,
true
],
[
false
,
false
],
])(
'
when isNewUser=%s
'
,
(
isNewUser
,
visible
)
=>
{
beforeEach
(()
=>
{
createComponent
({
state
:
{
isNewUser
}
});
});
it
(
`progress bar visibility is
${
visible
}
`
,
()
=>
{
expect
(
findProgressBar
().
exists
()).
toBe
(
visible
);
});
});
describe
(
'
passing the correct options to the progress bar component
'
,
()
=>
{
beforeEach
(()
=>
{
createComponent
({
state
:
{
isNewUser
:
true
}
});
});
it
(
'
passes the steps
'
,
()
=>
{
expect
(
findProgressBar
().
props
(
'
steps
'
)).
toEqual
([
'
Your profile
'
,
'
Checkout
'
,
'
Your GitLab group
'
,
]);
});
it
(
'
passes the current step
'
,
()
=>
{
expect
(
findProgressBar
().
props
(
'
currentStep
'
)).
toEqual
(
'
Checkout
'
);
});
});
});
ee/spec/frontend/subscriptions/graphql/resolvers_spec.js
→
ee/spec/frontend/subscriptions/
buy_minutes/
graphql/resolvers_spec.js
View file @
adc61522
File moved
ee/spec/frontend/subscriptions/buy_minutes/index_spec.js
View file @
adc61522
import
{
GlEmptyState
}
from
'
@gitlab/ui
'
;
import
*
as
Sentry
from
'
@sentry/browser
'
;
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/purchase_flow/components/step_order_app.vue
'
;
...
...
@@ -15,7 +14,11 @@ describe('initBuyMinutesApp', () => {
function
createComponent
()
{
const
el
=
document
.
createElement
(
'
div
'
);
Object
.
assign
(
el
.
dataset
,
{
ciMinutesPlans
:
mockCiMinutesPlans
,
groupData
:
'
[]
'
});
Object
.
assign
(
el
.
dataset
,
{
ciMinutesPlans
:
mockCiMinutesPlans
,
groupData
:
'
[]
'
,
fullName
:
'
GitLab
'
,
});
vm
=
initBuyMinutesApp
(
el
).
$mount
();
wrapper
=
createWrapper
(
vm
);
}
...
...
ee/spec/frontend/subscriptions/buy_minutes/mock_data.js
View file @
adc61522
import
{
STEPS
}
from
'
ee/subscriptions/new/constants
'
;
export
const
mockCiMinutesPlans
=
'
[{"deprecated":false,"name":"1000 CI minutes pack","code":"ci_minutes","active":true,"free":null,"price_per_month":0.8333333333333334,"price_per_year":10.0,"features":null,"about_page_href":null,"hide_deprecated_card":false}]
'
;
export
const
mockParsedCiMinutesPlans
=
[
...
...
@@ -14,3 +16,42 @@ export const mockParsedCiMinutesPlans = [
hideDeprecatedCard
:
false
,
},
];
export
const
namespaces
=
[
{
id
:
132
,
name
:
'
My first group
'
,
users
:
3
,
__typename
:
'
Namespace
'
},
{
id
:
483
,
name
:
'
My second group
'
,
users
:
12
,
__typename
:
'
Namespace
'
},
];
export
const
plans
=
[
{
id
:
'
firstPlanId
'
,
code
:
'
bronze
'
,
pricePerYear
:
48
,
name
:
'
bronze
'
,
__typename
:
'
Plan
'
},
{
id
:
'
secondPlanId
'
,
code
:
'
silver
'
,
pricePerYear
:
228
,
name
:
'
silver
'
,
__typename
:
'
Plan
'
},
];
export
const
stateData
=
{
state
:
{
plans
,
namespaces
:
[],
subscription
:
{
planId
:
'
secondPlanId
'
,
quantity
:
1
,
namespaceId
:
null
,
paymentMethodId
:
null
,
__typename
:
'
Subscription
'
,
},
customer
:
{
country
:
null
,
address1
:
null
,
address2
:
null
,
city
:
null
,
state
:
null
,
zipCode
:
null
,
company
:
null
,
__typename
:
'
Customer
'
,
},
fullName
:
'
Full Name
'
,
isNewUser
:
false
,
isSetupForCompany
:
true
,
},
stepList
:
STEPS
,
activeStep
:
STEPS
[
0
],
};
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