Merge pull request #5087 from overleaf/em-promisify-subscription-updater
Promisify FeaturesUpdater and SubscriptionHandler GitOrigin-RevId: 1a9725afa119c0eaee3d975a11197b6f702f1307
This commit is contained in:
@@ -106,6 +106,8 @@ describe('InstitutionsManager', function () {
|
||||
},
|
||||
'../Subscription/FeaturesUpdater': {
|
||||
refreshFeatures: this.refreshFeatures,
|
||||
},
|
||||
'../Subscription/FeaturesHelper': {
|
||||
isFeatureSetBetter: (this.isFeatureSetBetter = sinon.stub()),
|
||||
},
|
||||
'../User/UserGetter': this.UserGetter,
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { expect } = require('chai')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/FeaturesHelper'
|
||||
|
||||
describe('FeaturesHelper', function () {
|
||||
beforeEach(function () {
|
||||
this.FeaturesHelper = SandboxedModule.require(MODULE_PATH)
|
||||
})
|
||||
|
||||
describe('mergeFeatures', function () {
|
||||
it('should prefer priority over standard for compileGroup', function () {
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileGroup: 'priority' },
|
||||
{ compileGroup: 'standard' }
|
||||
)
|
||||
).to.deep.equal({ compileGroup: 'priority' })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileGroup: 'standard' },
|
||||
{ compileGroup: 'priority' }
|
||||
)
|
||||
).to.deep.equal({ compileGroup: 'priority' })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileGroup: 'priority' },
|
||||
{ compileGroup: 'priority' }
|
||||
)
|
||||
).to.deep.equal({ compileGroup: 'priority' })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileGroup: 'standard' },
|
||||
{ compileGroup: 'standard' }
|
||||
)
|
||||
).to.deep.equal({ compileGroup: 'standard' })
|
||||
})
|
||||
|
||||
it('should prefer -1 over any other for collaborators', function () {
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ collaborators: -1 },
|
||||
{ collaborators: 10 }
|
||||
)
|
||||
).to.deep.equal({ collaborators: -1 })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ collaborators: 10 },
|
||||
{ collaborators: -1 }
|
||||
)
|
||||
).to.deep.equal({ collaborators: -1 })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ collaborators: 4 },
|
||||
{ collaborators: 10 }
|
||||
)
|
||||
).to.deep.equal({ collaborators: 10 })
|
||||
})
|
||||
|
||||
it('should prefer the higher of compileTimeout', function () {
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileTimeout: 20 },
|
||||
{ compileTimeout: 10 }
|
||||
)
|
||||
).to.deep.equal({ compileTimeout: 20 })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures(
|
||||
{ compileTimeout: 10 },
|
||||
{ compileTimeout: 20 }
|
||||
)
|
||||
).to.deep.equal({ compileTimeout: 20 })
|
||||
})
|
||||
|
||||
it('should prefer the true over false for other keys', function () {
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures({ github: true }, { github: false })
|
||||
).to.deep.equal({ github: true })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures({ github: false }, { github: true })
|
||||
).to.deep.equal({ github: true })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures({ github: true }, { github: true })
|
||||
).to.deep.equal({ github: true })
|
||||
expect(
|
||||
this.FeaturesHelper.mergeFeatures({ github: false }, { github: false })
|
||||
).to.deep.equal({ github: false })
|
||||
})
|
||||
})
|
||||
|
||||
describe('isFeatureSetBetter', function () {
|
||||
it('simple comparisons', function () {
|
||||
const result1 = this.FeaturesHelper.isFeatureSetBetter(
|
||||
{ dropbox: true },
|
||||
{ dropbox: false }
|
||||
)
|
||||
expect(result1).to.be.true
|
||||
|
||||
const result2 = this.FeaturesHelper.isFeatureSetBetter(
|
||||
{ dropbox: false },
|
||||
{ dropbox: true }
|
||||
)
|
||||
expect(result2).to.be.false
|
||||
})
|
||||
|
||||
it('compound comparisons with same features', function () {
|
||||
const result1 = this.FeaturesHelper.isFeatureSetBetter(
|
||||
{ collaborators: 9, dropbox: true },
|
||||
{ collaborators: 10, dropbox: true }
|
||||
)
|
||||
expect(result1).to.be.false
|
||||
|
||||
const result2 = this.FeaturesHelper.isFeatureSetBetter(
|
||||
{ collaborators: -1, dropbox: true },
|
||||
{ collaborators: 10, dropbox: true }
|
||||
)
|
||||
expect(result2).to.be.true
|
||||
|
||||
const result3 = this.FeaturesHelper.isFeatureSetBetter(
|
||||
{ collaborators: -1, compileTimeout: 60, dropbox: true },
|
||||
{ collaborators: 10, compileTimeout: 60, dropbox: true }
|
||||
)
|
||||
expect(result3).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,556 +1,244 @@
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const { assert, expect } = require('chai')
|
||||
const { expect } = require('chai')
|
||||
const sinon = require('sinon')
|
||||
const modulePath = '../../../../app/src/Features/Subscription/FeaturesUpdater'
|
||||
const { ObjectId } = require('mongodb')
|
||||
|
||||
const MODULE_PATH = '../../../../app/src/Features/Subscription/FeaturesUpdater'
|
||||
|
||||
describe('FeaturesUpdater', function () {
|
||||
beforeEach(function () {
|
||||
this.user_id = ObjectId().toString()
|
||||
this.user = {
|
||||
_id: new ObjectId(),
|
||||
features: {},
|
||||
}
|
||||
this.v1UserId = 12345
|
||||
this.subscriptions = {
|
||||
individual: { planCode: 'individual-plan' },
|
||||
group1: { planCode: 'group-plan-1' },
|
||||
group2: { planCode: 'group-plan-2' },
|
||||
noDropbox: { planCode: 'no-dropbox' },
|
||||
}
|
||||
|
||||
this.FeaturesUpdater = SandboxedModule.require(modulePath, {
|
||||
this.UserFeaturesUpdater = {
|
||||
promises: {
|
||||
updateFeatures: sinon
|
||||
.stub()
|
||||
.resolves({ features: { some: 'features' }, featuresChanged: true }),
|
||||
},
|
||||
}
|
||||
|
||||
this.SubscriptionLocator = {
|
||||
promises: {
|
||||
getUserIndividualSubscription: sinon.stub(),
|
||||
getGroupSubscriptionsMemberOf: sinon.stub(),
|
||||
},
|
||||
}
|
||||
this.SubscriptionLocator.promises.getUserIndividualSubscription
|
||||
.withArgs(this.user._id)
|
||||
.resolves(this.subscriptions.individual)
|
||||
this.SubscriptionLocator.promises.getGroupSubscriptionsMemberOf
|
||||
.withArgs(this.user._id)
|
||||
.resolves([this.subscriptions.group1, this.subscriptions.group2])
|
||||
|
||||
this.Settings = {
|
||||
defaultFeatures: { default: 'features' },
|
||||
plans: [
|
||||
{ planCode: 'individual-plan', features: { individual: 'features' } },
|
||||
{ planCode: 'group-plan-1', features: { group1: 'features' } },
|
||||
{ planCode: 'group-plan-2', features: { group2: 'features' } },
|
||||
{ planCode: 'v1-plan', features: { v1: 'features' } },
|
||||
{ planCode: 'no-dropbox', features: { dropbox: false } },
|
||||
],
|
||||
features: {
|
||||
all: {
|
||||
default: 'features',
|
||||
individual: 'features',
|
||||
group1: 'features',
|
||||
group2: 'features',
|
||||
institutions: 'features',
|
||||
v1: 'features',
|
||||
grandfathered: 'features',
|
||||
bonus: 'features',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
this.ReferalFeatures = {
|
||||
promises: {
|
||||
getBonusFeatures: sinon.stub().resolves({ bonus: 'features' }),
|
||||
},
|
||||
}
|
||||
this.V1SubscriptionManager = {
|
||||
getGrandfatheredFeaturesForV1User: sinon.stub(),
|
||||
promises: {
|
||||
getPlanCodeFromV1: sinon.stub(),
|
||||
},
|
||||
}
|
||||
this.V1SubscriptionManager.promises.getPlanCodeFromV1
|
||||
.withArgs(this.user._id)
|
||||
.resolves({ planCode: 'v1-plan', v1Id: this.v1UserId })
|
||||
this.V1SubscriptionManager.getGrandfatheredFeaturesForV1User
|
||||
.withArgs(this.v1UserId)
|
||||
.returns({ grandfathered: 'features' })
|
||||
|
||||
this.InstitutionsFeatures = {
|
||||
promises: {
|
||||
getInstitutionsFeatures: sinon
|
||||
.stub()
|
||||
.resolves({ institutions: 'features' }),
|
||||
},
|
||||
}
|
||||
|
||||
this.UserGetter = {
|
||||
promises: {
|
||||
getUser: sinon.stub().resolves(null),
|
||||
},
|
||||
}
|
||||
this.UserGetter.promises.getUser.withArgs(this.user._id).resolves(this.user)
|
||||
this.UserGetter.promises.getUser
|
||||
.withArgs({ 'overleaf.id': this.v1UserId })
|
||||
.resolves(this.user)
|
||||
|
||||
this.AnalyticsManager = {
|
||||
setUserPropertyForUser: sinon.stub(),
|
||||
}
|
||||
this.Modules = {
|
||||
promises: { hooks: { fire: sinon.stub().resolves() } },
|
||||
}
|
||||
this.FeaturesHelper = {
|
||||
mergeFeatures: sinon.stub().callsFake((a, b) => ({ ...a, ...b })),
|
||||
}
|
||||
|
||||
this.FeaturesUpdater = SandboxedModule.require(MODULE_PATH, {
|
||||
requires: {
|
||||
'./UserFeaturesUpdater': (this.UserFeaturesUpdater = {}),
|
||||
'./SubscriptionLocator': (this.SubscriptionLocator = {}),
|
||||
'./PlansLocator': (this.PlansLocator = {}),
|
||||
'@overleaf/settings': (this.Settings = {
|
||||
features: {
|
||||
personal: {
|
||||
collaborators: 1,
|
||||
dropbox: false,
|
||||
compileTimeout: 60,
|
||||
compileGroup: 'standard',
|
||||
},
|
||||
collaborator: {
|
||||
collaborators: 10,
|
||||
dropbox: true,
|
||||
compileTimeout: 240,
|
||||
compileGroup: 'priority',
|
||||
},
|
||||
professional: {
|
||||
collaborators: -1,
|
||||
dropbox: true,
|
||||
compileTimeout: 240,
|
||||
compileGroup: 'priority',
|
||||
},
|
||||
},
|
||||
}),
|
||||
'../Referal/ReferalFeatures': (this.ReferalFeatures = {}),
|
||||
'./V1SubscriptionManager': (this.V1SubscriptionManager = {}),
|
||||
'../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
|
||||
'../User/UserGetter': (this.UserGetter = {}),
|
||||
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
|
||||
setUserPropertyForUser: sinon.stub(),
|
||||
}),
|
||||
'../../infrastructure/Modules': (this.Modules = {
|
||||
hooks: { fire: sinon.stub() },
|
||||
}),
|
||||
'./UserFeaturesUpdater': this.UserFeaturesUpdater,
|
||||
'./SubscriptionLocator': this.SubscriptionLocator,
|
||||
'./FeaturesHelper': this.FeaturesHelper,
|
||||
'@overleaf/settings': this.Settings,
|
||||
'../Referal/ReferalFeatures': this.ReferalFeatures,
|
||||
'./V1SubscriptionManager': this.V1SubscriptionManager,
|
||||
'../Institutions/InstitutionsFeatures': this.InstitutionsFeatures,
|
||||
'../User/UserGetter': this.UserGetter,
|
||||
'../Analytics/AnalyticsManager': this.AnalyticsManager,
|
||||
'../../infrastructure/Modules': this.Modules,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
describe('refreshFeatures', function () {
|
||||
beforeEach(function () {
|
||||
this.user = {
|
||||
_id: this.user_id,
|
||||
features: {},
|
||||
}
|
||||
this.UserFeaturesUpdater.updateFeatures = sinon
|
||||
.stub()
|
||||
.yields(null, { some: 'features' }, true)
|
||||
this.FeaturesUpdater._getIndividualFeatures = sinon
|
||||
.stub()
|
||||
.yields(null, { individual: 'features' })
|
||||
this.FeaturesUpdater._getGroupFeatureSets = sinon
|
||||
.stub()
|
||||
.yields(null, [{ group: 'features' }, { group: 'features2' }])
|
||||
this.InstitutionsFeatures.getInstitutionsFeatures = sinon
|
||||
.stub()
|
||||
.yields(null, { institutions: 'features' })
|
||||
this.FeaturesUpdater._getV1Features = sinon
|
||||
.stub()
|
||||
.yields(null, { v1: 'features' })
|
||||
this.ReferalFeatures.getBonusFeatures = sinon
|
||||
.stub()
|
||||
.yields(null, { bonus: 'features' })
|
||||
this.FeaturesUpdater._mergeFeatures = sinon
|
||||
.stub()
|
||||
.returns({ merged: 'features' })
|
||||
this.UserGetter.getUser = sinon.stub().yields(null, this.user)
|
||||
this.callback = sinon.stub()
|
||||
})
|
||||
it('should return features and featuresChanged', function () {
|
||||
this.FeaturesUpdater.refreshFeatures(
|
||||
this.user_id,
|
||||
'test',
|
||||
(err, features, featuresChanged) => {
|
||||
expect(err).to.not.exist
|
||||
expect(features).to.exist
|
||||
expect(featuresChanged).to.exist
|
||||
}
|
||||
it('should return features and featuresChanged', async function () {
|
||||
const {
|
||||
features,
|
||||
featuresChanged,
|
||||
} = await this.FeaturesUpdater.promises.refreshFeatures(
|
||||
this.user._id,
|
||||
'test'
|
||||
)
|
||||
expect(features).to.exist
|
||||
expect(featuresChanged).to.exist
|
||||
})
|
||||
|
||||
describe('normally', function () {
|
||||
beforeEach(function () {
|
||||
this.FeaturesUpdater.refreshFeatures(
|
||||
this.user_id,
|
||||
'test',
|
||||
this.callback
|
||||
beforeEach(async function () {
|
||||
await this.FeaturesUpdater.promises.refreshFeatures(
|
||||
this.user._id,
|
||||
'test'
|
||||
)
|
||||
})
|
||||
it('should get the individual features', function () {
|
||||
this.FeaturesUpdater._getIndividualFeatures
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
it('should get the group features', function () {
|
||||
this.FeaturesUpdater._getGroupFeatureSets
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
it('should get the institution features', function () {
|
||||
this.InstitutionsFeatures.getInstitutionsFeatures
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
it('should get the v1 features', function () {
|
||||
this.FeaturesUpdater._getV1Features
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
it('should get the bonus features', function () {
|
||||
this.ReferalFeatures.getBonusFeatures
|
||||
.calledWith(this.user_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
it('should merge from the default features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(this.Settings.defaultFeatures)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should merge the individual features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { individual: 'features' })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should merge the group features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { group: 'features' })
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { group: 'features2' })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should merge the institutions features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { institutions: 'features' })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should merge the v1 features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { v1: 'features' })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should merge the bonus features', function () {
|
||||
this.FeaturesUpdater._mergeFeatures
|
||||
.calledWith(sinon.match.any, { bonus: 'features' })
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should update the user with the merged features', function () {
|
||||
this.UserFeaturesUpdater.updateFeatures
|
||||
.calledWith(this.user_id, { merged: 'features' })
|
||||
.should.equal(true)
|
||||
expect(
|
||||
this.UserFeaturesUpdater.promises.updateFeatures
|
||||
).to.have.been.calledWith(this.user._id, this.Settings.features.all)
|
||||
})
|
||||
|
||||
it('should send the corresponding feature set user property', function () {
|
||||
expect(
|
||||
this.AnalyticsManager.setUserPropertyForUser
|
||||
).to.have.been.calledWith(this.user._id, 'feature-set', 'all')
|
||||
})
|
||||
})
|
||||
|
||||
describe('analytics user properties', function () {
|
||||
it('should send the corresponding feature set user property', function () {
|
||||
this.FeaturesUpdater._mergeFeatures = sinon
|
||||
.stub()
|
||||
.returns(this.Settings.features.personal)
|
||||
|
||||
this.FeaturesUpdater.refreshFeatures(
|
||||
this.user_id,
|
||||
'test',
|
||||
this.callback
|
||||
)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.user_id,
|
||||
'feature-set',
|
||||
'personal'
|
||||
describe('with a non-standard feature set', async function () {
|
||||
beforeEach(async function () {
|
||||
this.SubscriptionLocator.promises.getGroupSubscriptionsMemberOf
|
||||
.withArgs(this.user._id)
|
||||
.resolves(null)
|
||||
await this.FeaturesUpdater.promises.refreshFeatures(
|
||||
this.user._id,
|
||||
'test'
|
||||
)
|
||||
})
|
||||
|
||||
it('should send mixed feature set user property', function () {
|
||||
this.FeaturesUpdater._mergeFeatures = sinon
|
||||
.stub()
|
||||
.returns({ dropbox: true, feature: 'some' })
|
||||
|
||||
this.FeaturesUpdater.refreshFeatures(
|
||||
this.user_id,
|
||||
'test',
|
||||
this.callback
|
||||
)
|
||||
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.user_id,
|
||||
this.user._id,
|
||||
'feature-set',
|
||||
'mixed'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when losing dropbox feature', function () {
|
||||
beforeEach(function () {
|
||||
this.user = {
|
||||
_id: this.user_id,
|
||||
features: { dropbox: true },
|
||||
}
|
||||
this.UserGetter.getUser = sinon.stub().yields(null, this.user)
|
||||
this.FeaturesUpdater._mergeFeatures = sinon
|
||||
.stub()
|
||||
.returns({ dropbox: false })
|
||||
this.FeaturesUpdater.refreshFeatures(
|
||||
this.user_id,
|
||||
'test',
|
||||
this.callback
|
||||
describe('when losing dropbox feature', async function () {
|
||||
beforeEach(async function () {
|
||||
this.user.features = { dropbox: true }
|
||||
this.SubscriptionLocator.promises.getUserIndividualSubscription
|
||||
.withArgs(this.user._id)
|
||||
.resolves(this.subscriptions.noDropbox)
|
||||
await this.FeaturesUpdater.promises.refreshFeatures(
|
||||
this.user._id,
|
||||
'test'
|
||||
)
|
||||
})
|
||||
|
||||
it('should fire module hook to unlink dropbox', function () {
|
||||
this.Modules.hooks.fire
|
||||
.calledWith('removeDropbox', this.user._id, 'test')
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('_mergeFeatures', function () {
|
||||
it('should prefer priority over standard for compileGroup', function () {
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileGroup: 'priority',
|
||||
},
|
||||
{
|
||||
compileGroup: 'standard',
|
||||
}
|
||||
expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
|
||||
'removeDropbox',
|
||||
this.user._id,
|
||||
'test'
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileGroup: 'priority',
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileGroup: 'standard',
|
||||
},
|
||||
{
|
||||
compileGroup: 'priority',
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileGroup: 'priority',
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileGroup: 'priority',
|
||||
},
|
||||
{
|
||||
compileGroup: 'priority',
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileGroup: 'priority',
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileGroup: 'standard',
|
||||
},
|
||||
{
|
||||
compileGroup: 'standard',
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileGroup: 'standard',
|
||||
})
|
||||
})
|
||||
|
||||
it('should prefer -1 over any other for collaborators', function () {
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
collaborators: -1,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
collaborators: -1,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
collaborators: 10,
|
||||
},
|
||||
{
|
||||
collaborators: -1,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
collaborators: -1,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
collaborators: 4,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
collaborators: 10,
|
||||
})
|
||||
})
|
||||
|
||||
it('should prefer the higher of compileTimeout', function () {
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileTimeout: 20,
|
||||
},
|
||||
{
|
||||
compileTimeout: 10,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileTimeout: 20,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
compileTimeout: 10,
|
||||
},
|
||||
{
|
||||
compileTimeout: 20,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
compileTimeout: 20,
|
||||
})
|
||||
})
|
||||
|
||||
it('should prefer the true over false for other keys', function () {
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
github: true,
|
||||
},
|
||||
{
|
||||
github: false,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
github: true,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
github: false,
|
||||
},
|
||||
{
|
||||
github: true,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
github: true,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
github: true,
|
||||
},
|
||||
{
|
||||
github: true,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
github: true,
|
||||
})
|
||||
expect(
|
||||
this.FeaturesUpdater._mergeFeatures(
|
||||
{
|
||||
github: false,
|
||||
},
|
||||
{
|
||||
github: false,
|
||||
}
|
||||
)
|
||||
).to.deep.equal({
|
||||
github: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('doSyncFromV1', function () {
|
||||
beforeEach(function () {
|
||||
this.v1UserId = 1
|
||||
this.user = {
|
||||
_id: this.user_id,
|
||||
email: 'user@example.com',
|
||||
overleaf: {
|
||||
id: this.v1UserId,
|
||||
},
|
||||
}
|
||||
|
||||
this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, this.user)
|
||||
this.FeaturesUpdater.refreshFeatures = sinon.stub().yields(null)
|
||||
this.call = cb => {
|
||||
this.FeaturesUpdater.doSyncFromV1(this.v1UserId, cb)
|
||||
}
|
||||
})
|
||||
|
||||
describe('when all goes well', function () {
|
||||
it('should call getUser', function (done) {
|
||||
this.call(() => {
|
||||
expect(this.UserGetter.getUser.callCount).to.equal(1)
|
||||
expect(
|
||||
this.UserGetter.getUser.calledWith({ 'overleaf.id': this.v1UserId })
|
||||
).to.equal(true)
|
||||
done()
|
||||
})
|
||||
beforeEach(async function () {
|
||||
await this.FeaturesUpdater.promises.doSyncFromV1(this.v1UserId)
|
||||
})
|
||||
|
||||
it('should call refreshFeatures', function (done) {
|
||||
this.call(() => {
|
||||
expect(this.FeaturesUpdater.refreshFeatures.callCount).to.equal(1)
|
||||
expect(
|
||||
this.FeaturesUpdater.refreshFeatures.calledWith(this.user_id)
|
||||
).to.equal(true)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not produce an error', function (done) {
|
||||
this.call(err => {
|
||||
expect(err).to.not.exist
|
||||
done()
|
||||
})
|
||||
it('should update the user with the merged features', function () {
|
||||
expect(
|
||||
this.UserFeaturesUpdater.promises.updateFeatures
|
||||
).to.have.been.calledWith(this.user._id, this.Settings.features.all)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when getUser produces an error', function () {
|
||||
beforeEach(function () {
|
||||
this.UserGetter.getUser = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, new Error('woops'))
|
||||
this.UserGetter.promises.getUser.rejects(new Error('woops'))
|
||||
})
|
||||
|
||||
it('should not call refreshFeatures', function () {
|
||||
expect(this.FeaturesUpdater.refreshFeatures.callCount).to.equal(0)
|
||||
})
|
||||
|
||||
it('should produce an error', function (done) {
|
||||
this.call(err => {
|
||||
expect(err).to.exist
|
||||
done()
|
||||
})
|
||||
it('should propagate the error', async function () {
|
||||
const someId = 9090
|
||||
await expect(this.FeaturesUpdater.promises.doSyncFromV1(someId)).to.be
|
||||
.rejected
|
||||
expect(this.UserFeaturesUpdater.promises.updateFeatures).not.to.have
|
||||
.been.called
|
||||
})
|
||||
})
|
||||
|
||||
describe('when getUser does not find a user', function () {
|
||||
beforeEach(function () {
|
||||
this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, null)
|
||||
beforeEach(async function () {
|
||||
const someOtherId = 987
|
||||
await this.FeaturesUpdater.promises.doSyncFromV1(someOtherId)
|
||||
})
|
||||
|
||||
it('should not call refreshFeatures', function (done) {
|
||||
this.call(() => {
|
||||
expect(this.FeaturesUpdater.refreshFeatures.callCount).to.equal(0)
|
||||
done()
|
||||
})
|
||||
it('should not update the user', function () {
|
||||
expect(this.UserFeaturesUpdater.promises.updateFeatures).not.to.have
|
||||
.been.called
|
||||
})
|
||||
|
||||
it('should not produce an error', function (done) {
|
||||
this.call(err => {
|
||||
expect(err).to.not.exist
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('isFeatureSetBetter', function () {
|
||||
it('simple comparisons', function () {
|
||||
const result1 = this.FeaturesUpdater.isFeatureSetBetter(
|
||||
{
|
||||
dropbox: true,
|
||||
},
|
||||
{
|
||||
dropbox: false,
|
||||
}
|
||||
)
|
||||
assert.isTrue(result1)
|
||||
|
||||
const result2 = this.FeaturesUpdater.isFeatureSetBetter(
|
||||
{
|
||||
dropbox: false,
|
||||
},
|
||||
{
|
||||
dropbox: true,
|
||||
}
|
||||
)
|
||||
assert.isFalse(result2)
|
||||
})
|
||||
|
||||
it('compound comparisons with same features', function () {
|
||||
const result1 = this.FeaturesUpdater.isFeatureSetBetter(
|
||||
{
|
||||
collaborators: 9,
|
||||
dropbox: true,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
dropbox: true,
|
||||
}
|
||||
)
|
||||
assert.isFalse(result1)
|
||||
|
||||
const result2 = this.FeaturesUpdater.isFeatureSetBetter(
|
||||
{
|
||||
collaborators: -1,
|
||||
dropbox: true,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
dropbox: true,
|
||||
}
|
||||
)
|
||||
assert.isTrue(result2)
|
||||
|
||||
const result3 = this.FeaturesUpdater.isFeatureSetBetter(
|
||||
{
|
||||
collaborators: -1,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
}
|
||||
)
|
||||
assert.isTrue(result3)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,7 +2,8 @@ const SandboxedModule = require('sandboxed-module')
|
||||
const sinon = require('sinon')
|
||||
const chai = require('chai')
|
||||
const { expect } = chai
|
||||
const modulePath =
|
||||
|
||||
const MODULE_PATH =
|
||||
'../../../../app/src/Features/Subscription/SubscriptionHandler'
|
||||
|
||||
const mockRecurlySubscriptions = {
|
||||
@@ -47,6 +48,8 @@ const mockSubscriptionChanges = {
|
||||
|
||||
describe('SubscriptionHandler', function () {
|
||||
beforeEach(function () {
|
||||
this.callback = sinon.stub()
|
||||
|
||||
this.Settings = {
|
||||
plans: [
|
||||
{
|
||||
@@ -85,6 +88,7 @@ describe('SubscriptionHandler', function () {
|
||||
getBillingInfo: sinon.stub().yields(),
|
||||
getAccountPastDueInvoices: sinon.stub().yields(),
|
||||
attemptInvoiceCollection: sinon.stub().yields(),
|
||||
listAccountActiveSubscriptions: sinon.stub().yields(null, []),
|
||||
}
|
||||
this.RecurlyClient = {
|
||||
changeSubscriptionByUuid: sinon
|
||||
@@ -118,7 +122,7 @@ describe('SubscriptionHandler', function () {
|
||||
shouldPlanChangeAtTermEnd: sinon.stub(),
|
||||
}
|
||||
|
||||
this.SubscriptionHandler = SandboxedModule.require(modulePath, {
|
||||
this.SubscriptionHandler = SandboxedModule.require(MODULE_PATH, {
|
||||
requires: {
|
||||
'./RecurlyWrapper': this.RecurlyWrapper,
|
||||
'./RecurlyClient': this.RecurlyClient,
|
||||
@@ -134,23 +138,15 @@ describe('SubscriptionHandler', function () {
|
||||
'./SubscriptionHelper': this.SubscriptionHelper,
|
||||
},
|
||||
})
|
||||
|
||||
this.SubscriptionHandler.syncSubscriptionToUser = sinon
|
||||
.stub()
|
||||
.callsArgWith(2)
|
||||
})
|
||||
|
||||
describe('createSubscription', function () {
|
||||
beforeEach(function () {
|
||||
this.callback = sinon.stub()
|
||||
this.subscriptionDetails = {
|
||||
cvv: '123',
|
||||
number: '12345',
|
||||
}
|
||||
this.recurlyTokenIds = { billing: '45555666' }
|
||||
this.SubscriptionHandler.validateNoSubscriptionInRecurly = sinon
|
||||
.stub()
|
||||
.yields(null, true)
|
||||
})
|
||||
|
||||
describe('successfully', function () {
|
||||
@@ -182,9 +178,9 @@ describe('SubscriptionHandler', function () {
|
||||
|
||||
describe('when there is already a subscription in Recurly', function () {
|
||||
beforeEach(function () {
|
||||
this.SubscriptionHandler.validateNoSubscriptionInRecurly = sinon
|
||||
.stub()
|
||||
.yields(null, false)
|
||||
this.RecurlyWrapper.listAccountActiveSubscriptions.yields(null, [
|
||||
this.subscription,
|
||||
])
|
||||
this.SubscriptionHandler.createSubscription(
|
||||
this.user,
|
||||
this.subscriptionDetails,
|
||||
@@ -235,9 +231,9 @@ describe('SubscriptionHandler', function () {
|
||||
callback(null, this.user)
|
||||
}
|
||||
this.plan_code = 'collaborator'
|
||||
this.SubscriptionHelper.shouldPlanChangeAtTermEnd = sinon
|
||||
.stub()
|
||||
.returns(shouldPlanChangeAtTermEnd)
|
||||
this.SubscriptionHelper.shouldPlanChangeAtTermEnd.returns(
|
||||
shouldPlanChangeAtTermEnd
|
||||
)
|
||||
this.LimitationsManager.userHasV2Subscription.callsArgWith(
|
||||
1,
|
||||
null,
|
||||
@@ -277,14 +273,13 @@ describe('SubscriptionHandler', function () {
|
||||
callback(null, this.user)
|
||||
}
|
||||
this.plan_code = 'collaborator'
|
||||
this.PlansLocator.findLocalPlanInSettings = sinon.stub().returns(null)
|
||||
this.PlansLocator.findLocalPlanInSettings.returns(null)
|
||||
this.LimitationsManager.userHasV2Subscription.callsArgWith(
|
||||
1,
|
||||
null,
|
||||
true,
|
||||
this.subscription
|
||||
)
|
||||
this.callback = sinon.stub()
|
||||
this.SubscriptionHandler.updateSubscription(
|
||||
this.user,
|
||||
this.plan_code,
|
||||
@@ -322,9 +317,7 @@ describe('SubscriptionHandler', function () {
|
||||
|
||||
it('should redirect to the subscription dashboard', function () {
|
||||
this.RecurlyClient.changeSubscriptionByUuid.called.should.equal(false)
|
||||
this.SubscriptionHandler.syncSubscriptionToUser.called.should.equal(
|
||||
false
|
||||
)
|
||||
this.SubscriptionUpdater.syncSubscription.called.should.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -561,18 +554,11 @@ describe('SubscriptionHandler', function () {
|
||||
})
|
||||
|
||||
describe('validateNoSubscriptionInRecurly', function () {
|
||||
beforeEach(function () {
|
||||
this.subscriptions = []
|
||||
this.RecurlyWrapper.listAccountActiveSubscriptions = sinon
|
||||
.stub()
|
||||
.yields(null, this.subscriptions)
|
||||
this.SubscriptionUpdater.syncSubscription = sinon.stub().yields()
|
||||
this.callback = sinon.stub()
|
||||
})
|
||||
|
||||
describe('with no subscription in recurly', function () {
|
||||
describe('with a subscription in recurly', function () {
|
||||
beforeEach(function () {
|
||||
this.subscriptions.push((this.subscription = { mock: 'subscription' }))
|
||||
this.RecurlyWrapper.listAccountActiveSubscriptions.yields(null, [
|
||||
this.subscription,
|
||||
])
|
||||
this.SubscriptionHandler.validateNoSubscriptionInRecurly(
|
||||
this.user_id,
|
||||
this.callback
|
||||
@@ -596,7 +582,7 @@ describe('SubscriptionHandler', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a subscription in recurly', function () {
|
||||
describe('with no subscription in recurly', function () {
|
||||
beforeEach(function () {
|
||||
this.SubscriptionHandler.validateNoSubscriptionInRecurly(
|
||||
this.user_id,
|
||||
|
||||
@@ -7,12 +7,14 @@ const { ObjectId } = require('mongodb')
|
||||
|
||||
describe('SubscriptionUpdater', function () {
|
||||
beforeEach(function () {
|
||||
this.recurlyPlan = { planCode: 'recurly-plan' }
|
||||
this.recurlySubscription = {
|
||||
uuid: '1238uoijdasjhd',
|
||||
plan: {
|
||||
plan_code: 'kjhsakjds',
|
||||
plan_code: this.recurlyPlan.planCode,
|
||||
},
|
||||
}
|
||||
|
||||
this.adminUser = { _id: (this.adminuser_id = '5208dd34438843e2db000007') }
|
||||
this.otherUserId = '5208dd34438842e2db000005'
|
||||
this.allUserIds = ['13213', 'dsadas', 'djsaiud89']
|
||||
@@ -21,7 +23,7 @@ describe('SubscriptionUpdater', function () {
|
||||
admin_id: this.adminUser._id,
|
||||
manager_ids: [this.adminUser._id],
|
||||
member_ids: [],
|
||||
save: sinon.stub().callsArgWith(0),
|
||||
save: sinon.stub().resolves(),
|
||||
planCode: 'student_or_something',
|
||||
}
|
||||
this.user_id = this.adminuser_id
|
||||
@@ -31,7 +33,7 @@ describe('SubscriptionUpdater', function () {
|
||||
admin_id: this.adminUser._id,
|
||||
manager_ids: [this.adminUser._id],
|
||||
member_ids: this.allUserIds,
|
||||
save: sinon.stub().callsArgWith(0),
|
||||
save: sinon.stub().resolves(),
|
||||
groupPlan: true,
|
||||
planCode: 'group_subscription',
|
||||
}
|
||||
@@ -40,17 +42,11 @@ describe('SubscriptionUpdater', function () {
|
||||
admin_id: this.adminUser._id,
|
||||
manager_ids: [this.adminUser._id],
|
||||
member_ids: [this.otherUserId],
|
||||
save: sinon.stub().callsArgWith(0),
|
||||
save: sinon.stub().resolves(),
|
||||
groupPlan: true,
|
||||
planCode: 'better_group_subscription',
|
||||
}
|
||||
|
||||
this.updateStub = sinon.stub().callsArgWith(2, null)
|
||||
this.updateManyStub = sinon.stub().callsArgWith(2, null)
|
||||
this.findOneAndUpdateStub = sinon
|
||||
.stub()
|
||||
.callsArgWith(2, null, this.subscription)
|
||||
|
||||
const subscription = this.subscription
|
||||
this.SubscriptionModel = class {
|
||||
constructor(opts) {
|
||||
@@ -61,62 +57,93 @@ describe('SubscriptionUpdater', function () {
|
||||
}
|
||||
|
||||
save() {
|
||||
return subscription
|
||||
return Promise.resolve(subscription)
|
||||
}
|
||||
}
|
||||
this.SubscriptionModel.deleteOne = sinon.stub().yields()
|
||||
this.SubscriptionModel.updateOne = this.updateStub
|
||||
this.SubscriptionModel.updateMany = this.updateManyStub
|
||||
this.SubscriptionModel.findOneAndUpdate = this.findOneAndUpdateStub
|
||||
this.SubscriptionModel.deleteOne = sinon
|
||||
.stub()
|
||||
.returns({ exec: sinon.stub().resolves() })
|
||||
this.SubscriptionModel.updateOne = sinon
|
||||
.stub()
|
||||
.returns({ exec: sinon.stub().resolves() })
|
||||
this.SubscriptionModel.updateMany = sinon
|
||||
.stub()
|
||||
.returns({ exec: sinon.stub().resolves() })
|
||||
this.SubscriptionModel.findOneAndUpdate = sinon.stub().returns({
|
||||
exec: sinon.stub().resolves(this.subscription),
|
||||
})
|
||||
|
||||
this.SubscriptionLocator = {
|
||||
getUsersSubscription: sinon.stub(),
|
||||
getGroupSubscriptionMemberOf: sinon.stub(),
|
||||
getMemberSubscriptions: sinon.stub().yields(null, []),
|
||||
promises: {
|
||||
getMemberSubscriptions: sinon.stub().returns([this.groupSubscription]),
|
||||
getUsersSubscription: sinon.stub(),
|
||||
getGroupSubscriptionMemberOf: sinon.stub(),
|
||||
getMemberSubscriptions: sinon.stub().resolves([]),
|
||||
getSubscription: sinon.stub(),
|
||||
},
|
||||
}
|
||||
|
||||
this.SubscriptionLocator.promises.getSubscription
|
||||
.withArgs(this.subscription._id)
|
||||
.resolves(this.subscription)
|
||||
|
||||
this.Settings = {
|
||||
defaultPlanCode: 'personal',
|
||||
defaultFeatures: { default: 'features' },
|
||||
plans: [
|
||||
this.recurlyPlan,
|
||||
{ planCode: this.subscription.planCode, features: {} },
|
||||
{
|
||||
planCode: this.groupSubscription.planCode,
|
||||
features: {
|
||||
collaborators: 10,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
planCode: this.betterGroupSubscription.planCode,
|
||||
features: {
|
||||
collaborators: -1,
|
||||
compileTimeout: 240,
|
||||
dropbox: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
this.UserFeaturesUpdater = { updateFeatures: sinon.stub().yields() }
|
||||
this.UserFeaturesUpdater = {
|
||||
promises: {
|
||||
updateFeatures: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
|
||||
this.PlansLocator = { findLocalPlanInSettings: sinon.stub().returns({}) }
|
||||
|
||||
this.UserGetter = {
|
||||
getUsers(memberIds, projection, callback) {
|
||||
const users = memberIds.map(id => ({ _id: id }))
|
||||
callback(null, users)
|
||||
this.ReferalFeatures = {
|
||||
promises: {
|
||||
getBonusFeatures: sinon.stub().resolves(),
|
||||
},
|
||||
getUser: sinon.stub(),
|
||||
}
|
||||
|
||||
this.ReferalFeatures = { getBonusFeatures: sinon.stub().callsArgWith(1) }
|
||||
this.Modules = { hooks: { fire: sinon.stub().callsArgWith(2, null, null) } }
|
||||
this.FeaturesUpdater = {
|
||||
refreshFeatures: sinon.stub().yields(),
|
||||
planCodeToFeatures: sinon.stub(),
|
||||
promises: {
|
||||
refreshFeatures: sinon.stub().resolves({}),
|
||||
},
|
||||
}
|
||||
|
||||
this.DeletedSubscription = {
|
||||
findOneAndUpdate: sinon.stub().yields(),
|
||||
findOneAndUpdate: sinon.stub().returns({ exec: sinon.stub().resolves() }),
|
||||
}
|
||||
|
||||
this.AnalyticsManager = {
|
||||
setUserPropertyForUser: sinon.stub(),
|
||||
}
|
||||
|
||||
this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
mongodb: { ObjectId },
|
||||
'../../models/Subscription': {
|
||||
Subscription: this.SubscriptionModel,
|
||||
},
|
||||
'./UserFeaturesUpdater': this.UserFeaturesUpdater,
|
||||
'./SubscriptionLocator': this.SubscriptionLocator,
|
||||
'../User/UserGetter': this.UserGetter,
|
||||
'./PlansLocator': this.PlansLocator,
|
||||
'@overleaf/settings': this.Settings,
|
||||
'../../infrastructure/mongodb': { db: {}, ObjectId },
|
||||
'./FeaturesUpdater': this.FeaturesUpdater,
|
||||
@@ -129,266 +156,184 @@ describe('SubscriptionUpdater', function () {
|
||||
})
|
||||
|
||||
describe('updateAdmin', function () {
|
||||
it('should update the subscription admin', function (done) {
|
||||
it('should update the subscription admin', async function () {
|
||||
this.subscription.groupPlan = true
|
||||
this.SubscriptionUpdater.updateAdmin(
|
||||
await this.SubscriptionUpdater.promises.updateAdmin(
|
||||
this.subscription,
|
||||
this.otherUserId,
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
const query = {
|
||||
_id: ObjectId(this.subscription._id),
|
||||
customAccount: true,
|
||||
}
|
||||
const update = {
|
||||
$set: { admin_id: ObjectId(this.otherUserId) },
|
||||
$addToSet: { manager_ids: ObjectId(this.otherUserId) },
|
||||
}
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledOnce
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledWith(
|
||||
query,
|
||||
update
|
||||
)
|
||||
done()
|
||||
}
|
||||
this.otherUserId
|
||||
)
|
||||
const query = {
|
||||
_id: ObjectId(this.subscription._id),
|
||||
customAccount: true,
|
||||
}
|
||||
const update = {
|
||||
$set: { admin_id: ObjectId(this.otherUserId) },
|
||||
$addToSet: { manager_ids: ObjectId(this.otherUserId) },
|
||||
}
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledOnce
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledWith(
|
||||
query,
|
||||
update
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove the manager for non-group subscriptions', function (done) {
|
||||
this.SubscriptionUpdater.updateAdmin(
|
||||
it('should remove the manager for non-group subscriptions', async function () {
|
||||
await this.SubscriptionUpdater.promises.updateAdmin(
|
||||
this.subscription,
|
||||
this.otherUserId,
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
const query = {
|
||||
_id: ObjectId(this.subscription._id),
|
||||
customAccount: true,
|
||||
}
|
||||
const update = {
|
||||
$set: {
|
||||
admin_id: ObjectId(this.otherUserId),
|
||||
manager_ids: [ObjectId(this.otherUserId)],
|
||||
},
|
||||
}
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledOnce
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledWith(
|
||||
query,
|
||||
update
|
||||
)
|
||||
done()
|
||||
}
|
||||
this.otherUserId
|
||||
)
|
||||
const query = {
|
||||
_id: ObjectId(this.subscription._id),
|
||||
customAccount: true,
|
||||
}
|
||||
const update = {
|
||||
$set: {
|
||||
admin_id: ObjectId(this.otherUserId),
|
||||
manager_ids: [ObjectId(this.otherUserId)],
|
||||
},
|
||||
}
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledOnce
|
||||
this.SubscriptionModel.updateOne.should.have.been.calledWith(
|
||||
query,
|
||||
update
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('syncSubscription', function () {
|
||||
beforeEach(function () {
|
||||
this.SubscriptionLocator.getUsersSubscription.callsArgWith(
|
||||
1,
|
||||
null,
|
||||
this.SubscriptionLocator.promises.getUsersSubscription.resolves(
|
||||
this.subscription
|
||||
)
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly = sinon
|
||||
.stub()
|
||||
.yields()
|
||||
})
|
||||
|
||||
it('should update the subscription if the user already is admin of one', function (done) {
|
||||
this.SubscriptionUpdater.syncSubscription(
|
||||
it('should update the subscription if the user already is admin of one', async function () {
|
||||
await this.SubscriptionUpdater.promises.syncSubscription(
|
||||
this.recurlySubscription,
|
||||
this.adminUser._id,
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
this.SubscriptionLocator.getUsersSubscription
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
this.adminUser._id
|
||||
)
|
||||
this.SubscriptionLocator.promises.getUsersSubscription
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should not call updateFeatures with group subscription if recurly subscription is not expired', function (done) {
|
||||
this.SubscriptionUpdater.syncSubscription(
|
||||
it('should not call updateFeatures with group subscription if recurly subscription is not expired', async function () {
|
||||
await this.SubscriptionUpdater.promises.syncSubscription(
|
||||
this.recurlySubscription,
|
||||
this.adminUser._id,
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
this.SubscriptionLocator.getUsersSubscription
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
this.UserFeaturesUpdater.updateFeatures.called.should.equal(false)
|
||||
done()
|
||||
}
|
||||
this.adminUser._id
|
||||
)
|
||||
this.SubscriptionLocator.promises.getUsersSubscription
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
this.UserFeaturesUpdater.promises.updateFeatures.called.should.equal(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateSubscriptionFromRecurly', function () {
|
||||
beforeEach(function () {
|
||||
this.FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(2)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
this.subscription.member_ids = []
|
||||
})
|
||||
|
||||
it('should update the subscription with token etc when not expired', function (done) {
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
it('should update the subscription with token etc when not expired', async function () {
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
this.subscription.recurlySubscription_id.should.equal(
|
||||
this.recurlySubscription.uuid
|
||||
)
|
||||
this.subscription.planCode.should.equal(
|
||||
this.recurlySubscription.plan.plan_code
|
||||
)
|
||||
this.subscription.save.called.should.equal(true)
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
this.subscription.recurlySubscription_id.should.equal(
|
||||
this.recurlySubscription.uuid
|
||||
)
|
||||
this.subscription.planCode.should.equal(
|
||||
this.recurlySubscription.plan.plan_code
|
||||
)
|
||||
this.subscription.save.called.should.equal(true)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should remove the subscription when expired', function (done) {
|
||||
it('should remove the subscription when expired', async function () {
|
||||
this.recurlySubscription.state = 'expired'
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
||||
it('should update all the users features', function (done) {
|
||||
it('should update all the users features', async function () {
|
||||
this.subscription.member_ids = this.allUserIds
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.allUserIds[0])
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.allUserIds[1])
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.allUserIds[2])
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.adminUser._id)
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.allUserIds[0])
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.allUserIds[1])
|
||||
.should.equal(true)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.allUserIds[2])
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should set group to true and save how many members can be added to group', function (done) {
|
||||
this.PlansLocator.findLocalPlanInSettings
|
||||
.withArgs(this.recurlySubscription.plan.plan_code)
|
||||
.returns({ groupPlan: true, membersLimit: 5 })
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
it('should set group to true and save how many members can be added to group', async function () {
|
||||
this.recurlyPlan.groupPlan = true
|
||||
this.recurlyPlan.membersLimit = 5
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
this.subscription.membersLimit.should.equal(5)
|
||||
this.subscription.groupPlan.should.equal(true)
|
||||
this.subscription.member_ids.should.deep.equal([
|
||||
this.subscription.admin_id,
|
||||
])
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
this.subscription.membersLimit.should.equal(5)
|
||||
this.subscription.groupPlan.should.equal(true)
|
||||
this.subscription.member_ids.should.deep.equal([
|
||||
this.subscription.admin_id,
|
||||
])
|
||||
})
|
||||
|
||||
it('should delete and replace subscription when downgrading from group to individual plan', function (done) {
|
||||
this.PlansLocator.findLocalPlanInSettings
|
||||
.withArgs(this.recurlySubscription.plan.plan_code)
|
||||
.returns({ groupPlan: false })
|
||||
this.SubscriptionUpdater._deleteAndReplaceSubscriptionFromRecurly = sinon
|
||||
.stub()
|
||||
.yields()
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
it('should delete and replace subscription when downgrading from group to individual plan', async function () {
|
||||
this.recurlyPlan.groupPlan = false
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.groupSubscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
||||
it('should not set group to true or set groupPlan', function (done) {
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
it('should not set group to true or set groupPlan', async function () {
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
err => {
|
||||
if (err != null) {
|
||||
return done(err)
|
||||
}
|
||||
assert.notEqual(this.subscription.membersLimit, 5)
|
||||
assert.notEqual(this.subscription.groupPlan, true)
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
assert.notEqual(this.subscription.membersLimit, 5)
|
||||
assert.notEqual(this.subscription.groupPlan, true)
|
||||
})
|
||||
|
||||
describe('when the plan allows adding more seats', function () {
|
||||
beforeEach(function () {
|
||||
this.membersLimitAddOn = 'add_on1'
|
||||
this.PlansLocator.findLocalPlanInSettings
|
||||
.withArgs(this.recurlySubscription.plan.plan_code)
|
||||
.returns({
|
||||
groupPlan: true,
|
||||
membersLimit: 5,
|
||||
membersLimitAddOn: this.membersLimitAddOn,
|
||||
})
|
||||
this.recurlyPlan.groupPlan = true
|
||||
this.recurlyPlan.membersLimit = 5
|
||||
this.recurlyPlan.membersLimitAddOn = this.membersLimitAddOn
|
||||
})
|
||||
|
||||
function expectMembersLimit(limit) {
|
||||
it('should set the membersLimit accordingly', function (done) {
|
||||
this.SubscriptionUpdater.updateSubscriptionFromRecurly(
|
||||
it('should set the membersLimit accordingly', async function () {
|
||||
await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
|
||||
this.recurlySubscription,
|
||||
this.subscription,
|
||||
{},
|
||||
error => {
|
||||
if (error) return done(error)
|
||||
|
||||
expect(this.subscription.membersLimit).to.equal(limit)
|
||||
done()
|
||||
}
|
||||
{}
|
||||
)
|
||||
expect(this.subscription.membersLimit).to.equal(limit)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -431,117 +376,34 @@ describe('SubscriptionUpdater', function () {
|
||||
})
|
||||
|
||||
describe('addUserToGroup', function () {
|
||||
beforeEach(function () {
|
||||
this.FeaturesUpdater.refreshFeatures = sinon.stub().yields(null, {})
|
||||
this.FeaturesUpdater.isFeatureSetBetter = sinon.stub()
|
||||
this.FeaturesUpdater.isFeatureSetBetter
|
||||
.withArgs(
|
||||
{
|
||||
collaborators: 10,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
},
|
||||
{}
|
||||
)
|
||||
.returns(true)
|
||||
this.FeaturesUpdater.isFeatureSetBetter
|
||||
.withArgs(
|
||||
{
|
||||
collaborators: -1,
|
||||
compileTimeout: 240,
|
||||
dropbox: true,
|
||||
},
|
||||
{
|
||||
collaborators: 10,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
}
|
||||
)
|
||||
.returns(true)
|
||||
this.FeaturesUpdater.isFeatureSetBetter
|
||||
.withArgs(
|
||||
{
|
||||
collaborators: -1,
|
||||
compileTimeout: 240,
|
||||
dropbox: true,
|
||||
},
|
||||
{}
|
||||
)
|
||||
.returns(true)
|
||||
this.PlansLocator.findLocalPlanInSettings = sinon.stub()
|
||||
this.PlansLocator.findLocalPlanInSettings
|
||||
.withArgs(this.groupSubscription.planCode)
|
||||
.returns({
|
||||
planCode: this.groupSubscription.planCode,
|
||||
features: {
|
||||
collaborators: 10,
|
||||
compileTimeout: 60,
|
||||
dropbox: true,
|
||||
},
|
||||
})
|
||||
this.PlansLocator.findLocalPlanInSettings
|
||||
.withArgs(this.betterGroupSubscription.planCode)
|
||||
.returns({
|
||||
planCode: this.betterGroupSubscription.planCode,
|
||||
features: {
|
||||
collaborators: -1,
|
||||
compileTimeout: 240,
|
||||
dropbox: true,
|
||||
},
|
||||
})
|
||||
it('should add the user ids to the group as a set', async function () {
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
const searchOps = { _id: this.subscription._id }
|
||||
const insertOperation = {
|
||||
$addToSet: { member_ids: this.otherUserId },
|
||||
}
|
||||
this.SubscriptionModel.updateOne
|
||||
.calledWith(searchOps, insertOperation)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should add the user ids to the group as a set', function (done) {
|
||||
this.SubscriptionUpdater.addUserToGroup(
|
||||
it('should update the users features', async function () {
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
const searchOps = { _id: this.subscription._id }
|
||||
const insertOperation = {
|
||||
$addToSet: { member_ids: this.otherUserId },
|
||||
}
|
||||
this.updateStub
|
||||
.calledWith(searchOps, insertOperation)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should update the users features', function (done) {
|
||||
this.SubscriptionUpdater.addUserToGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property', function (done) {
|
||||
this.SubscriptionUpdater.addUserToGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-plan-code',
|
||||
'group_subscription'
|
||||
)
|
||||
done()
|
||||
}
|
||||
this.otherUserId
|
||||
)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property to the best plan with 1 group subscription', async function () {
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
|
||||
.stub()
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions
|
||||
.withArgs(this.otherUserId)
|
||||
.returns([this.groupSubscription])
|
||||
.resolves([this.groupSubscription])
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.groupSubscription._id,
|
||||
this.otherUserId
|
||||
@@ -555,10 +417,9 @@ describe('SubscriptionUpdater', function () {
|
||||
})
|
||||
|
||||
it('should set the group plan code user property to the best plan with 2 group subscriptions', async function () {
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
|
||||
.stub()
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions
|
||||
.withArgs(this.otherUserId)
|
||||
.returns([this.groupSubscription, this.betterGroupSubscription])
|
||||
.resolves([this.groupSubscription, this.betterGroupSubscription])
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.betterGroupSubscription._id,
|
||||
this.otherUserId
|
||||
@@ -572,10 +433,9 @@ describe('SubscriptionUpdater', function () {
|
||||
})
|
||||
|
||||
it('should set the group plan code user property to the best plan with 2 group subscriptions in reverse order', async function () {
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
|
||||
.stub()
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions
|
||||
.withArgs(this.otherUserId)
|
||||
.returns([this.betterGroupSubscription, this.groupSubscription])
|
||||
.resolves([this.betterGroupSubscription, this.groupSubscription])
|
||||
await this.SubscriptionUpdater.promises.addUserToGroup(
|
||||
this.betterGroupSubscription._id,
|
||||
this.otherUserId
|
||||
@@ -591,95 +451,84 @@ describe('SubscriptionUpdater', function () {
|
||||
|
||||
describe('removeUserFromGroups', function () {
|
||||
beforeEach(function () {
|
||||
this.FeaturesUpdater.refreshFeatures = sinon.stub().yields(null, {})
|
||||
this.FeaturesUpdater.isFeatureSetBetter = sinon.stub().returns(true)
|
||||
this.UserGetter.getUser.yields(null, {})
|
||||
this.fakeSubscriptions = [{ _id: 'fake-id-1' }, { _id: 'fake-id-2' }]
|
||||
this.SubscriptionLocator.getMemberSubscriptions.yields(
|
||||
null,
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions.resolves(
|
||||
this.fakeSubscriptions
|
||||
)
|
||||
this.SubscriptionLocator.promises.getMemberSubscriptions.returns([])
|
||||
})
|
||||
|
||||
it('should pull the users id from the group', function (done) {
|
||||
this.SubscriptionUpdater.removeUserFromGroup(
|
||||
it('should pull the users id from the group', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
const removeOperation = { $pull: { member_ids: this.otherUserId } }
|
||||
this.SubscriptionModel.updateOne
|
||||
.calledWith({ _id: this.subscription._id }, removeOperation)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property when removing user from group', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
const removeOperation = { $pull: { member_ids: this.otherUserId } }
|
||||
this.updateStub
|
||||
.calledWith({ _id: this.subscription._id }, removeOperation)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
'group-subscription-plan-code',
|
||||
null
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property when removing user from group', function (done) {
|
||||
this.SubscriptionUpdater.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
it('should set the group plan code user property when removing user from all groups', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromAllGroups(
|
||||
this.otherUserId
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-plan-code',
|
||||
null
|
||||
)
|
||||
done()
|
||||
}
|
||||
'group-subscription-plan-code',
|
||||
null
|
||||
)
|
||||
})
|
||||
|
||||
it('should set the group plan code user property when removing user from all groups', function (done) {
|
||||
this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
|
||||
sinon.assert.calledWith(
|
||||
this.AnalyticsManager.setUserPropertyForUser,
|
||||
this.otherUserId,
|
||||
'group-subscription-plan-code',
|
||||
null
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should pull the users id from all groups', function (done) {
|
||||
this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
|
||||
const filter = { _id: ['fake-id-1', 'fake-id-2'] }
|
||||
const removeOperation = { $pull: { member_ids: this.otherUserId } }
|
||||
sinon.assert.calledWith(this.updateManyStub, filter, removeOperation)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should update the users features', function (done) {
|
||||
this.SubscriptionUpdater.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId,
|
||||
() => {
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
done()
|
||||
}
|
||||
it('should pull the users id from all groups', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromAllGroups(
|
||||
this.otherUserId
|
||||
)
|
||||
const filter = { _id: ['fake-id-1', 'fake-id-2'] }
|
||||
const removeOperation = { $pull: { member_ids: this.otherUserId } }
|
||||
sinon.assert.calledWith(
|
||||
this.SubscriptionModel.updateMany,
|
||||
filter,
|
||||
removeOperation
|
||||
)
|
||||
})
|
||||
|
||||
it('should update the users features', async function () {
|
||||
await this.SubscriptionUpdater.promises.removeUserFromGroup(
|
||||
this.subscription._id,
|
||||
this.otherUserId
|
||||
)
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.otherUserId)
|
||||
.should.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('deleteSubscription', function () {
|
||||
beforeEach(function (done) {
|
||||
beforeEach(async function () {
|
||||
this.subscription = {
|
||||
_id: ObjectId().toString(),
|
||||
mock: 'subscription',
|
||||
admin_id: ObjectId(),
|
||||
member_ids: [ObjectId(), ObjectId(), ObjectId()],
|
||||
}
|
||||
this.SubscriptionLocator.getSubscription = sinon
|
||||
.stub()
|
||||
.yields(null, this.subscription)
|
||||
this.FeaturesUpdater.refreshFeatures = sinon.stub().yields()
|
||||
this.SubscriptionUpdater.deleteSubscription(this.subscription, {}, done)
|
||||
await this.SubscriptionUpdater.promises.deleteSubscription(
|
||||
this.subscription,
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove the subscription', function () {
|
||||
@@ -689,14 +538,14 @@ describe('SubscriptionUpdater', function () {
|
||||
})
|
||||
|
||||
it('should downgrade the admin_id', function () {
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(this.subscription.admin_id)
|
||||
.should.equal(true)
|
||||
})
|
||||
|
||||
it('should downgrade all of the members', function () {
|
||||
for (const userId of this.subscription.member_ids) {
|
||||
this.FeaturesUpdater.refreshFeatures
|
||||
this.FeaturesUpdater.promises.refreshFeatures
|
||||
.calledWith(userId)
|
||||
.should.equal(true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user