Merge pull request #22448 from overleaf/ii-flexible-group-licensing-add-seats-tests

[web] Add seats tests

GitOrigin-RevId: 76fb5edc6eba5579fac2d3e05cd1f64fba16046c
This commit is contained in:
ilkin-overleaf
2024-12-17 11:22:35 +02:00
committed by Copybot
parent 4285a00e2e
commit 1be593f612
7 changed files with 769 additions and 17 deletions

View File

@@ -171,12 +171,12 @@ async function previewAddSeatsSubscriptionChange(req, res) {
*/
async function createAddSeatsSubscriptionChange(req, res) {
try {
const preview =
const create =
await SubscriptionGroupHandler.promises.createAddSeatsSubscriptionChange(
req
)
res.json(preview)
res.json(create)
} catch (error) {
logger.err(
{ error },

View File

@@ -29,7 +29,7 @@ import {
} from '../../../../../../types/subscription/subscription-change-preview'
import { MergeAndOverride } from '../../../../../../types/utils'
const MAX_NUMBER_OF_USERS = 50
export const MAX_NUMBER_OF_USERS = 50
function AddSeats() {
const { t } = useTranslation()
@@ -244,6 +244,7 @@ function AddSeats() {
className="d-grid gap-4"
onSubmit={handleSubmit}
ref={formRef}
data-testid="add-more-users-group-form"
>
<div className="d-grid gap-1">
<h4 className="fw-bold m-0 card-description-secondary">

View File

@@ -20,7 +20,10 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
const { t } = useTranslation()
return (
<Card className="card-gray card-description-secondary">
<Card
className="card-gray card-description-secondary"
data-testid="cost-summary"
>
<Card.Body className="d-grid gap-2 p-3">
<div>
<div className="fw-bold">{t('cost_summary')}</div>
@@ -53,35 +56,44 @@ function CostSummary({ subscriptionChange, totalLicenses }: CostSummaryProps) {
<>
<div>
<ListGroup>
<ListGroup.Item className="bg-transparent border-0 px-0 gap-3 card-description-secondary">
<ListGroup.Item
className="bg-transparent border-0 px-0 gap-3 card-description-secondary"
data-testid="plan"
>
<span className="me-auto">
{subscriptionChange.nextInvoice.plan.name} x{' '}
{subscriptionChange.change.addOn.quantity -
subscriptionChange.change.addOn.prevQuantity}{' '}
{t('seats')}
</span>
<span>
<span data-testid="price">
{formatCurrencyLocalized(
subscriptionChange.immediateCharge.subtotal,
subscriptionChange.currency
)}
</span>
</ListGroup.Item>
<ListGroup.Item className="bg-transparent border-0 px-0 gap-3 card-description-secondary">
<ListGroup.Item
className="bg-transparent border-0 px-0 gap-3 card-description-secondary"
data-testid="tax"
>
<span className="me-auto">
{t('sales_tax')} &middot;{' '}
{subscriptionChange.nextInvoice.tax.rate * 100}%
</span>
<span>
<span data-testid="price">
{formatCurrencyLocalized(
subscriptionChange.immediateCharge.tax,
subscriptionChange.currency
)}
</span>
</ListGroup.Item>
<ListGroup.Item className="bg-transparent border-0 px-0 gap-3 card-description-secondary">
<ListGroup.Item
className="bg-transparent border-0 px-0 gap-3 card-description-secondary"
data-testid="total"
>
<strong className="me-auto">{t('total_due_today')}</strong>
<strong>
<strong data-testid="price">
{formatCurrencyLocalized(
subscriptionChange.immediateCharge.total,
subscriptionChange.currency

View File

@@ -0,0 +1,351 @@
import '../../../helpers/bootstrap-5'
import AddSeats, {
MAX_NUMBER_OF_USERS,
} from '@/features/group-management/components/add-seats/add-seats'
import { SplitTestProvider } from '@/shared/context/split-test-context'
describe('<AddSeats />', function () {
beforeEach(function () {
this.totalLicenses = 5
cy.window().then(win => {
win.metaAttributesCache.set('ol-groupName', 'My Awesome Team')
win.metaAttributesCache.set('ol-subscriptionId', '123')
win.metaAttributesCache.set(
'ol-subscriptionEndsAt',
'2025-01-01T12:00:00.000Z'
)
win.metaAttributesCache.set('ol-totalLicenses', this.totalLicenses)
})
cy.mount(
<SplitTestProvider>
<AddSeats />
</SplitTestProvider>
)
cy.findByRole('button', { name: /add users/i })
cy.findByTestId('add-more-users-group-form')
})
it('renders the back button', function () {
cy.findByTestId('group-heading').within(() => {
cy.findByRole('button', { name: /back to subscription/i }).should(
'have.attr',
'href',
'/user/subscription'
)
})
})
it('shows the group name', function () {
cy.findByTestId('group-heading').within(() => {
cy.findByRole('heading', { name: 'My Awesome Team' })
})
})
it('shows the "Add more users" label', function () {
cy.findByText(/add more users/i)
})
it('shows the maximum supported users', function () {
cy.findByText(
new RegExp(
`your current plan supports up to ${this.totalLicenses} users`,
'i'
)
)
})
it('shows instructions on how to reduce users on a plan', function () {
cy.contains(
/if you want to reduce the number of users on your plan, please contact customer support/i
).within(() => {
cy.findByRole('link', { name: /contact customer support/i }).should(
'have.attr',
'href',
'/contact'
)
})
})
it('shows the "Upgrade my plan" link', function () {
cy.findByRole('link', { name: /upgrade my plan/i }).should(
'have.attr',
'href',
'/user/subscription/group/upgrade-subscription'
)
})
it('renders the cancel button', function () {
cy.findByRole('button', { name: /cancel/i }).should(
'have.attr',
'href',
'/user/subscription'
)
})
describe('cost summary', function () {
beforeEach(function () {
cy.findByLabelText(/how many users do you want to add/i).as('input')
})
it('shows the title', function () {
cy.findByTestId('cost-summary').within(() => {
cy.findByText(/cost summary/i)
})
})
describe('shows default content when', function () {
afterEach(function () {
cy.findByTestId('cost-summary').within(() => {
cy.findByText(
/enter the number of users youd like to add to see the cost breakdown/i
)
})
})
it('leaves input empty', function () {
cy.get('@input').should('have.value', '')
})
it('fills in a non-numeric value', function () {
cy.get('@input').type('ab')
cy.findByText(/value must be a number/i)
})
it('fills in a decimal value', function () {
cy.get('@input').type('1.5')
cy.findByText(/value must be a whole number/i)
})
it('fills in a "0" value', function () {
cy.get('@input').type('0')
cy.findByText(/value must be at least 1/i)
})
it('fills in a value and clears the input', function () {
cy.get('@input').type('a{backspace}')
cy.get('@input').should('have.text', '')
cy.findByText(/this field is required/i)
})
})
describe('entered more than the maximum allowed number of users', function () {
beforeEach(function () {
this.numberOfUsersExceedingMaxLimit = MAX_NUMBER_OF_USERS + 1
cy.get('@input').type(this.numberOfUsersExceedingMaxLimit.toString())
cy.findByRole('button', { name: /add users/i }).should('not.exist')
cy.findByRole('button', { name: /send request/i }).as('sendRequestBtn')
})
it('renders a notification', function () {
cy.findByTestId('cost-summary').should('not.exist')
cy.findByRole('alert').should(
'contain.text',
`If you want more than ${MAX_NUMBER_OF_USERS} users on your plan, we need to add them for you. Just click Send request below and well be happy to help.`
)
})
describe('request', function () {
afterEach(function () {
cy.findByRole('button', { name: /go to subscriptions/i }).should(
'have.attr',
'href',
'/user/subscription'
)
})
function makeRequest(statusCode: number, adding: string) {
cy.intercept(
'POST',
'/user/subscription/group/add-users/sales-contact-form',
{
statusCode,
}
).as('addUsersRequest')
cy.get('@sendRequestBtn').click()
cy.get('@addUsersRequest').its('request.body').should('deep.equal', {
adding,
})
cy.findByTestId('add-more-users-group-form').should('not.exist')
}
it('sends a request that succeeds', function () {
makeRequest(204, this.numberOfUsersExceedingMaxLimit.toString())
cy.findByTestId('title').should(
'contain.text',
'Weve got your request'
)
cy.findByText(/our team will get back to you shortly/i)
})
it('sends a request that fails', function () {
makeRequest(400, this.numberOfUsersExceedingMaxLimit.toString())
cy.findByTestId('title').should(
'contain.text',
'Something went wrong'
)
cy.contains(
/it looks like that didnt work. You can try again or get in touch with our Support team for more help/i
).within(() => {
cy.findByRole('link', { name: /get in touch/i }).should(
'have.attr',
'href',
'/contact'
)
})
})
})
})
describe('entered less than the maximum allowed number of users', function () {
beforeEach(function () {
this.adding = 1
cy.findByRole('button', { name: /add users/i }).as('addUsersBtn')
cy.findByRole('button', { name: /send request/i }).should('not.exist')
})
it('renders the preview data', function () {
this.body = {
change: {
type: 'add-on-update',
addOn: {
code: 'additional-license',
quantity: this.totalLicenses + this.adding,
prevQuantity: this.totalLicenses,
},
},
currency: 'USD',
immediateCharge: {
subtotal: 100,
tax: 20,
total: 120,
},
nextInvoice: {
date: '2025-12-01T00:00:00.000Z',
plan: {
name: 'Overleaf Standard Group',
amount: 0,
},
subtotal: 895,
tax: {
rate: 0.2,
},
total: 1000,
},
}
cy.intercept('POST', '/user/subscription/group/add-users/preview', {
statusCode: 200,
body: this.body,
}).as('addUsersRequest')
cy.get('@input').type(this.adding.toString())
cy.findByTestId('cost-summary').within(() => {
cy.contains(
new RegExp(
`youre adding ${this.adding} users to your plan giving you a total of ${this.body.change.addOn.quantity} users`,
'i'
)
)
cy.findByTestId('plan').within(() => {
cy.findByText(
`${this.body.nextInvoice.plan.name} x ${this.adding} Seats`
)
cy.findByTestId('price').should(
'have.text',
`$${this.body.immediateCharge.subtotal}.00`
)
})
cy.findByTestId('tax').within(() => {
cy.findByText(
new RegExp(
`sales tax · ${this.body.nextInvoice.tax.rate * 100}%`,
'i'
)
)
cy.findByTestId('price').should(
'have.text',
`$${this.body.immediateCharge.tax}.00`
)
})
cy.findByTestId('total').within(() => {
cy.findByText(/total due today/i)
cy.findByTestId('price').should(
'have.text',
`$${this.body.immediateCharge.total}.00`
)
})
cy.findByText(
/well charge you now for the cost of your additional users based on the remaining months of your current subscription/i
)
cy.findByText(
/after that, well bill you \$1,000.00 \+ applicable taxes annually on December 1, unless you cancel/i
)
})
})
describe('request', function () {
afterEach(function () {
cy.findByRole('button', { name: /go to subscriptions/i }).should(
'have.attr',
'href',
'/user/subscription'
)
})
function makeRequest(statusCode: number, adding: string) {
cy.intercept('POST', '/user/subscription/group/add-users/create', {
statusCode,
}).as('addUsersRequest')
cy.get('@input').type(adding)
cy.get('@addUsersBtn').click()
cy.get('@addUsersRequest')
.its('request.body')
.should('deep.equal', {
adding: Number(adding),
})
cy.findByTestId('add-more-users-group-form').should('not.exist')
}
it('sends a request that succeeds', function () {
makeRequest(204, this.adding.toString())
cy.findByTestId('title').should(
'contain.text',
'Youve added more users'
)
cy.findByText(/youve added more users to your subscription/i)
cy.findByRole('link', { name: /invite people/i }).should(
'have.attr',
'href',
'/manage/groups/123/members'
)
})
it('sends a request that fails', function () {
makeRequest(400, this.adding.toString())
cy.findByTestId('title').should(
'contain.text',
'Something went wrong'
)
cy.contains(
/it looks like that didnt work. You can try again or get in touch with our Support team for more help/i
).within(() => {
cy.findByRole('link', { name: /get in touch/i }).should(
'have.attr',
'href',
'/contact'
)
})
})
})
})
})
})

View File

@@ -1,7 +1,7 @@
import '../../../helpers/bootstrap-5'
import RequestStatus from '@/features/group-management/components/request-status'
describe('request confirmation page', function () {
describe('<RequestStatus />', function () {
beforeEach(function () {
cy.window().then(win => {
win.metaAttributesCache.set('ol-groupName', 'My Awesome Team')

View File

@@ -27,11 +27,35 @@ describe('SubscriptionGroupController', function () {
_id: this.subscriptionId,
teamName: 'Cool group',
groupPlan: true,
membersLimit: 5,
}
this.plan = {
canUseFlexibleLicensing: true,
}
this.previewSubscriptionChangeData = {
change: {},
currency: 'USD',
}
this.createSubscriptionChangeData = { adding: 1 }
this.SubscriptionGroupHandler = {
promises: {
removeUserFromGroup: sinon.stub().resolves(),
getUsersGroupSubscriptionDetails: sinon.stub().resolves({
subscription: this.subscription,
plan: this.plan,
recurlySubscription: {},
}),
previewAddSeatsSubscriptionChange: sinon
.stub()
.resolves(this.previewSubscriptionChangeData),
createAddSeatsSubscriptionChange: sinon
.stub()
.resolves(this.createSubscriptionChangeData),
ensureFlexibleLicensingEnabled: sinon.stub().resolves(),
},
}
@@ -66,14 +90,13 @@ describe('SubscriptionGroupController', function () {
this.SplitTestHandler = {
promises: {
getAssignment: sinon.stub().resolves({ variant: 'default' }),
getAssignment: sinon.stub().resolves(),
},
getAssignment: sinon.stub().yields(null, { variant: 'default' }),
}
this.UserGetter = {
promises: {
getUserEmail: sinon.stub().resolves(this.user),
getUserEmail: sinon.stub().resolves(this.user.email),
},
}
@@ -105,6 +128,13 @@ describe('SubscriptionGroupController', function () {
'../../../../app/src/Features/Subscription/RecurlyClient':
this.RecurlyClient,
'../../../../app/src/models/Subscription': this.SubscriptionModel,
'@overleaf/logger': {
err: sinon.stub(),
error: sinon.stub(),
warn: sinon.stub(),
log: sinon.stub(),
debug: sinon.stub(),
},
})
})
@@ -287,4 +317,183 @@ describe('SubscriptionGroupController', function () {
this.Controller.removeSelfFromGroup(this.req, res, done)
})
})
describe('addSeatsToGroupSubscription', function () {
it('should render the "add seats" page', function (done) {
const res = {
render: (page, props) => {
this.SubscriptionGroupHandler.promises.getUsersGroupSubscriptionDetails
.calledWith(this.req)
.should.equal(true)
this.SubscriptionGroupHandler.promises.ensureFlexibleLicensingEnabled
.calledWith(this.plan)
.should.equal(true)
page.should.equal('subscriptions/add-seats')
props.subscriptionId.should.equal(this.subscriptionId)
props.groupName.should.equal(this.subscription.teamName)
props.totalLicenses.should.equal(this.subscription.membersLimit)
done()
},
}
this.Controller.addSeatsToGroupSubscription(this.req, res)
})
it('should redirect to subscription page when getting subscription details fails', function (done) {
this.SubscriptionGroupHandler.promises.getUsersGroupSubscriptionDetails =
sinon.stub().rejects()
const res = {
redirect: url => {
url.should.equal('/user/subscription')
done()
},
}
this.Controller.addSeatsToGroupSubscription(this.req, res)
})
it('should redirect to subscription page when flexible licensing is not enabled', function (done) {
this.SubscriptionGroupHandler.promises.ensureFlexibleLicensingEnabled =
sinon.stub().rejects()
const res = {
redirect: url => {
url.should.equal('/user/subscription')
done()
},
}
this.Controller.addSeatsToGroupSubscription(this.req, res)
})
})
describe('previewAddSeatsSubscriptionChange', function () {
it('should preview "add seats" change', function (done) {
const res = {
json: data => {
this.SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange
.calledWith(this.req)
.should.equal(true)
data.should.deep.equal(this.previewSubscriptionChangeData)
done()
},
}
this.Controller.previewAddSeatsSubscriptionChange(this.req, res)
})
it('should fail previewing "add seats" change', function (done) {
this.SubscriptionGroupHandler.promises.previewAddSeatsSubscriptionChange =
sinon.stub().rejects()
const res = {
status: statusCode => {
statusCode.should.equal(400)
return {
end: () => {
done()
},
}
},
}
this.Controller.previewAddSeatsSubscriptionChange(this.req, res)
})
})
describe('createAddSeatsSubscriptionChange', function () {
it('should apply "add seats" change', function (done) {
const res = {
json: data => {
this.SubscriptionGroupHandler.promises.createAddSeatsSubscriptionChange
.calledWith(this.req)
.should.equal(true)
data.should.deep.equal(this.createSubscriptionChangeData)
done()
},
}
this.Controller.createAddSeatsSubscriptionChange(this.req, res)
})
it('should fail applying "add seats" change', function (done) {
this.SubscriptionGroupHandler.promises.createAddSeatsSubscriptionChange =
sinon.stub().rejects()
const res = {
status: statusCode => {
statusCode.should.equal(400)
return {
end: () => {
done()
},
}
},
}
this.Controller.createAddSeatsSubscriptionChange(this.req, res)
})
})
describe('submitForm', function () {
it('should build and pass the request body to the sales submit handler', function (done) {
const adding = 100
this.req.body = { adding }
const res = {
sendStatus: code => {
this.Modules.promises.hooks.fire
.calledWith('sendSupportRequest', {
email: this.user.email,
subject: 'Sales Contact Form',
message:
'\n' +
'**Overleaf Sales Contact Form:**\n' +
'\n' +
'**Subject:** Self-Serve Group User Increase Request\n' +
'\n' +
`**Estimated Number of Users:** ${adding}\n` +
'\n' +
`**Message:** This email has been generated on behalf of user with email **${this.user.email}** to request an increase in the total number of users for their subscription.`,
inbox: 'sales',
})
.should.equal(true)
sinon.assert.calledOnce(this.Modules.promises.hooks.fire)
code.should.equal(204)
done()
},
}
this.Controller.submitForm(this.req, res, done)
})
})
describe('flexibleLicensingSplitTest', function () {
it('passes when the variant is "enabled"', function (done) {
const res = sinon.stub()
const next = () => {
this.ErrorController.notFound.notCalled.should.equal(true)
done()
}
this.SplitTestHandler.promises.getAssignment.resolves({
variant: 'enabled',
})
this.Controller.flexibleLicensingSplitTest(this.req, res, next, done)
})
it('returns error page when the variant is "default"', function (done) {
const res = sinon.stub()
const next = sinon.stub()
this.ErrorController.notFound = sinon.stub().callsFake(() => {
next.notCalled.should.equal(true)
done()
})
this.SplitTestHandler.promises.getAssignment.resolves({
variant: 'default',
})
this.Controller.flexibleLicensingSplitTest(this.req, res, next, done)
})
})
})

View File

@@ -1,6 +1,7 @@
const SandboxedModule = require('sandboxed-module')
const sinon = require('sinon')
const { expect } = require('chai')
const MockRequest = require('../helpers/MockRequest')
const modulePath =
'../../../../app/src/Features/Subscription/SubscriptionGroupHandler'
@@ -12,6 +13,12 @@ describe('SubscriptionGroupHandler', function () {
this.email = 'jim@example.com'
this.user = { _id: this.user_id, email: this.newEmail }
this.subscription_id = '31DSd1123D'
this.adding = 1
this.paymentMethod = { cardType: 'Visa', lastFour: '1111' }
this.localPlanInSettings = {
membersLimit: 2,
membersLimitAddOn: 'additional-license',
}
this.subscription = {
admin_id: this.adminUser_id,
@@ -19,16 +26,35 @@ describe('SubscriptionGroupHandler', function () {
_id: this.subscription_id,
}
this.changeRequest = {
timeframe: 'now',
}
this.recurlySubscription = {
id: 123,
addOns: [
{
code: 'additional-license',
quantity: 1,
},
],
getRequestForAddOnUpdate: sinon.stub().returns(this.changeRequest),
}
this.SubscriptionLocator = {
promises: {
getUsersSubscription: sinon.stub(),
getUsersSubscription: sinon.stub().resolves({ groupPlan: true }),
getSubscriptionByMemberIdAndId: sinon.stub(),
getSubscription: sinon.stub().resolves(this.subscription),
},
}
this.changePreview = {
currency: 'USD',
}
this.SubscriptionController = {
makeChangePreview: sinon.stub().resolves(),
makeChangePreview: sinon.stub().resolves(this.changePreview),
}
this.SubscriptionUpdater = {
@@ -44,8 +70,36 @@ describe('SubscriptionGroupHandler', function () {
findOne: sinon.stub().returns({ exec: sinon.stub().resolves }),
}
this.SessionManager = {
getLoggedInUserId: sinon.stub().returns(this.user._id),
}
this.previewSubscriptionChange = {
nextAddOns: [
{
code: 'additional-license',
quantity: this.recurlySubscription.addOns[0].quantity + this.adding,
},
],
}
this.applySubscriptionChange = {}
this.RecurlyClient = {
promises: {},
promises: {
getSubscription: sinon.stub().resolves(this.recurlySubscription),
getPaymentMethod: sinon.stub().resolves(this.paymentMethod),
previewSubscriptionChange: sinon
.stub()
.resolves(this.previewSubscriptionChange),
applySubscriptionChangeRequest: sinon
.stub()
.resolves(this.applySubscriptionChange),
},
}
this.PlansLocator = {
findLocalPlanInSettings: sinon.stub(this.localPlanInSettings),
}
this.SubscriptionHandler = {
@@ -64,6 +118,8 @@ describe('SubscriptionGroupHandler', function () {
Subscription: this.Subscription,
},
'./RecurlyClient': this.RecurlyClient,
'./PlansLocator': this.PlansLocator,
'../Authentication/SessionManager': this.SessionManager,
},
})
})
@@ -183,4 +239,127 @@ describe('SubscriptionGroupHandler', function () {
})
})
})
describe('getUsersGroupSubscriptionDetails', function () {
beforeEach(function () {
this.req = new MockRequest()
this.PlansLocator.findLocalPlanInSettings = sinon.stub().returns({
...this.localPlanInSettings,
canUseFlexibleLicensing: true,
})
})
it('should throw if the subscription is not a group plan', async function () {
this.SubscriptionLocator.promises.getUsersSubscription = sinon
.stub()
.resolves({ groupPlan: false })
await expect(
this.Handler.promises.getUsersGroupSubscriptionDetails(this.req)
).to.be.rejectedWith('User subscription is not a group plan')
})
it('should return users group subscription details', async function () {
const data = await this.Handler.promises.getUsersGroupSubscriptionDetails(
this.req
)
expect(data).to.deep.equal({
subscription: { groupPlan: true },
plan: {
membersLimit: 2,
membersLimitAddOn: 'additional-license',
canUseFlexibleLicensing: true,
},
recurlySubscription: this.recurlySubscription,
})
})
})
describe('add seats subscription change', function () {
beforeEach(function () {
this.req = new MockRequest()
Object.assign(this.req.body, { adding: this.adding })
this.PlansLocator.findLocalPlanInSettings = sinon.stub().returns({
...this.localPlanInSettings,
canUseFlexibleLicensing: true,
})
})
afterEach(function () {
this.recurlySubscription.getRequestForAddOnUpdate
.calledWith(
'additional-license',
this.recurlySubscription.addOns[0].quantity + this.adding
)
.should.equal(true)
})
describe('previewAddSeatsSubscriptionChange', function () {
it('should return the subscription change preview', async function () {
const preview =
await this.Handler.promises.previewAddSeatsSubscriptionChange(
this.req
)
this.RecurlyClient.promises.getPaymentMethod
.calledWith(this.user_id)
.should.equal(true)
this.RecurlyClient.promises.previewSubscriptionChange
.calledWith(this.changeRequest)
.should.equal(true)
this.SubscriptionController.makeChangePreview
.calledWith(
{
type: 'add-on-update',
addOn: {
code: 'additional-license',
quantity:
this.recurlySubscription.addOns[0].quantity + this.adding,
prevQuantity: this.adding,
},
},
this.previewSubscriptionChange,
this.paymentMethod
)
.should.equal(true)
preview.should.equal(this.changePreview)
})
})
describe('createAddSeatsSubscriptionChange', function () {
it('should change the subscription', async function () {
const result =
await this.Handler.promises.createAddSeatsSubscriptionChange(this.req)
this.RecurlyClient.promises.applySubscriptionChangeRequest
.calledWith(this.changeRequest)
.should.equal(true)
this.SubscriptionHandler.promises.syncSubscription
.calledWith({ uuid: this.recurlySubscription.id }, this.user_id)
.should.equal(true)
expect(result).to.deep.equal({
adding: this.req.body.adding,
})
})
})
})
describe('ensureFlexibleLicensingEnabled', function () {
it('should throw if the subscription can not use flexible licensing', async function () {
await expect(
this.Handler.promises.ensureFlexibleLicensingEnabled({
canUseFlexibleLicensing: false,
})
).to.be.rejectedWith('The group plan does not support flexible licencing')
})
})
it('should not throw if the subscription can use flexible licensing', async function () {
await expect(
this.Handler.promises.ensureFlexibleLicensingEnabled({
canUseFlexibleLicensing: true,
})
).to.not.be.rejected
})
})