Преглед изворни кода

Merge pull request #28811 from overleaf/dp-promisify-learned-words-manager

Promisify LearnedWordsManager and LearnedWordsManagerTests

GitOrigin-RevId: f4e30eca0292409bcefe82b17facd1129fdc85ae
David пре 1 година
родитељ
комит
abd3e6e325

+ 72 - 68
services/web/app/src/Features/Spelling/LearnedWordsManager.js

@@ -1,94 +1,98 @@
+// @ts-check
+
 const { db } = require('../../infrastructure/mongodb')
 const { db } = require('../../infrastructure/mongodb')
-const { promisify } = require('util')
-const OError = require('@overleaf/o-error')
+const { callbackify } = require('util')
 const Settings = require('@overleaf/settings')
 const Settings = require('@overleaf/settings')
 const { InvalidError } = require('../Errors/Errors')
 const { InvalidError } = require('../Errors/Errors')
 
 
 const LearnedWordsManager = {
 const LearnedWordsManager = {
-  learnWord(userToken, word, callback) {
-    LearnedWordsManager.getLearnedWordsSize(userToken, (error, wordsSize) => {
-      if (error != null) {
-        return callback(OError.tag(error))
-      }
-      const wordSize = Buffer.from(word).length
-      if (wordsSize + wordSize > Settings.maxDictionarySize) {
-        return callback(new InvalidError('Max dictionary size reached'))
-      }
-      db.spellingPreferences.updateOne(
-        {
-          token: userToken,
-        },
-        {
-          $addToSet: { learnedWords: word },
-        },
-        {
-          upsert: true,
-        },
-        callback
-      )
-    })
-  },
+  /**
+   * @param {string} userToken
+   * @param {string} word
+   */
+  async learnWord(userToken, word) {
+    const wordsSize = await LearnedWordsManager.getLearnedWordsSize(userToken)
+
+    const wordSize = Buffer.from(word).length
+    if (wordsSize + wordSize > Settings.maxDictionarySize) {
+      throw new InvalidError('Max dictionary size reached')
+    }
 
 
-  unlearnWord(userToken, word, callback) {
-    return db.spellingPreferences.updateOne(
+    return await db.spellingPreferences.updateOne(
       {
       {
         token: userToken,
         token: userToken,
       },
       },
       {
       {
-        $pull: { learnedWords: word },
+        $addToSet: { learnedWords: word },
       },
       },
-      callback
+      {
+        upsert: true,
+      }
     )
     )
   },
   },
 
 
-  getLearnedWords(userToken, callback) {
-    db.spellingPreferences.findOne(
-      { token: userToken },
-      function (error, preferences) {
-        if (error != null) {
-          return callback(OError.tag(error))
-        }
-        let words =
-          (preferences != null ? preferences.learnedWords : undefined) || []
-        if (words) {
-          // remove duplicates
-          words = words.filter(
-            (value, index, self) => self.indexOf(value) === index
-          )
-        }
-        callback(null, words)
+  /**
+   * @param {string} userToken
+   * @param {string} word
+   */
+  async unlearnWord(userToken, word) {
+    return await db.spellingPreferences.updateOne(
+      {
+        token: userToken,
+      },
+      {
+        $pull: { learnedWords: word },
       }
       }
     )
     )
   },
   },
 
 
-  getLearnedWordsSize(userToken, callback) {
-    db.spellingPreferences.findOne(
-      { token: userToken },
-      function (error, preferences) {
-        if (error != null) {
-          return callback(OError.tag(error))
-        }
-        const words = (preferences && preferences.learnedWords) || []
-        const wordsSize = Buffer.from(JSON.stringify(words)).length
-        callback(null, wordsSize)
-      }
-    )
+  /**
+   * @param {string} userToken
+   */
+  async getLearnedWords(userToken) {
+    const preferences = await db.spellingPreferences.findOne({
+      token: userToken,
+    })
+
+    let words =
+      (preferences != null ? preferences.learnedWords : undefined) || []
+
+    if (words) {
+      // remove duplicates
+      words = words.filter(
+        (value, index, self) => self.indexOf(value) === index
+      )
+    }
+    return words
   },
   },
 
 
-  deleteUsersLearnedWords(userToken, callback) {
-    db.spellingPreferences.deleteOne({ token: userToken }, callback)
+  /**
+   * @param {string} userToken
+   */
+  async getLearnedWordsSize(userToken) {
+    const preferences = await db.spellingPreferences.findOne({
+      token: userToken,
+    })
+
+    const words = (preferences && preferences.learnedWords) || []
+    return Buffer.from(JSON.stringify(words)).length
+  },
+
+  /**
+   * @param {string} userToken
+   */
+  async deleteUsersLearnedWords(userToken) {
+    return await db.spellingPreferences.deleteOne({ token: userToken })
   },
   },
 }
 }
 
 
