| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- const SandboxedModule = require('sandboxed-module')
- const { expect } = require('chai')
- const sinon = require('sinon')
- const modulePath = '../../../../app/src/Features/Subscription/FeaturesUpdater'
- const { ObjectId } = require('mongodb')
- describe('FeaturesUpdater', function () {
- beforeEach(function () {
- this.user_id = ObjectId().toString()
- this.FeaturesUpdater = SandboxedModule.require(modulePath, {
- requires: {
- './UserFeaturesUpdater': (this.UserFeaturesUpdater = {}),
- './SubscriptionLocator': (this.SubscriptionLocator = {}),
- './PlansLocator': (this.PlansLocator = {}),
- 'settings-sharelatex': (this.Settings = {}),
- '../Referal/ReferalFeatures': (this.ReferalFeatures = {}),
- './V1SubscriptionManager': (this.V1SubscriptionManager = {}),
- '../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
- '../User/UserGetter': (this.UserGetter = {}),
- '../../infrastructure/Modules': (this.Modules = {
- hooks: { fire: sinon.stub() },
- }),
- },
- })
- })
- 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
- }
- )
- })
- describe('normally', function () {
- beforeEach(function () {
- this.FeaturesUpdater.refreshFeatures(
- this.user_id,
- 'test',
- this.callback
- )
- })
- 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)
- })
- })
- 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
- )
- })
- 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',
- }
- )
- ).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()
- })
- })
- 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()
- })
- })
- })
- describe('when getUser produces an error', function () {
- beforeEach(function () {
- this.UserGetter.getUser = sinon
- .stub()
- .callsArgWith(2, 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()
- })
- })
- })
- describe('when getUser does not find a user', function () {
- beforeEach(function () {
- this.UserGetter.getUser = sinon.stub().callsArgWith(2, null, null)
- })
- it('should not call refreshFeatures', function (done) {
- this.call(() => {
- expect(this.FeaturesUpdater.refreshFeatures.callCount).to.equal(0)
- done()
- })
- })
- it('should not produce an error', function (done) {
- this.call(err => {
- expect(err).to.not.exist
- done()
- })
- })
- })
- })
- })
|