SpellingAPIManagerTests.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /* eslint-disable
  2. handle-callback-err
  3. */
  4. const sinon = require('sinon')
  5. const { expect } = require('chai')
  6. const SandboxedModule = require('sandboxed-module')
  7. const modulePath = require('path').join(
  8. __dirname,
  9. '../../../app/js/SpellingAPIManager'
  10. )
  11. const promiseStub = val => new Promise(resolve => resolve(val))
  12. describe('SpellingAPIManager', function () {
  13. beforeEach(function () {
  14. this.token = 'user-id-123'
  15. this.ASpell = {}
  16. this.learnedWords = ['lerned']
  17. this.LearnedWordsManager = {
  18. getLearnedWords: sinon.stub().callsArgWith(1, null, this.learnedWords),
  19. learnWord: sinon.stub().callsArg(2),
  20. unlearnWord: sinon.stub().callsArg(2),
  21. promises: {
  22. getLearnedWords: sinon.stub().returns(promiseStub(this.learnedWords)),
  23. },
  24. }
  25. this.SpellingAPIManager = SandboxedModule.require(modulePath, {
  26. requires: {
  27. './ASpell': this.ASpell,
  28. '@overleaf/settings': { ignoredMisspellings: ['ShareLaTeX'] },
  29. './LearnedWordsManager': this.LearnedWordsManager,
  30. },
  31. })
  32. })
  33. describe('runRequest', function () {
  34. beforeEach(function () {
  35. this.nonLearnedWords = [
  36. 'some',
  37. 'words',
  38. 'htat',
  39. 'are',
  40. 'speled',
  41. 'rong',
  42. 'lerned',
  43. ]
  44. this.allWords = this.nonLearnedWords.concat(this.learnedWords)
  45. this.misspellings = [
  46. { index: 2, suggestions: ['that'] },
  47. { index: 4, suggestions: ['spelled'] },
  48. { index: 5, suggestions: ['wrong', 'ring'] },
  49. { index: 6, suggestions: ['learned'] },
  50. ]
  51. this.misspellingsWithoutLearnedWords = this.misspellings.slice(0, 3)
  52. this.ASpell.checkWords = (lang, word, callback) => {
  53. callback(null, this.misspellings)
  54. }
  55. this.ASpell.promises = {
  56. checkWords: sinon.stub().returns(promiseStub(this.misspellings)),
  57. }
  58. sinon.spy(this.ASpell, 'checkWords')
  59. })
  60. describe('with sensible JSON', function () {
  61. beforeEach(function (done) {
  62. this.SpellingAPIManager.runRequest(
  63. this.token,
  64. { words: this.allWords },
  65. (error, result) => {
  66. this.result = result
  67. done()
  68. }
  69. )
  70. })
  71. it('should return the words that are spelled incorrectly and not learned', function () {
  72. expect(this.result.misspellings).to.deep.equal(
  73. this.misspellingsWithoutLearnedWords
  74. )
  75. })
  76. })
  77. describe('with a missing words array', function () {
  78. beforeEach(function (done) {
  79. this.SpellingAPIManager.runRequest(this.token, {}, (error, result) => {
  80. this.error = error
  81. this.result = result
  82. done()
  83. })
  84. })
  85. it('should return an error', function () {
  86. expect(this.error).to.exist
  87. expect(this.error).to.be.instanceof(Error)
  88. expect(this.error.message).to.equal('malformed JSON')
  89. })
  90. })
  91. describe('with a missing token', function () {
  92. beforeEach(function (done) {
  93. this.SpellingAPIManager.runRequest(
  94. null,
  95. { words: this.allWords },
  96. (error, result) => {
  97. this.error = error
  98. this.result = result
  99. done()
  100. }
  101. )
  102. })
  103. it('should spell check without using any learned words', function () {
  104. this.LearnedWordsManager.getLearnedWords.called.should.equal(false)
  105. })
  106. })
  107. describe('without a language', function () {
  108. beforeEach(function (done) {
  109. this.SpellingAPIManager.runRequest(
  110. this.token,
  111. { words: this.allWords },
  112. (error, result) => {
  113. this.result = result
  114. done()
  115. }
  116. )
  117. })
  118. it('should use en as the default', function () {
  119. this.ASpell.promises.checkWords.calledWith('en').should.equal(true)
  120. })
  121. })
  122. describe('with a language', function () {
  123. beforeEach(function (done) {
  124. this.language = 'fr'
  125. this.SpellingAPIManager.runRequest(
  126. this.token,
  127. {
  128. words: this.allWords,
  129. language: this.language,
  130. },
  131. (error, result) => {
  132. this.result = result
  133. done()
  134. }
  135. )
  136. })
  137. it('should use the language', function () {
  138. this.ASpell.promises.checkWords
  139. .calledWith(this.language)
  140. .should.equal(true)
  141. })
  142. })
  143. describe('with words from the whitelist', function () {
  144. beforeEach(function (done) {
  145. this.whitelistWord = this.SpellingAPIManager.whitelist[0]
  146. this.words = ['One', 'Two', this.whitelistWord]
  147. this.SpellingAPIManager.runRequest(
  148. this.token,
  149. { words: this.words },
  150. (error, result) => {
  151. this.result = result
  152. done()
  153. }
  154. )
  155. })
  156. it('should ignore the white-listed word', function () {
  157. expect(this.result.misspellings.length).to.equal(
  158. this.misspellings.length - 1
  159. )
  160. })
  161. })
  162. })
  163. describe('learnWord', function () {
  164. describe('without a token', function () {
  165. beforeEach(function (done) {
  166. this.SpellingAPIManager.learnWord(null, { word: 'banana' }, error => {
  167. this.error = error
  168. done()
  169. })
  170. })
  171. it('should return an error', function () {
  172. expect(this.error).to.exist
  173. expect(this.error).to.be.instanceof(Error)
  174. expect(this.error.message).to.equal('no token provided')
  175. })
  176. })
  177. describe('without a word', function () {
  178. beforeEach(function (done) {
  179. this.SpellingAPIManager.learnWord(this.token, {}, error => {
  180. this.error = error
  181. done()
  182. })
  183. })
  184. it('should return an error', function () {
  185. expect(this.error).to.exist
  186. expect(this.error).to.be.instanceof(Error)
  187. expect(this.error.message).to.equal('malformed JSON')
  188. })
  189. })
  190. describe('with a word and a token', function () {
  191. beforeEach(function (done) {
  192. this.word = 'banana'
  193. this.SpellingAPIManager.learnWord(
  194. this.token,
  195. { word: this.word },
  196. error => {
  197. this.error = error
  198. done()
  199. }
  200. )
  201. })
  202. it('should call LearnedWordsManager.learnWord', function () {
  203. this.LearnedWordsManager.learnWord
  204. .calledWith(this.token, this.word)
  205. .should.equal(true)
  206. })
  207. })
  208. })
  209. describe('unlearnWord', function () {
  210. describe('without a token', function () {
  211. beforeEach(function (done) {
  212. this.SpellingAPIManager.unlearnWord(null, { word: 'banana' }, error => {
  213. this.error = error
  214. done()
  215. })
  216. })
  217. it('should return an error', function () {
  218. expect(this.error).to.exist
  219. expect(this.error).to.be.instanceof(Error)
  220. expect(this.error.message).to.equal('no token provided')
  221. })
  222. })
  223. describe('without a word', function () {
  224. beforeEach(function (done) {
  225. this.SpellingAPIManager.unlearnWord(this.token, {}, error => {
  226. this.error = error
  227. done()
  228. })
  229. })
  230. it('should return an error', function () {
  231. expect(this.error).to.exist
  232. expect(this.error).to.be.instanceof(Error)
  233. expect(this.error.message).to.equal('malformed JSON')
  234. })
  235. })
  236. describe('with a word and a token', function () {
  237. beforeEach(function (done) {
  238. this.word = 'banana'
  239. this.SpellingAPIManager.unlearnWord(
  240. this.token,
  241. { word: this.word },
  242. error => {
  243. this.error = error
  244. done()
  245. }
  246. )
  247. })
  248. it('should call LearnedWordsManager.unlearnWord', function () {
  249. this.LearnedWordsManager.unlearnWord
  250. .calledWith(this.token, this.word)
  251. .should.equal(true)
  252. })
  253. })
  254. })
  255. })