LimitationsManagerTests.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. const SandboxedModule = require('sandboxed-module')
  2. const assert = require('assert')
  3. const sinon = require('sinon')
  4. const modulePath = require('path').join(
  5. __dirname,
  6. '../../../../app/src/Features/Subscription/LimitationsManager'
  7. )
  8. describe('LimitationsManager', function () {
  9. beforeEach(function () {
  10. this.project = { _id: (this.projectId = 'project-id') }
  11. this.user = { _id: (this.userId = 'user-id'), features: {} }
  12. this.ProjectGetter = {
  13. getProject: (projectId, fields, callback) => {
  14. if (projectId === this.projectId) {
  15. callback(null, this.project)
  16. } else {
  17. callback(null, null)
  18. }
  19. },
  20. }
  21. this.UserGetter = {
  22. getUser: (userId, filter, callback) => {
  23. if (userId === this.userId) {
  24. callback(null, this.user)
  25. } else {
  26. callback(null, null)
  27. }
  28. },
  29. }
  30. this.SubscriptionLocator = {
  31. getUsersSubscription: sinon.stub(),
  32. getSubscription: sinon.stub(),
  33. }
  34. this.LimitationsManager = SandboxedModule.require(modulePath, {
  35. requires: {
  36. '../Project/ProjectGetter': this.ProjectGetter,
  37. '../User/UserGetter': this.UserGetter,
  38. './SubscriptionLocator': this.SubscriptionLocator,
  39. '@overleaf/settings': (this.Settings = {}),
  40. '../Collaborators/CollaboratorsGetter': (this.CollaboratorsGetter = {}),
  41. '../Collaborators/CollaboratorsInviteHandler':
  42. (this.CollaboratorsInviteHandler = {}),
  43. './V1SubscriptionManager': (this.V1SubscriptionManager = {}),
  44. },
  45. })
  46. })
  47. describe('allowedNumberOfCollaboratorsInProject', function () {
  48. describe('when the project is owned by a user without a subscription', function () {
  49. beforeEach(function () {
  50. this.Settings.defaultFeatures = { collaborators: 23 }
  51. this.project.owner_ref = this.userId
  52. delete this.user.features
  53. this.callback = sinon.stub()
  54. this.LimitationsManager.allowedNumberOfCollaboratorsInProject(
  55. this.projectId,
  56. this.callback
  57. )
  58. })
  59. it('should return the default number', function () {
  60. this.callback
  61. .calledWith(null, this.Settings.defaultFeatures.collaborators)
  62. .should.equal(true)
  63. })
  64. })
  65. describe('when the project is owned by a user with a subscription', function () {
  66. beforeEach(function () {
  67. this.project.owner_ref = this.userId
  68. this.user.features = { collaborators: 21 }
  69. this.callback = sinon.stub()
  70. this.LimitationsManager.allowedNumberOfCollaboratorsInProject(
  71. this.projectId,
  72. this.callback
  73. )
  74. })
  75. it('should return the number of collaborators the user is allowed', function () {
  76. this.callback
  77. .calledWith(null, this.user.features.collaborators)
  78. .should.equal(true)
  79. })
  80. })
  81. })
  82. describe('allowedNumberOfCollaboratorsForUser', function () {
  83. describe('when the user has no features', function () {
  84. beforeEach(function () {
  85. this.Settings.defaultFeatures = { collaborators: 23 }
  86. delete this.user.features
  87. this.callback = sinon.stub()
  88. this.LimitationsManager.allowedNumberOfCollaboratorsForUser(
  89. this.userId,
  90. this.callback
  91. )
  92. })
  93. it('should return the default number', function () {
  94. this.callback
  95. .calledWith(null, this.Settings.defaultFeatures.collaborators)
  96. .should.equal(true)
  97. })
  98. })
  99. describe('when the user has features', function () {
  100. beforeEach(function () {
  101. this.user.features = { collaborators: 21 }
  102. this.callback = sinon.stub()
  103. this.LimitationsManager.allowedNumberOfCollaboratorsForUser(
  104. this.userId,
  105. this.callback
  106. )
  107. })
  108. it('should return the number of collaborators the user is allowed', function () {
  109. this.callback
  110. .calledWith(null, this.user.features.collaborators)
  111. .should.equal(true)
  112. })
  113. })
  114. })
  115. describe('canAddXCollaborators', function () {
  116. describe('when the project has fewer collaborators than allowed', function () {
  117. beforeEach(function () {
  118. this.current_number = 1
  119. this.allowed_number = 2
  120. this.invite_count = 0
  121. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  122. projectId,
  123. callback
  124. ) => callback(null, this.current_number)
  125. this.CollaboratorsInviteHandler.getInviteCount = (
  126. projectId,
  127. callback
  128. ) => callback(null, this.invite_count)
  129. sinon
  130. .stub(
  131. this.LimitationsManager,
  132. 'allowedNumberOfCollaboratorsInProject'
  133. )
  134. .callsFake((projectId, callback) => {
  135. callback(null, this.allowed_number)
  136. })
  137. this.callback = sinon.stub()
  138. this.LimitationsManager.canAddXCollaborators(
  139. this.projectId,
  140. 1,
  141. this.callback
  142. )
  143. })
  144. it('should return true', function () {
  145. this.callback.calledWith(null, true).should.equal(true)
  146. })
  147. })
  148. describe('when the project has fewer collaborators and invites than allowed', function () {
  149. beforeEach(function () {
  150. this.current_number = 1
  151. this.allowed_number = 4
  152. this.invite_count = 1
  153. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  154. projectId,
  155. callback
  156. ) => callback(null, this.current_number)
  157. this.CollaboratorsInviteHandler.getInviteCount = (
  158. projectId,
  159. callback
  160. ) => callback(null, this.invite_count)
  161. sinon
  162. .stub(
  163. this.LimitationsManager,
  164. 'allowedNumberOfCollaboratorsInProject'
  165. )
  166. .callsFake((projectId, callback) => {
  167. callback(null, this.allowed_number)
  168. })
  169. this.callback = sinon.stub()
  170. this.LimitationsManager.canAddXCollaborators(
  171. this.projectId,
  172. 1,
  173. this.callback
  174. )
  175. })
  176. it('should return true', function () {
  177. this.callback.calledWith(null, true).should.equal(true)
  178. })
  179. })
  180. describe('when the project has fewer collaborators than allowed but I want to add more than allowed', function () {
  181. beforeEach(function () {
  182. this.current_number = 1
  183. this.allowed_number = 2
  184. this.invite_count = 0
  185. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  186. projectId,
  187. callback
  188. ) => callback(null, this.current_number)
  189. this.CollaboratorsInviteHandler.getInviteCount = (
  190. projectId,
  191. callback
  192. ) => callback(null, this.invite_count)
  193. sinon
  194. .stub(
  195. this.LimitationsManager,
  196. 'allowedNumberOfCollaboratorsInProject'
  197. )
  198. .callsFake((projectId, callback) => {
  199. callback(null, this.allowed_number)
  200. })
  201. this.callback = sinon.stub()
  202. this.LimitationsManager.canAddXCollaborators(
  203. this.projectId,
  204. 2,
  205. this.callback
  206. )
  207. })
  208. it('should return false', function () {
  209. this.callback.calledWith(null, false).should.equal(true)
  210. })
  211. })
  212. describe('when the project has more collaborators than allowed', function () {
  213. beforeEach(function () {
  214. this.current_number = 3
  215. this.allowed_number = 2
  216. this.invite_count = 0
  217. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  218. projectId,
  219. callback
  220. ) => callback(null, this.current_number)
  221. this.CollaboratorsInviteHandler.getInviteCount = (
  222. projectId,
  223. callback
  224. ) => callback(null, this.invite_count)
  225. sinon
  226. .stub(
  227. this.LimitationsManager,
  228. 'allowedNumberOfCollaboratorsInProject'
  229. )
  230. .callsFake((projectId, callback) => {
  231. callback(null, this.allowed_number)
  232. })
  233. this.callback = sinon.stub()
  234. this.LimitationsManager.canAddXCollaborators(
  235. this.projectId,
  236. 1,
  237. this.callback
  238. )
  239. })
  240. it('should return false', function () {
  241. this.callback.calledWith(null, false).should.equal(true)
  242. })
  243. })
  244. describe('when the project has infinite collaborators', function () {
  245. beforeEach(function () {
  246. this.current_number = 100
  247. this.allowed_number = -1
  248. this.invite_count = 0
  249. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  250. projectId,
  251. callback
  252. ) => callback(null, this.current_number)
  253. this.CollaboratorsInviteHandler.getInviteCount = (
  254. projectId,
  255. callback
  256. ) => callback(null, this.invite_count)
  257. sinon
  258. .stub(
  259. this.LimitationsManager,
  260. 'allowedNumberOfCollaboratorsInProject'
  261. )
  262. .callsFake((projectId, callback) => {
  263. callback(null, this.allowed_number)
  264. })
  265. this.callback = sinon.stub()
  266. this.LimitationsManager.canAddXCollaborators(
  267. this.projectId,
  268. 1,
  269. this.callback
  270. )
  271. })
  272. it('should return true', function () {
  273. this.callback.calledWith(null, true).should.equal(true)
  274. })
  275. })
  276. describe('when the project has more invites than allowed', function () {
  277. beforeEach(function () {
  278. this.current_number = 0
  279. this.allowed_number = 2
  280. this.invite_count = 2
  281. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  282. projectId,
  283. callback
  284. ) => callback(null, this.current_number)
  285. this.CollaboratorsInviteHandler.getInviteCount = (
  286. projectId,
  287. callback
  288. ) => callback(null, this.invite_count)
  289. sinon
  290. .stub(
  291. this.LimitationsManager,
  292. 'allowedNumberOfCollaboratorsInProject'
  293. )
  294. .callsFake((projectId, callback) => {
  295. callback(null, this.allowed_number)
  296. })
  297. this.callback = sinon.stub()
  298. this.LimitationsManager.canAddXCollaborators(
  299. this.projectId,
  300. 1,
  301. this.callback
  302. )
  303. })
  304. it('should return false', function () {
  305. this.callback.calledWith(null, false).should.equal(true)
  306. })
  307. })
  308. describe('when the project has more invites and collaborators than allowed', function () {
  309. beforeEach(function () {
  310. this.current_number = 1
  311. this.allowed_number = 2
  312. this.invite_count = 1
  313. this.CollaboratorsGetter.getInvitedCollaboratorCount = (
  314. projectId,
  315. callback
  316. ) => callback(null, this.current_number)
  317. this.CollaboratorsInviteHandler.getInviteCount = (
  318. projectId,
  319. callback
  320. ) => callback(null, this.invite_count)
  321. sinon
  322. .stub(
  323. this.LimitationsManager,
  324. 'allowedNumberOfCollaboratorsInProject'
  325. )
  326. .callsFake((projectId, callback) => {
  327. callback(null, this.allowed_number)
  328. })
  329. this.callback = sinon.stub()
  330. this.LimitationsManager.canAddXCollaborators(
  331. this.projectId,
  332. 1,
  333. this.callback
  334. )
  335. })
  336. it('should return false', function () {
  337. this.callback.calledWith(null, false).should.equal(true)
  338. })
  339. })
  340. })
  341. describe('userHasV2Subscription', function () {
  342. beforeEach(function () {
  343. this.SubscriptionLocator.getUsersSubscription = sinon.stub()
  344. })
  345. it('should return true if the recurly token is set', function (done) {
  346. this.SubscriptionLocator.getUsersSubscription.callsArgWith(1, null, {
  347. recurlySubscription_id: '1234',
  348. })
  349. this.LimitationsManager.userHasV2Subscription(
  350. this.user,
  351. (err, hasSubscription) => {
  352. assert.equal(err, null)
  353. hasSubscription.should.equal(true)
  354. done()
  355. }
  356. )
  357. })
  358. it('should return false if the recurly token is not set', function (done) {
  359. this.SubscriptionLocator.getUsersSubscription.callsArgWith(1, null, {})
  360. this.subscription = {}
  361. this.LimitationsManager.userHasV2Subscription(
  362. this.user,
  363. (err, hasSubscription) => {
  364. assert.equal(err, null)
  365. hasSubscription.should.equal(false)
  366. done()
  367. }
  368. )
  369. })
  370. it('should return false if the subscription is undefined', function (done) {
  371. this.SubscriptionLocator.getUsersSubscription.callsArgWith(1)
  372. this.LimitationsManager.userHasV2Subscription(
  373. this.user,
  374. (err, hasSubscription) => {
  375. assert.equal(err, null)
  376. hasSubscription.should.equal(false)
  377. done()
  378. }
  379. )
  380. })
  381. it('should return the subscription', function (done) {
  382. const stubbedSubscription = { freeTrial: {}, token: '' }
  383. this.SubscriptionLocator.getUsersSubscription.callsArgWith(
  384. 1,
  385. null,
  386. stubbedSubscription
  387. )
  388. this.LimitationsManager.userHasV2Subscription(
  389. this.user,
  390. (err, hasSubOrIsGroupMember, subscription) => {
  391. assert.equal(err, null)
  392. subscription.should.deep.equal(stubbedSubscription)
  393. done()
  394. }
  395. )
  396. })
  397. describe('when user has a custom account', function () {
  398. beforeEach(function () {
  399. this.fakeSubscription = { customAccount: true }
  400. this.SubscriptionLocator.getUsersSubscription.callsArgWith(
  401. 1,
  402. null,
  403. this.fakeSubscription
  404. )
  405. })
  406. it('should return true', function (done) {
  407. this.LimitationsManager.userHasV2Subscription(
  408. this.user,
  409. (err, hasSubscription, subscription) => {
  410. assert.equal(err, null)
  411. hasSubscription.should.equal(true)
  412. done()
  413. }
  414. )
  415. })
  416. it('should return the subscription', function (done) {
  417. this.LimitationsManager.userHasV2Subscription(
  418. this.user,
  419. (err, hasSubscription, subscription) => {
  420. assert.equal(err, null)
  421. subscription.should.deep.equal(this.fakeSubscription)
  422. done()
  423. }
  424. )
  425. })
  426. })
  427. })
  428. describe('userIsMemberOfGroupSubscription', function () {
  429. beforeEach(function () {
  430. this.SubscriptionLocator.getMemberSubscriptions = sinon.stub()
  431. })
  432. it('should return false if there are no groups subcriptions', function (done) {
  433. this.SubscriptionLocator.getMemberSubscriptions.callsArgWith(1, null, [])
  434. this.LimitationsManager.userIsMemberOfGroupSubscription(
  435. this.user,
  436. (err, isMember) => {
  437. assert.equal(err, null)
  438. isMember.should.equal(false)
  439. done()
  440. }
  441. )
  442. })
  443. it('should return true if there are no groups subcriptions', function (done) {
  444. let subscriptions
  445. this.SubscriptionLocator.getMemberSubscriptions.callsArgWith(
  446. 1,
  447. null,
  448. (subscriptions = ['mock-subscription'])
  449. )
  450. this.LimitationsManager.userIsMemberOfGroupSubscription(
  451. this.user,
  452. (err, isMember, retSubscriptions) => {
  453. assert.equal(err, null)
  454. isMember.should.equal(true)
  455. retSubscriptions.should.equal(subscriptions)
  456. done()
  457. }
  458. )
  459. })
  460. })
  461. describe('hasPaidSubscription', function () {
  462. beforeEach(function () {
  463. this.LimitationsManager.userIsMemberOfGroupSubscription = sinon
  464. .stub()
  465. .yields(null, false)
  466. this.LimitationsManager.userHasV2Subscription = sinon
  467. .stub()
  468. .yields(null, false)
  469. this.LimitationsManager.userHasV1Subscription = sinon
  470. .stub()
  471. .yields(null, false)
  472. })
  473. it('should return true if userIsMemberOfGroupSubscription', function (done) {
  474. this.LimitationsManager.userIsMemberOfGroupSubscription = sinon
  475. .stub()
  476. .yields(null, true)
  477. this.LimitationsManager.hasPaidSubscription(
  478. this.user,
  479. (err, hasSubOrIsGroupMember) => {
  480. assert.equal(err, null)
  481. hasSubOrIsGroupMember.should.equal(true)
  482. done()
  483. }
  484. )
  485. })
  486. it('should return true if userHasV2Subscription', function (done) {
  487. this.LimitationsManager.userHasV2Subscription = sinon
  488. .stub()
  489. .yields(null, true)
  490. this.LimitationsManager.hasPaidSubscription(
  491. this.user,
  492. (err, hasSubOrIsGroupMember) => {
  493. assert.equal(err, null)
  494. hasSubOrIsGroupMember.should.equal(true)
  495. done()
  496. }
  497. )
  498. })
  499. it('should return true if userHasV1Subscription', function (done) {
  500. this.LimitationsManager.userHasV1Subscription = sinon
  501. .stub()
  502. .yields(null, true)
  503. this.LimitationsManager.hasPaidSubscription(
  504. this.user,
  505. (err, hasSubOrIsGroupMember) => {
  506. assert.equal(err, null)
  507. hasSubOrIsGroupMember.should.equal(true)
  508. done()
  509. }
  510. )
  511. })
  512. it('should return false if none are true', function (done) {
  513. this.LimitationsManager.hasPaidSubscription(
  514. this.user,
  515. (err, hasSubOrIsGroupMember) => {
  516. assert.equal(err, null)
  517. hasSubOrIsGroupMember.should.equal(false)
  518. done()
  519. }
  520. )
  521. })
  522. it('should have userHasSubscriptionOrIsGroupMember alias', function (done) {
  523. this.LimitationsManager.userHasSubscriptionOrIsGroupMember(
  524. this.user,
  525. (err, hasSubOrIsGroupMember) => {
  526. assert.equal(err, null)
  527. hasSubOrIsGroupMember.should.equal(false)
  528. done()
  529. }
  530. )
  531. })
  532. })
  533. describe('userHasV1OrV2Subscription', function () {
  534. beforeEach(function () {
  535. this.LimitationsManager.userHasV2Subscription = sinon
  536. .stub()
  537. .yields(null, false)
  538. this.LimitationsManager.userHasV1Subscription = sinon
  539. .stub()
  540. .yields(null, false)
  541. })
  542. it('should return true if userHasV2Subscription', function (done) {
  543. this.LimitationsManager.userHasV2Subscription = sinon
  544. .stub()
  545. .yields(null, true)
  546. this.LimitationsManager.userHasV1OrV2Subscription(
  547. this.user,
  548. (err, hasSub) => {
  549. assert.equal(err, null)
  550. hasSub.should.equal(true)
  551. done()
  552. }
  553. )
  554. })
  555. it('should return true if userHasV1Subscription', function (done) {
  556. this.LimitationsManager.userHasV1Subscription = sinon
  557. .stub()
  558. .yields(null, true)
  559. this.LimitationsManager.userHasV1OrV2Subscription(
  560. this.user,
  561. (err, hasSub) => {
  562. assert.equal(err, null)
  563. hasSub.should.equal(true)
  564. done()
  565. }
  566. )
  567. })
  568. it('should return false if none are true', function (done) {
  569. this.LimitationsManager.userHasV1OrV2Subscription(
  570. this.user,
  571. (err, hasSub) => {
  572. assert.equal(err, null)
  573. hasSub.should.equal(false)
  574. done()
  575. }
  576. )
  577. })
  578. })
  579. describe('hasGroupMembersLimitReached', function () {
  580. beforeEach(function () {
  581. this.subscriptionId = '12312'
  582. this.subscription = {
  583. membersLimit: 3,
  584. member_ids: ['', ''],
  585. teamInvites: [
  586. { email: 'bob@example.com', sentAt: new Date(), token: 'hey' },
  587. ],
  588. }
  589. })
  590. it('should return true if the limit is hit (including members and invites)', function (done) {
  591. this.SubscriptionLocator.getSubscription.callsArgWith(
  592. 1,
  593. null,
  594. this.subscription
  595. )
  596. this.LimitationsManager.hasGroupMembersLimitReached(
  597. this.subscriptionId,
  598. (err, limitReached) => {
  599. assert.equal(err, null)
  600. limitReached.should.equal(true)
  601. done()
  602. }
  603. )
  604. })
  605. it('should return false if the limit is not hit (including members and invites)', function (done) {
  606. this.subscription.membersLimit = 4
  607. this.SubscriptionLocator.getSubscription.callsArgWith(
  608. 1,
  609. null,
  610. this.subscription
  611. )
  612. this.LimitationsManager.hasGroupMembersLimitReached(
  613. this.subscriptionId,
  614. (err, limitReached) => {
  615. assert.equal(err, null)
  616. limitReached.should.equal(false)
  617. done()
  618. }
  619. )
  620. })
  621. it('should return true if the limit has been exceded (including members and invites)', function (done) {
  622. this.subscription.membersLimit = 2
  623. this.SubscriptionLocator.getSubscription.callsArgWith(
  624. 1,
  625. null,
  626. this.subscription
  627. )
  628. this.LimitationsManager.hasGroupMembersLimitReached(
  629. this.subscriptionId,
  630. (err, limitReached) => {
  631. assert.equal(err, null)
  632. limitReached.should.equal(true)
  633. done()
  634. }
  635. )
  636. })
  637. })
  638. describe('userHasV1Subscription', function () {
  639. it('should return true if v1 returns has_subscription = true', function (done) {
  640. this.V1SubscriptionManager.getSubscriptionsFromV1 = sinon
  641. .stub()
  642. .yields(null, { has_subscription: true })
  643. this.LimitationsManager.userHasV1Subscription(
  644. this.user,
  645. (error, result) => {
  646. assert.equal(error, null)
  647. this.V1SubscriptionManager.getSubscriptionsFromV1
  648. .calledWith(this.userId)
  649. .should.equal(true)
  650. result.should.equal(true)
  651. done()
  652. }
  653. )
  654. })
  655. it('should return false if v1 returns has_subscription = false', function (done) {
  656. this.V1SubscriptionManager.getSubscriptionsFromV1 = sinon
  657. .stub()
  658. .yields(null, { has_subscription: false })
  659. this.LimitationsManager.userHasV1Subscription(
  660. this.user,
  661. (error, result) => {
  662. assert.equal(error, null)
  663. this.V1SubscriptionManager.getSubscriptionsFromV1
  664. .calledWith(this.userId)
  665. .should.equal(true)
  666. result.should.equal(false)
  667. done()
  668. }
  669. )
  670. })
  671. it('should return false if v1 returns nothing', function (done) {
  672. this.V1SubscriptionManager.getSubscriptionsFromV1 = sinon
  673. .stub()
  674. .yields(null, null)
  675. this.LimitationsManager.userHasV1Subscription(
  676. this.user,
  677. (error, result) => {
  678. assert.equal(error, null)
  679. this.V1SubscriptionManager.getSubscriptionsFromV1
  680. .calledWith(this.userId)
  681. .should.equal(true)
  682. result.should.equal(false)
  683. done()
  684. }
  685. )
  686. })
  687. })
  688. })