overleaf/services/web/test/acceptance/src/FeatureUpdaterTests.js

383 lines
10 KiB
JavaScript
Raw Normal View History

const { expect } = require('chai')
const UserHelper = require('./helpers/UserHelper')
const settings = require('settings-sharelatex')
const { ObjectId } = require('mongodb')
const { Subscription } = require('../../../app/src/models/Subscription')
const { User } = require('../../../app/src/models/User')
const FeaturesUpdater = require('../../../app/src/Features/Subscription/FeaturesUpdater')
const MockV1ApiClass = require('./mocks/MockV1Api')
const logger = require('logger-sharelatex')
logger.logger.level('error')
let MockV1Api
before(function () {
MockV1Api = MockV1ApiClass.instance()
})
const syncUserAndGetFeatures = function (user, callback) {
FeaturesUpdater.refreshFeatures(user._id, error => {
if (error) {
return callback(error)
}
User.findById(user._id, (error, user) => {
if (error) {
return callback(error)
}
const { features } = user.toObject()
delete features.$init // mongoose internals
callback(null, features)
})
})
}
describe('FeatureUpdater.refreshFeatures', function () {
let userHelper, user
beforeEach(async function () {
userHelper = await UserHelper.createUser()
user = userHelper.user
})
describe('when user has no subscriptions', function () {
it('should set their features to the basic set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
expect(features).to.deep.equal(settings.defaultFeatures)
done()
})
})
})
describe('when the user has an individual subscription', function () {
beforeEach(function () {
Subscription.create({
admin_id: user._id,
manager_ids: [user._id],
planCode: 'collaborator',
customAccount: true,
})
}) // returns a promise
it('should set their features to the upgraded set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const plan = settings.plans.find(
plan => plan.planCode === 'collaborator'
)
expect(features).to.deep.equal(plan.features)
done()
})
})
})
describe('when the user is in a group subscription', function () {
beforeEach(function () {
const groupAdminId = ObjectId()
Subscription.create({
admin_id: groupAdminId,
manager_ids: [groupAdminId],
member_ids: [user._id],
groupAccount: true,
planCode: 'collaborator',
customAccount: true,
})
}) // returns a promise
it('should set their features to the upgraded set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const plan = settings.plans.find(
plan => plan.planCode === 'collaborator'
)
expect(features).to.deep.equal(plan.features)
done()
})
})
})
describe('when the user has bonus features', function () {
beforeEach(function () {
return User.updateOne(
{
_id: user._id,
},
{
refered_user_count: 10,
}
)
}) // returns a promise
it('should set their features to the bonus set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
expect(features).to.deep.equal(
Object.assign(
{},
settings.defaultFeatures,
settings.bonus_features[9]
)
)
done()
})
})
})
describe('when the user has affiliations', function () {
let email2, institutionId, hostname
beforeEach(async function () {
institutionId = MockV1Api.createInstitution({ commonsAccount: true })
hostname = 'institution.edu'
MockV1Api.addInstitutionDomain(institutionId, hostname, {
confirmed: true,
})
email2 = `${user._id}@${hostname}`
userHelper = await UserHelper.loginUser(
userHelper.getDefaultEmailPassword()
)
await userHelper.addEmail(email2)
this.institutionPlan = settings.plans.find(
plan => plan.planCode === settings.institutionPlanCode
)
})
it('should not set their features if email is not confirmed', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
expect(features).to.deep.equal(settings.defaultFeatures)
done()
})
})
describe('when email is confirmed', function () {
beforeEach(async function () {
await userHelper.confirmEmail(user._id, email2)
})
it('should set their features', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
expect(features).to.deep.equal(this.institutionPlan.features)
done()
})
})
describe('when domain is not confirmed as part of institution', function () {
beforeEach(function () {
MockV1Api.updateInstitutionDomain(institutionId, hostname, {
confirmed: false,
})
})
it('should not set their features', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
expect(features).to.deep.equal(settings.defaultFeatures)
done()
})
})
})
})
})
describe('when the user is due bonus features and has extra features that no longer apply', function () {
beforeEach(function () {
return User.updateOne(
{
_id: user._id,
},
{
refered_user_count: 10,
'features.github': true,
}
)
}) // returns a promise
it('should set their features to the bonus set and downgrade the extras', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
expect(features).to.deep.equal(
Object.assign(
{},
settings.defaultFeatures,
settings.bonus_features[9]
)
)
done()
})
})
})
describe('when the user has a v1 plan', function () {
beforeEach(function () {
MockV1Api.setUser(42, { plan_name: 'free' })
return User.updateOne(
{
_id: user._id,
},
{
overleaf: {
id: 42,
},
}
)
}) // returns a promise
it('should set their features to the v1 plan', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const plan = settings.plans.find(plan => plan.planCode === 'v1_free')
expect(features).to.deep.equal(plan.features)
done()
})
})
})
describe('when the user has a v1 plan and bonus features', function () {
beforeEach(function () {
MockV1Api.setUser(42, { plan_name: 'free' })
return User.updateOne(
{
_id: user._id,
},
{
overleaf: {
id: 42,
},
refered_user_count: 10,
}
)
}) // returns a promise
it('should set their features to the best of the v1 plan and bonus features', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const v1plan = settings.plans.find(plan => plan.planCode === 'v1_free')
const expectedFeatures = Object.assign(
{},
v1plan.features,
settings.bonus_features[9]
)
expect(features).to.deep.equal(expectedFeatures)
done()
})
})
})
describe('when the user has a group and personal subscription', function () {
beforeEach(function (done) {
const groupAdminId = ObjectId()
Subscription.create(
{
admin_id: user._id,
manager_ids: [user._id],
planCode: 'professional',
customAccount: true,
},
error => {
if (error) {
throw error
}
Subscription.create(
{
admin_id: groupAdminId,
manager_ids: [groupAdminId],
member_ids: [user._id],
groupAccount: true,
planCode: 'collaborator',
customAccount: true,
},
done
)
}
)
})
it('should set their features to the best set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const plan = settings.plans.find(
plan => plan.planCode === 'professional'
)
expect(features).to.deep.equal(plan.features)
done()
})
})
})
describe('when the notifyV1Flag is passed', function () {
beforeEach(function () {
User.updateOne(
{
_id: user._id,
},
{
overleaf: {
id: 42,
},
}
)
}) // returns a promise
})
describe('when the user has features overrides', function () {
beforeEach(function () {
const futureDate = new Date()
futureDate.setDate(futureDate.getDate() + 1)
return User.updateOne(
{
_id: user._id,
},
{
featuresOverrides: [
{
features: {
github: true,
},
},
{
features: {
dropbox: true,
},
expiresAt: new Date(1990, 12, 25),
},
{
features: {
trackChanges: true,
},
expiresAt: futureDate,
},
],
}
)
}) // returns a promise
it('should set their features to the overridden set', function (done) {
syncUserAndGetFeatures(user, (error, features) => {
if (error) {
throw error
}
const expectedFeatures = Object.assign(settings.defaultFeatures, {
github: true,
trackChanges: true,
})
expect(features).to.deep.equal(expectedFeatures)
done()
})
})
})
})