-const promises = {
-  learnWord: promisify(LearnedWordsManager.learnWord),
-  unlearnWord: promisify(LearnedWordsManager.unlearnWord),
-  getLearnedWords: promisify(LearnedWordsManager.getLearnedWords),
-  deleteUsersLearnedWords: promisify(
+module.exports = {
+  learnWord: callbackify(LearnedWordsManager.learnWord),
+  unlearnWord: callbackify(LearnedWordsManager.unlearnWord),
+  getLearnedWords: callbackify(LearnedWordsManager.getLearnedWords),
+  getLearnedWordsSize: callbackify(LearnedWordsManager.getLearnedWordsSize),
+  deleteUsersLearnedWords: callbackify(
     LearnedWordsManager.deleteUsersLearnedWords
     LearnedWordsManager.deleteUsersLearnedWords
   ),
   ),
+  promises: LearnedWordsManager,
 }
 }
-
-LearnedWordsManager.promises = promises
-
-module.exports = LearnedWordsManager

+ 31 - 42
services/web/test/unit/src/Spelling/LearnedWordsManagerTests.js

@@ -10,11 +10,10 @@ const { InvalidError } = require('../../../../app/src/Features/Errors/Errors')
 describe('LearnedWordsManager', function () {
 describe('LearnedWordsManager', function () {
   beforeEach(function () {
   beforeEach(function () {
     this.token = 'a6b3cd919ge'
     this.token = 'a6b3cd919ge'
-    this.callback = sinon.stub()
     this.db = {
     this.db = {
       spellingPreferences: {
       spellingPreferences: {
-        updateOne: sinon.stub().yields(),
-        findOne: sinon.stub().yields(null, ['pear']),
+        updateOne: sinon.stub().resolves(),
+        findOne: sinon.stub().resolves(['pear']),
       },
       },
     }
     }
     this.LearnedWordsManager = SandboxedModule.require(modulePath, {
     this.LearnedWordsManager = SandboxedModule.require(modulePath, {
@@ -32,9 +31,9 @@ describe('LearnedWordsManager', function () {
 
 
   describe('learnWord', function () {
   describe('learnWord', function () {
     describe('under size limit', function () {
     describe('under size limit', function () {
-      beforeEach(function () {
+      beforeEach(async function () {
         this.word = 'instanton'
         this.word = 'instanton'
-        this.LearnedWordsManager.learnWord(this.token, this.word, this.callback)
+        await this.LearnedWordsManager.promises.learnWord(this.token, this.word)
       })
       })
 
 
       it('should insert the word in the word list in the database', function () {
       it('should insert the word in the word list in the database', function () {
@@ -52,34 +51,26 @@ describe('LearnedWordsManager', function () {
           )
           )
         ).to.equal(true)
         ).to.equal(true)
       })
       })
-
-      it('should call the callback without error', function () {
-        sinon.assert.called(this.callback)
-        expect(this.callback.lastCall.args.length).to.equal(0)
-      })
     })
     })
 
 
     describe('over size limit', function () {
     describe('over size limit', function () {
       beforeEach(function () {
       beforeEach(function () {
         this.word = 'superlongwordthatwillgobeyondthelimit'
         this.word = 'superlongwordthatwillgobeyondthelimit'
-        this.LearnedWordsManager.learnWord(this.token, this.word, this.callback)
       })
       })
 
 
-      it('should not insert the word in the word list in the database', function () {
+      it('should throw an error and not insert the word in the word list in the database', async function () {
+        await expect(
+          this.LearnedWordsManager.promises.learnWord(this.token, this.word)
+        ).to.be.rejectedWith(InvalidError)
         expect(this.db.spellingPreferences.updateOne.notCalled).to.equal(true)
         expect(this.db.spellingPreferences.updateOne.notCalled).to.equal(true)
       })
       })
-
-      it('should call the callback with error', function () {
-        sinon.assert.called(this.callback)
-        expect(this.callback.lastCall.args[0]).to.be.instanceof(InvalidError)
-      })
     })
     })
   })
   })
 
 
   describe('unlearnWord', function () {
   describe('unlearnWord', function () {
-    beforeEach(function () {
+    beforeEach(async function () {
       this.word = 'instanton'
       this.word = 'instanton'
-      this.LearnedWordsManager.unlearnWord(this.token, this.word, this.callback)
+      await this.LearnedWordsManager.promises.unlearnWord(this.token, this.word)
     })
     })
 
 
     it('should remove the word from the word list in the database', function () {
     it('should remove the word from the word list in the database', function () {
@@ -94,22 +85,19 @@ describe('LearnedWordsManager', function () {
         )
         )
       ).to.equal(true)
       ).to.equal(true)
     })
     })
-
-    it('should call the callback', function () {
-      expect(this.callback.called).to.equal(true)
-    })
   })
   })
 
 
   describe('getLearnedWords', function () {
   describe('getLearnedWords', function () {
-    beforeEach(function () {
+    beforeEach(async function () {
       this.wordList = ['apples', 'bananas', 'pears']
       this.wordList = ['apples', 'bananas', 'pears']
       this.wordListWithDuplicates = this.wordList.slice()
       this.wordListWithDuplicates = this.wordList.slice()
       this.wordListWithDuplicates.push('bananas')
       this.wordListWithDuplicates.push('bananas')
-      this.db.spellingPreferences.findOne = (conditions, callback) => {
-        callback(null, { learnedWords: this.wordListWithDuplicates })
+      this.db.spellingPreferences.findOne = conditions => {
+        return Promise.resolve({ learnedWords: this.wordListWithDuplicates })
       }
       }
       sinon.spy(this.db.spellingPreferences, 'findOne')
       sinon.spy(this.db.spellingPreferences, 'findOne')
-      this.LearnedWordsManager.getLearnedWords(this.token, this.callback)
+      this.learnedWords =
+        await this.LearnedWordsManager.promises.getLearnedWords(this.token)
     })
     })
 
 
     it('should get the word list for the given user', function () {
     it('should get the word list for the given user', function () {
@@ -118,35 +106,36 @@ describe('LearnedWordsManager', function () {
       ).to.equal(true)
       ).to.equal(true)
     })
     })
 
 
-    it('should return the word list in the callback without duplicates', function () {
-      expect(this.callback.calledWith(null, this.wordList)).to.equal(true)
+    it('should return the word list without duplicates', function () {
+      expect(this.learnedWords).to.deep.equal(this.wordList)
     })
     })
   })
   })
 
 
   describe('getLearnedWordsSize', function () {
   describe('getLearnedWordsSize', function () {
-    it('should return the word list size in the callback', function () {
-      this.db.spellingPreferences.findOne = (conditions, callback) => {
-        callback(null, {
+    it('should return the word list size in the callback', async function () {
+      this.db.spellingPreferences.findOne = conditions => {
+        return Promise.resolve({
           learnedWords: ['apples', 'bananas', 'pears', 'bananas'],
           learnedWords: ['apples', 'bananas', 'pears', 'bananas'],
         })
         })
       }
       }
-      this.LearnedWordsManager.getLearnedWordsSize(this.token, this.callback)
-      sinon.assert.calledWith(this.callback, null, 38)
+      const learnedWordsSize =
+        await this.LearnedWordsManager.promises.getLearnedWordsSize(this.token)
+      expect(learnedWordsSize).to.equal(38)
     })
     })
   })
   })
 
 
   describe('deleteUsersLearnedWords', function () {
   describe('deleteUsersLearnedWords', function () {
     beforeEach(function () {
     beforeEach(function () {
-      this.db.spellingPreferences.deleteOne = sinon.stub().callsArgWith(1)
+      this.db.spellingPreferences.deleteOne = sinon.stub().resolves()
     })
     })
 
 
-    it('should get the word list for the given user', function (done) {
-      this.LearnedWordsManager.deleteUsersLearnedWords(this.token, () => {
-        this.db.spellingPreferences.deleteOne
-          .calledWith({ token: this.token })
-          .should.equal(true)
-        done()
-      })
+    it('should get the word list for the given user', async function () {
+      await this.LearnedWordsManager.promises.deleteUsersLearnedWords(
+        this.token
+      )
+      expect(
+        this.db.spellingPreferences.deleteOne.calledWith({ token: this.token })
+      ).to.equal(true)
     })
     })
   })
   })
 })
 })