SubscriptionUpdaterTests.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. const SandboxedModule = require('sandboxed-module')
  2. const sinon = require('sinon')
  3. const modulePath =
  4. '../../../../app/src/Features/Subscription/SubscriptionUpdater'
  5. const { assert, expect } = require('chai')
  6. const { ObjectId } = require('mongodb')
  7. describe('SubscriptionUpdater', function () {
  8. beforeEach(function () {
  9. this.recurlySubscription = {
  10. uuid: '1238uoijdasjhd',
  11. plan: {
  12. plan_code: 'kjhsakjds',
  13. },
  14. }
  15. this.adminUser = { _id: (this.adminuser_id = '5208dd34438843e2db000007') }
  16. this.otherUserId = '5208dd34438842e2db000005'
  17. this.allUserIds = ['13213', 'dsadas', 'djsaiud89']
  18. this.subscription = {
  19. _id: '111111111111111111111111',
  20. admin_id: this.adminUser._id,
  21. manager_ids: [this.adminUser._id],
  22. member_ids: [],
  23. save: sinon.stub().callsArgWith(0),
  24. planCode: 'student_or_something',
  25. }
  26. this.user_id = this.adminuser_id
  27. this.groupSubscription = {
  28. _id: '222222222222222222222222',
  29. admin_id: this.adminUser._id,
  30. manager_ids: [this.adminUser._id],
  31. member_ids: this.allUserIds,
  32. save: sinon.stub().callsArgWith(0),
  33. groupPlan: true,
  34. planCode: 'group_subscription',
  35. }
  36. this.betterGroupSubscription = {
  37. _id: '999999999999999999999999',
  38. admin_id: this.adminUser._id,
  39. manager_ids: [this.adminUser._id],
  40. member_ids: [this.otherUserId],
  41. save: sinon.stub().callsArgWith(0),
  42. groupPlan: true,
  43. planCode: 'better_group_subscription',
  44. }
  45. this.updateStub = sinon.stub().callsArgWith(2, null)
  46. this.updateManyStub = sinon.stub().callsArgWith(2, null)
  47. this.findOneAndUpdateStub = sinon
  48. .stub()
  49. .callsArgWith(2, null, this.subscription)
  50. const subscription = this.subscription
  51. this.SubscriptionModel = class {
  52. constructor(opts) {
  53. // Always return our mock subscription when creating a new one
  54. subscription.admin_id = opts.admin_id
  55. subscription.manager_ids = [opts.admin_id]
  56. return subscription
  57. }
  58. save() {
  59. return subscription
  60. }
  61. }
  62. this.SubscriptionModel.deleteOne = sinon.stub().yields()
  63. this.SubscriptionModel.updateOne = this.updateStub
  64. this.SubscriptionModel.updateMany = this.updateManyStub
  65. this.SubscriptionModel.findOneAndUpdate = this.findOneAndUpdateStub
  66. this.SubscriptionLocator = {
  67. getUsersSubscription: sinon.stub(),
  68. getGroupSubscriptionMemberOf: sinon.stub(),
  69. getMemberSubscriptions: sinon.stub().yields(null, []),
  70. promises: {
  71. getMemberSubscriptions: sinon.stub().returns([this.groupSubscription]),
  72. },
  73. }
  74. this.Settings = {
  75. defaultPlanCode: 'personal',
  76. defaultFeatures: { default: 'features' },
  77. }
  78. this.UserFeaturesUpdater = { updateFeatures: sinon.stub().yields() }
  79. this.PlansLocator = { findLocalPlanInSettings: sinon.stub().returns({}) }
  80. this.UserGetter = {
  81. getUsers(memberIds, projection, callback) {
  82. const users = memberIds.map(id => ({ _id: id }))
  83. callback(null, users)
  84. },
  85. getUser: sinon.stub(),
  86. }
  87. this.ReferalFeatures = { getBonusFeatures: sinon.stub().callsArgWith(1) }
  88. this.Modules = { hooks: { fire: sinon.stub().callsArgWith(2, null, null) } }
  89. this.FeaturesUpdater = {
  90. refreshFeatures: sinon.stub().yields(),
  91. planCodeToFeatures: sinon.stub(),
  92. }
  93. this.DeletedSubscription = {
  94. findOneAndUpdate: sinon.stub().yields(),
  95. }
  96. this.AnalyticsManager = {
  97. setUserPropertyForUser: sinon.stub(),
  98. }
  99. this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
  100. requires: {
  101. mongodb: { ObjectId },
  102. '../../models/Subscription': {
  103. Subscription: this.SubscriptionModel,
  104. },
  105. './UserFeaturesUpdater': this.UserFeaturesUpdater,
  106. './SubscriptionLocator': this.SubscriptionLocator,
  107. '../User/UserGetter': this.UserGetter,
  108. './PlansLocator': this.PlansLocator,
  109. '@overleaf/settings': this.Settings,
  110. '../../infrastructure/mongodb': { db: {}, ObjectId },
  111. './FeaturesUpdater': this.FeaturesUpdater,
  112. '../../models/DeletedSubscription': {
  113. DeletedSubscription: this.DeletedSubscription,
  114. },
  115. '../Analytics/AnalyticsManager': this.AnalyticsManager,
  116. },
  117. })
  118. })
  119. describe('updateAdmin', function () {
  120. it('should update the subscription admin', function (done) {
  121. this.subscription.groupPlan = true
  122. this.SubscriptionUpdater.updateAdmin(
  123. this.subscription,
  124. this.otherUserId,
  125. err => {
  126. if (err != null) {
  127. return done(err)
  128. }
  129. const query = {
  130. _id: ObjectId(this.subscription._id),
  131. customAccount: true,
  132. }
  133. const update = {
  134. $set: { admin_id: ObjectId(this.otherUserId) },
  135. $addToSet: { manager_ids: ObjectId(this.otherUserId) },
  136. }
  137. this.SubscriptionModel.updateOne.should.have.been.calledOnce
  138. this.SubscriptionModel.updateOne.should.have.been.calledWith(
  139. query,
  140. update
  141. )
  142. done()
  143. }
  144. )
  145. })
  146. it('should remove the manager for non-group subscriptions', function (done) {
  147. this.SubscriptionUpdater.updateAdmin(
  148. this.subscription,
  149. this.otherUserId,
  150. err => {
  151. if (err != null) {
  152. return done(err)
  153. }
  154. const query = {
  155. _id: ObjectId(this.subscription._id),
  156. customAccount: true,
  157. }
  158. const update = {
  159. $set: {
  160. admin_id: ObjectId(this.otherUserId),
  161. manager_ids: [ObjectId(this.otherUserId)],
  162. },
  163. }
  164. this.SubscriptionModel.updateOne.should.have.been.calledOnce
  165. this.SubscriptionModel.updateOne.should.have.been.calledWith(
  166. query,
  167. update
  168. )
  169. done()
  170. }
  171. )
  172. })
  173. })
  174. describe('syncSubscription', function () {
  175. beforeEach(function () {
  176. this.SubscriptionLocator.getUsersSubscription.callsArgWith(
  177. 1,
  178. null,
  179. this.subscription
  180. )
  181. this.SubscriptionUpdater.updateSubscriptionFromRecurly = sinon
  182. .stub()
  183. .yields()
  184. })
  185. it('should update the subscription if the user already is admin of one', function (done) {
  186. this.SubscriptionUpdater.syncSubscription(
  187. this.recurlySubscription,
  188. this.adminUser._id,
  189. err => {
  190. if (err != null) {
  191. return done(err)
  192. }
  193. this.SubscriptionLocator.getUsersSubscription
  194. .calledWith(this.adminUser._id)
  195. .should.equal(true)
  196. done()
  197. }
  198. )
  199. })
  200. it('should not call updateFeatures with group subscription if recurly subscription is not expired', function (done) {
  201. this.SubscriptionUpdater.syncSubscription(
  202. this.recurlySubscription,
  203. this.adminUser._id,
  204. err => {
  205. if (err != null) {
  206. return done(err)
  207. }
  208. this.SubscriptionLocator.getUsersSubscription
  209. .calledWith(this.adminUser._id)
  210. .should.equal(true)
  211. this.UserFeaturesUpdater.updateFeatures.called.should.equal(false)
  212. done()
  213. }
  214. )
  215. })
  216. })
  217. describe('updateSubscriptionFromRecurly', function () {
  218. beforeEach(function () {
  219. this.FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(2)
  220. })
  221. afterEach(function () {
  222. this.subscription.member_ids = []
  223. })
  224. it('should update the subscription with token etc when not expired', function (done) {
  225. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  226. this.recurlySubscription,
  227. this.subscription,
  228. {},
  229. err => {
  230. if (err != null) {
  231. return done(err)
  232. }
  233. this.subscription.recurlySubscription_id.should.equal(
  234. this.recurlySubscription.uuid
  235. )
  236. this.subscription.planCode.should.equal(
  237. this.recurlySubscription.plan.plan_code
  238. )
  239. this.subscription.save.called.should.equal(true)
  240. this.FeaturesUpdater.refreshFeatures
  241. .calledWith(this.adminUser._id)
  242. .should.equal(true)
  243. done()
  244. }
  245. )
  246. })
  247. it('should remove the subscription when expired', function (done) {
  248. this.recurlySubscription.state = 'expired'
  249. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  250. this.recurlySubscription,
  251. this.subscription,
  252. {},
  253. err => {
  254. if (err != null) {
  255. return done(err)
  256. }
  257. done()
  258. }
  259. )
  260. })
  261. it('should update all the users features', function (done) {
  262. this.subscription.member_ids = this.allUserIds
  263. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  264. this.recurlySubscription,
  265. this.subscription,
  266. {},
  267. err => {
  268. if (err != null) {
  269. return done(err)
  270. }
  271. this.FeaturesUpdater.refreshFeatures
  272. .calledWith(this.adminUser._id)
  273. .should.equal(true)
  274. this.FeaturesUpdater.refreshFeatures
  275. .calledWith(this.allUserIds[0])
  276. .should.equal(true)
  277. this.FeaturesUpdater.refreshFeatures
  278. .calledWith(this.allUserIds[1])
  279. .should.equal(true)
  280. this.FeaturesUpdater.refreshFeatures
  281. .calledWith(this.allUserIds[2])
  282. .should.equal(true)
  283. done()
  284. }
  285. )
  286. })
  287. it('should set group to true and save how many members can be added to group', function (done) {
  288. this.PlansLocator.findLocalPlanInSettings
  289. .withArgs(this.recurlySubscription.plan.plan_code)
  290. .returns({ groupPlan: true, membersLimit: 5 })
  291. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  292. this.recurlySubscription,
  293. this.subscription,
  294. {},
  295. err => {
  296. if (err != null) {
  297. return done(err)
  298. }
  299. this.subscription.membersLimit.should.equal(5)
  300. this.subscription.groupPlan.should.equal(true)
  301. this.subscription.member_ids.should.deep.equal([
  302. this.subscription.admin_id,
  303. ])
  304. done()
  305. }
  306. )
  307. })
  308. it('should delete and replace subscription when downgrading from group to individual plan', function (done) {
  309. this.PlansLocator.findLocalPlanInSettings
  310. .withArgs(this.recurlySubscription.plan.plan_code)
  311. .returns({ groupPlan: false })
  312. this.SubscriptionUpdater._deleteAndReplaceSubscriptionFromRecurly = sinon
  313. .stub()
  314. .yields()
  315. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  316. this.recurlySubscription,
  317. this.groupSubscription,
  318. {},
  319. err => {
  320. if (err != null) {
  321. return done(err)
  322. }
  323. done()
  324. }
  325. )
  326. })
  327. it('should not set group to true or set groupPlan', function (done) {
  328. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  329. this.recurlySubscription,
  330. this.subscription,
  331. {},
  332. err => {
  333. if (err != null) {
  334. return done(err)
  335. }
  336. assert.notEqual(this.subscription.membersLimit, 5)
  337. assert.notEqual(this.subscription.groupPlan, true)
  338. done()
  339. }
  340. )
  341. })
  342. describe('when the plan allows adding more seats', function () {
  343. beforeEach(function () {
  344. this.membersLimitAddOn = 'add_on1'
  345. this.PlansLocator.findLocalPlanInSettings
  346. .withArgs(this.recurlySubscription.plan.plan_code)
  347. .returns({
  348. groupPlan: true,
  349. membersLimit: 5,
  350. membersLimitAddOn: this.membersLimitAddOn,
  351. })
  352. })
  353. function expectMembersLimit(limit) {
  354. it('should set the membersLimit accordingly', function (done) {
  355. this.SubscriptionUpdater.updateSubscriptionFromRecurly(
  356. this.recurlySubscription,
  357. this.subscription,
  358. {},
  359. error => {
  360. if (error) return done(error)
  361. expect(this.subscription.membersLimit).to.equal(limit)
  362. done()
  363. }
  364. )
  365. })
  366. }
  367. describe('when the recurlySubscription does not have add ons', function () {
  368. beforeEach(function () {
  369. delete this.recurlySubscription.subscription_add_ons
  370. })
  371. expectMembersLimit(5)
  372. })
  373. describe('when the recurlySubscription has non-matching add ons', function () {
  374. beforeEach(function () {
  375. this.recurlySubscription.subscription_add_ons = [
  376. { add_on_code: 'add_on_99', quantity: 3 },
  377. ]
  378. })
  379. expectMembersLimit(5)
  380. })
  381. describe('when the recurlySubscription has a matching add on', function () {
  382. beforeEach(function () {
  383. this.recurlySubscription.subscription_add_ons = [
  384. { add_on_code: this.membersLimitAddOn, quantity: 10 },
  385. ]
  386. })
  387. expectMembersLimit(15)
  388. })
  389. // NOTE: This is unexpected, but we are going to support it anyways.
  390. describe('when the recurlySubscription has multiple matching add ons', function () {
  391. beforeEach(function () {
  392. this.recurlySubscription.subscription_add_ons = [
  393. { add_on_code: this.membersLimitAddOn, quantity: 10 },
  394. { add_on_code: this.membersLimitAddOn, quantity: 3 },
  395. ]
  396. })
  397. expectMembersLimit(18)
  398. })
  399. })
  400. })
  401. describe('addUserToGroup', function () {
  402. beforeEach(function () {
  403. this.FeaturesUpdater.refreshFeatures = sinon.stub().yields(null, {})
  404. this.FeaturesUpdater.isFeatureSetBetter = sinon.stub()
  405. this.FeaturesUpdater.isFeatureSetBetter
  406. .withArgs(
  407. {
  408. collaborators: 10,
  409. compileTimeout: 60,
  410. dropbox: true,
  411. },
  412. {}
  413. )
  414. .returns(true)
  415. this.FeaturesUpdater.isFeatureSetBetter
  416. .withArgs(
  417. {
  418. collaborators: -1,
  419. compileTimeout: 240,
  420. dropbox: true,
  421. },
  422. {
  423. collaborators: 10,
  424. compileTimeout: 60,
  425. dropbox: true,
  426. }
  427. )
  428. .returns(true)
  429. this.FeaturesUpdater.isFeatureSetBetter
  430. .withArgs(
  431. {
  432. collaborators: -1,
  433. compileTimeout: 240,
  434. dropbox: true,
  435. },
  436. {}
  437. )
  438. .returns(true)
  439. this.PlansLocator.findLocalPlanInSettings = sinon.stub()
  440. this.PlansLocator.findLocalPlanInSettings
  441. .withArgs(this.groupSubscription.planCode)
  442. .returns({
  443. planCode: this.groupSubscription.planCode,
  444. features: {
  445. collaborators: 10,
  446. compileTimeout: 60,
  447. dropbox: true,
  448. },
  449. })
  450. this.PlansLocator.findLocalPlanInSettings
  451. .withArgs(this.betterGroupSubscription.planCode)
  452. .returns({
  453. planCode: this.betterGroupSubscription.planCode,
  454. features: {
  455. collaborators: -1,
  456. compileTimeout: 240,
  457. dropbox: true,
  458. },
  459. })
  460. })
  461. it('should add the user ids to the group as a set', function (done) {
  462. this.SubscriptionUpdater.addUserToGroup(
  463. this.subscription._id,
  464. this.otherUserId,
  465. () => {
  466. const searchOps = { _id: this.subscription._id }
  467. const insertOperation = {
  468. $addToSet: { member_ids: this.otherUserId },
  469. }
  470. this.updateStub
  471. .calledWith(searchOps, insertOperation)
  472. .should.equal(true)
  473. done()
  474. }
  475. )
  476. })
  477. it('should update the users features', function (done) {
  478. this.SubscriptionUpdater.addUserToGroup(
  479. this.subscription._id,
  480. this.otherUserId,
  481. () => {
  482. this.FeaturesUpdater.refreshFeatures
  483. .calledWith(this.otherUserId)
  484. .should.equal(true)
  485. done()
  486. }
  487. )
  488. })
  489. it('should set the group plan code user property', function (done) {
  490. this.SubscriptionUpdater.addUserToGroup(
  491. this.subscription._id,
  492. this.otherUserId,
  493. () => {
  494. sinon.assert.calledWith(
  495. this.AnalyticsManager.setUserPropertyForUser,
  496. this.otherUserId,
  497. 'group-subscription-plan-code',
  498. 'group_subscription'
  499. )
  500. done()
  501. }
  502. )
  503. })
  504. it('should set the group plan code user property to the best plan with 1 group subscription', async function () {
  505. this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
  506. .stub()
  507. .withArgs(this.otherUserId)
  508. .returns([this.groupSubscription])
  509. await this.SubscriptionUpdater.promises.addUserToGroup(
  510. this.groupSubscription._id,
  511. this.otherUserId
  512. )
  513. sinon.assert.calledWith(
  514. this.AnalyticsManager.setUserPropertyForUser,
  515. this.otherUserId,
  516. 'group-subscription-plan-code',
  517. 'group_subscription'
  518. )
  519. })
  520. it('should set the group plan code user property to the best plan with 2 group subscriptions', async function () {
  521. this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
  522. .stub()
  523. .withArgs(this.otherUserId)
  524. .returns([this.groupSubscription, this.betterGroupSubscription])
  525. await this.SubscriptionUpdater.promises.addUserToGroup(
  526. this.betterGroupSubscription._id,
  527. this.otherUserId
  528. )
  529. sinon.assert.calledWith(
  530. this.AnalyticsManager.setUserPropertyForUser,
  531. this.otherUserId,
  532. 'group-subscription-plan-code',
  533. 'better_group_subscription'
  534. )
  535. })
  536. it('should set the group plan code user property to the best plan with 2 group subscriptions in reverse order', async function () {
  537. this.SubscriptionLocator.promises.getMemberSubscriptions = sinon
  538. .stub()
  539. .withArgs(this.otherUserId)
  540. .returns([this.betterGroupSubscription, this.groupSubscription])
  541. await this.SubscriptionUpdater.promises.addUserToGroup(
  542. this.betterGroupSubscription._id,
  543. this.otherUserId
  544. )
  545. sinon.assert.calledWith(
  546. this.AnalyticsManager.setUserPropertyForUser,
  547. this.otherUserId,
  548. 'group-subscription-plan-code',
  549. 'better_group_subscription'
  550. )
  551. })
  552. })
  553. describe('removeUserFromGroups', function () {
  554. beforeEach(function () {
  555. this.FeaturesUpdater.refreshFeatures = sinon.stub().yields(null, {})
  556. this.FeaturesUpdater.isFeatureSetBetter = sinon.stub().returns(true)
  557. this.UserGetter.getUser.yields(null, {})
  558. this.fakeSubscriptions = [{ _id: 'fake-id-1' }, { _id: 'fake-id-2' }]
  559. this.SubscriptionLocator.getMemberSubscriptions.yields(
  560. null,
  561. this.fakeSubscriptions
  562. )
  563. this.SubscriptionLocator.promises.getMemberSubscriptions.returns([])
  564. })
  565. it('should pull the users id from the group', function (done) {
  566. this.SubscriptionUpdater.removeUserFromGroup(
  567. this.subscription._id,
  568. this.otherUserId,
  569. () => {
  570. const removeOperation = { $pull: { member_ids: this.otherUserId } }
  571. this.updateStub
  572. .calledWith({ _id: this.subscription._id }, removeOperation)
  573. .should.equal(true)
  574. done()
  575. }
  576. )
  577. })
  578. it('should set the group plan code user property when removing user from group', function (done) {
  579. this.SubscriptionUpdater.removeUserFromGroup(
  580. this.subscription._id,
  581. this.otherUserId,
  582. () => {
  583. sinon.assert.calledWith(
  584. this.AnalyticsManager.setUserPropertyForUser,
  585. this.otherUserId,
  586. 'group-subscription-plan-code',
  587. null
  588. )
  589. done()
  590. }
  591. )
  592. })
  593. it('should set the group plan code user property when removing user from all groups', function (done) {
  594. this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
  595. sinon.assert.calledWith(
  596. this.AnalyticsManager.setUserPropertyForUser,
  597. this.otherUserId,
  598. 'group-subscription-plan-code',
  599. null
  600. )
  601. done()
  602. })
  603. })
  604. it('should pull the users id from all groups', function (done) {
  605. this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
  606. const filter = { _id: ['fake-id-1', 'fake-id-2'] }
  607. const removeOperation = { $pull: { member_ids: this.otherUserId } }
  608. sinon.assert.calledWith(this.updateManyStub, filter, removeOperation)
  609. done()
  610. })
  611. })
  612. it('should update the users features', function (done) {
  613. this.SubscriptionUpdater.removeUserFromGroup(
  614. this.subscription._id,
  615. this.otherUserId,
  616. () => {
  617. this.FeaturesUpdater.refreshFeatures
  618. .calledWith(this.otherUserId)
  619. .should.equal(true)
  620. done()
  621. }
  622. )
  623. })
  624. })
  625. describe('deleteSubscription', function () {
  626. beforeEach(function (done) {
  627. this.subscription = {
  628. _id: ObjectId().toString(),
  629. mock: 'subscription',
  630. admin_id: ObjectId(),
  631. member_ids: [ObjectId(), ObjectId(), ObjectId()],
  632. }
  633. this.SubscriptionLocator.getSubscription = sinon
  634. .stub()
  635. .yields(null, this.subscription)
  636. this.FeaturesUpdater.refreshFeatures = sinon.stub().yields()
  637. this.SubscriptionUpdater.deleteSubscription(this.subscription, {}, done)
  638. })
  639. it('should remove the subscription', function () {
  640. this.SubscriptionModel.deleteOne
  641. .calledWith({ _id: this.subscription._id })
  642. .should.equal(true)
  643. })
  644. it('should downgrade the admin_id', function () {
  645. this.FeaturesUpdater.refreshFeatures
  646. .calledWith(this.subscription.admin_id)
  647. .should.equal(true)
  648. })
  649. it('should downgrade all of the members', function () {
  650. for (const userId of this.subscription.member_ids) {
  651. this.FeaturesUpdater.refreshFeatures
  652. .calledWith(userId)
  653. .should.equal(true)
  654. }
  655. })
  656. })
  657. })