@internetarchive/bookreader 5.0.0-6-14 → 5.0.0-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (271) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +72 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +241 -140
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +24 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1519 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/close-circle-dark.svg +1 -0
  13. package/BookReader/icons/magnify-minus.svg +1 -1
  14. package/BookReader/icons/magnify-plus.svg +1 -1
  15. package/BookReader/icons/pause.svg +1 -1
  16. package/BookReader/icons/playback-speed.svg +1 -1
  17. package/BookReader/icons/read-aloud.svg +1 -1
  18. package/BookReader/icons/voice.svg +1 -0
  19. package/BookReader/images/BRicons.svg +2 -2
  20. package/BookReader/images/books_graphic.svg +1 -1
  21. package/BookReader/images/icon_book.svg +1 -1
  22. package/BookReader/images/icon_gear.svg +1 -1
  23. package/BookReader/images/icon_info.svg +1 -1
  24. package/BookReader/images/icon_playback-rate.svg +1 -1
  25. package/BookReader/images/icon_search_button.svg +1 -1
  26. package/BookReader/images/icon_share.svg +1 -1
  27. package/BookReader/images/icon_speaker.svg +1 -1
  28. package/BookReader/images/icon_speaker_open.svg +1 -1
  29. package/BookReader/images/marker_chap-off.svg +1 -1
  30. package/BookReader/images/marker_chap-on.svg +1 -1
  31. package/BookReader/images/marker_srch-on.svg +1 -1
  32. package/BookReader/jquery-3.js +2 -0
  33. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  34. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  35. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  36. package/BookReader/plugins/plugin.autoplay.js +1 -1
  37. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  38. package/BookReader/plugins/plugin.chapters.js +1 -1
  39. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  40. package/BookReader/plugins/plugin.iframe.js +1 -1
  41. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  42. package/BookReader/plugins/plugin.mobile_nav.js +1 -1
  43. package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
  44. package/BookReader/plugins/plugin.resume.js +1 -1
  45. package/BookReader/plugins/plugin.resume.js.map +1 -1
  46. package/BookReader/plugins/plugin.search.js +1 -1
  47. package/BookReader/plugins/plugin.search.js.map +1 -1
  48. package/BookReader/plugins/plugin.text_selection.js +1 -1
  49. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  50. package/BookReader/plugins/plugin.tts.js +1 -1
  51. package/BookReader/plugins/plugin.tts.js.map +1 -1
  52. package/BookReader/plugins/plugin.url.js +1 -1
  53. package/BookReader/plugins/plugin.url.js.map +1 -1
  54. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  55. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  56. package/BookReader/webcomponents-bundle.js +3 -0
  57. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  58. package/BookReader/webcomponents-bundle.js.map +1 -0
  59. package/BookReaderDemo/BookReaderDemo.css +14 -1
  60. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  61. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  62. package/BookReaderDemo/IADemoBr.js +147 -0
  63. package/BookReaderDemo/demo-advanced.html +2 -2
  64. package/BookReaderDemo/demo-autoplay.html +2 -1
  65. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  66. package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
  67. package/BookReaderDemo/demo-fullscreen.html +2 -1
  68. package/BookReaderDemo/demo-iiif.html +2 -1
  69. package/BookReaderDemo/demo-internetarchive.html +84 -17
  70. package/BookReaderDemo/demo-multiple.html +2 -1
  71. package/BookReaderDemo/demo-preview-pages.html +2 -1
  72. package/BookReaderDemo/demo-simple.html +2 -1
  73. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
  74. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  75. package/BookReaderDemo/immersion-1up.html +2 -1
  76. package/BookReaderDemo/immersion-mode.html +2 -1
  77. package/BookReaderDemo/toggle_controls.html +2 -1
  78. package/BookReaderDemo/view_mode.html +2 -1
  79. package/BookReaderDemo/viewmode-cycle.html +2 -3
  80. package/CHANGELOG.md +244 -0
  81. package/README.md +14 -1
  82. package/babel.config.js +19 -0
  83. package/codecov.yml +6 -0
  84. package/index.html +3 -0
  85. package/jsconfig.json +19 -0
  86. package/netlify.toml +5 -0
  87. package/package.json +70 -59
  88. package/renovate.json +52 -0
  89. package/scripts/preversion.js +4 -1
  90. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  91. package/src/BookNavigator/assets/button-base.js +9 -2
  92. package/src/BookNavigator/assets/ia-logo.js +17 -0
  93. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  94. package/src/BookNavigator/assets/icon_close.js +1 -1
  95. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  96. package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
  97. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  98. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  99. package/src/BookNavigator/book-navigator.js +585 -0
  100. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  101. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  102. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  103. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  104. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  105. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  106. package/src/BookNavigator/delete-modal-actions.js +1 -1
  107. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  108. package/src/BookNavigator/downloads/downloads.js +41 -25
  109. package/src/BookNavigator/search/search-provider.js +80 -28
  110. package/src/BookNavigator/search/search-results.js +34 -25
  111. package/src/BookNavigator/sharing.js +27 -0
  112. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  113. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  114. package/src/BookNavigator/volumes/volumes-provider.js +111 -0
  115. package/src/BookNavigator/volumes/volumes.js +188 -0
  116. package/src/BookReader/BookModel.js +59 -30
  117. package/src/BookReader/DebugConsole.js +3 -3
  118. package/src/BookReader/DragScrollable.js +233 -0
  119. package/src/BookReader/Mode1Up.js +56 -351
  120. package/src/BookReader/Mode1UpLit.js +391 -0
  121. package/src/BookReader/Mode2Up.js +73 -1318
  122. package/src/BookReader/Mode2UpLit.js +781 -0
  123. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  124. package/src/BookReader/ModeSmoothZoom.js +211 -0
  125. package/src/BookReader/ModeThumb.js +17 -11
  126. package/src/BookReader/Navbar/Navbar.js +10 -36
  127. package/src/BookReader/PageContainer.js +69 -6
  128. package/src/BookReader/ReduceSet.js +1 -1
  129. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  130. package/src/BookReader/events.js +2 -0
  131. package/src/BookReader/options.js +24 -2
  132. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  133. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  134. package/src/BookReader/utils.js +108 -13
  135. package/src/BookReader.js +481 -828
  136. package/src/assets/icons/close-circle-dark.svg +1 -0
  137. package/src/assets/icons/magnify-minus.svg +3 -7
  138. package/src/assets/icons/magnify-plus.svg +3 -7
  139. package/src/assets/icons/voice.svg +1 -0
  140. package/src/css/_BRBookmarks.scss +1 -1
  141. package/src/css/_BRComponent.scss +1 -1
  142. package/src/css/_BRmain.scss +33 -0
  143. package/src/css/_BRnav.scss +4 -26
  144. package/src/css/_BRpages.scss +147 -40
  145. package/src/css/_BRsearch.scss +25 -11
  146. package/src/css/_TextSelection.scss +16 -17
  147. package/src/css/_colorbox.scss +2 -2
  148. package/src/css/_controls.scss +17 -5
  149. package/src/css/_icons.scss +7 -1
  150. package/src/ia-bookreader/ia-bookreader.js +224 -0
  151. package/src/plugins/plugin.archive_analytics.js +3 -3
  152. package/src/plugins/plugin.autoplay.js +4 -9
  153. package/src/plugins/plugin.chapters.js +28 -35
  154. package/src/plugins/plugin.mobile_nav.js +11 -10
  155. package/src/plugins/plugin.resume.js +3 -3
  156. package/src/plugins/plugin.text_selection.js +32 -41
  157. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  158. package/src/plugins/search/plugin.search.js +179 -103
  159. package/src/plugins/search/view.js +59 -44
  160. package/src/plugins/tts/AbstractTTSEngine.js +46 -37
  161. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  162. package/src/plugins/tts/PageChunk.js +15 -21
  163. package/src/plugins/tts/PageChunkIterator.js +8 -12
  164. package/src/plugins/tts/WebTTSEngine.js +87 -71
  165. package/src/plugins/tts/plugin.tts.js +94 -125
  166. package/src/plugins/tts/utils.js +0 -25
  167. package/src/plugins/url/UrlPlugin.js +193 -0
  168. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  169. package/src/util/docCookies.js +21 -2
  170. package/tests/e2e/README.md +37 -0
  171. package/tests/e2e/autoplay.test.js +2 -2
  172. package/tests/e2e/base.test.js +7 -7
  173. package/tests/e2e/helpers/base.js +28 -23
  174. package/tests/e2e/helpers/debug.js +1 -1
  175. package/tests/e2e/helpers/desktopSearch.js +14 -13
  176. package/tests/e2e/helpers/mobileSearch.js +3 -3
  177. package/tests/e2e/helpers/params.js +17 -0
  178. package/tests/e2e/helpers/rightToLeft.js +4 -10
  179. package/tests/e2e/models/Navigation.js +13 -4
  180. package/tests/e2e/rightToLeft.test.js +4 -5
  181. package/tests/e2e/viewmode.test.js +40 -33
  182. package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
  183. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  184. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  185. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  186. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  187. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  188. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  189. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  190. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +104 -60
  191. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  192. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  193. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  194. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  195. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +59 -14
  196. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  197. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
  198. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  199. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  200. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  201. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  202. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  203. package/tests/jest/BookReader/ModeSmoothZoom.test.js +175 -0
  204. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  205. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  206. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  207. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  208. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  209. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  210. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  211. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  212. package/tests/jest/BookReader/utils.test.js +217 -0
  213. package/tests/jest/BookReader.keyboard.test.js +190 -0
  214. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  215. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  216. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  217. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  218. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
  219. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  220. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
  221. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  222. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
  223. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  224. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +57 -47
  225. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
  226. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
  227. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  228. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  229. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  230. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  231. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  232. package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
  233. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  234. package/tests/jest/setup.js +3 -0
  235. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  236. package/tests/jest/util/docCookies.test.js +24 -0
  237. package/tests/{util → jest/util}/strings.test.js +1 -1
  238. package/tests/{utils.js → jest/utils.js} +38 -0
  239. package/webpack.config.js +11 -5
  240. package/.babelrc +0 -12
  241. package/.dependabot/config.yml +0 -6
  242. package/.testcaferc.json +0 -5
  243. package/BookReader/bookreader-component-bundle.js +0 -1450
  244. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  245. package/BookReader/bookreader-component-bundle.js.map +0 -1
  246. package/BookReader/jquery-1.10.1.js +0 -2
  247. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  248. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  249. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  250. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  251. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  252. package/karma.conf.js +0 -23
  253. package/src/BookNavigator/BookModel.js +0 -14
  254. package/src/BookNavigator/BookNavigator.js +0 -438
  255. package/src/BookNavigator/assets/book-loader.js +0 -27
  256. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  257. package/src/BookNavigator/search/a-search-result.js +0 -55
  258. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  259. package/src/ItemNavigator/ItemNavigator.js +0 -372
  260. package/src/ItemNavigator/providers/sharing.js +0 -29
  261. package/src/dragscrollable-br.js +0 -261
  262. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  263. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  264. package/tests/BookReader/Mode1Up.test.js +0 -164
  265. package/tests/BookReader/Mode2Up.test.js +0 -247
  266. package/tests/BookReader/utils.test.js +0 -109
  267. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  268. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  269. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  270. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  271. package/tests/util/docCookies.test.js +0 -15
@@ -1,7 +1,7 @@
1
1
  import sinon from 'sinon';
2
2
 
3
- import '../../src/BookReader.js';
4
- import { BookreaderWithTextSelection, TextSelectionPlugin, Cache } from '../../src/plugins/plugin.text_selection.js';
3
+ import '@/src/BookReader.js';
4
+ import { BookreaderWithTextSelection, TextSelectionPlugin, Cache } from '@/src/plugins/plugin.text_selection.js';
5
5
 
6
6
 
7
7
  /** @type {BookReader} */
@@ -19,30 +19,32 @@ const FAKE_XML_5COORDS = `<OBJECT data="file://localhost//tmp/derive/goodytwosho
19
19
  const FAKE_XML_EMPTY = '';
20
20
 
21
21
  describe("Generic tests", () => {
22
- let br;
23
- beforeEach(() => {
24
- document.body.innerHTML = '<div id="BookReader">';
25
- br = new BookreaderWithTextSelection({
26
- data: [
27
- [
28
- { width: 800, height: 1200,
29
- uri: '//archive.org/download/BookReader/img/page001.jpg' },
30
- ],
31
- [
32
- { width: 800, height: 1200,
33
- uri: '//archive.org/download/BookReader/img/page002.jpg' },
34
- { width: 800, height: 1200,
35
- uri: '//archive.org/download/BookReader/img/page003.jpg' },
36
- ],
37
- [
38
- { width: 800, height: 1200,
39
- uri: '//archive.org/download/BookReader/img/page004.jpg' },
40
- { width: 800, height: 1200,
41
- uri: '//archive.org/download/BookReader/img/page005.jpg' },
42
- ]
22
+ document.body.innerHTML = '<div id="BookReader">';
23
+ const br = new BookreaderWithTextSelection({
24
+ data: [
25
+ [
26
+ { width: 800, height: 1200,
27
+ uri: '//archive.org/download/BookReader/img/page001.jpg' },
43
28
  ],
44
- });
45
- br.init();
29
+ [
30
+ { width: 800, height: 1200,
31
+ uri: '//archive.org/download/BookReader/img/page002.jpg' },
32
+ { width: 800, height: 1200,
33
+ uri: '//archive.org/download/BookReader/img/page003.jpg' },
34
+ ],
35
+ [
36
+ { width: 800, height: 1200,
37
+ uri: '//archive.org/download/BookReader/img/page004.jpg' },
38
+ { width: 800, height: 1200,
39
+ uri: '//archive.org/download/BookReader/img/page005.jpg' },
40
+ ]
41
+ ],
42
+ });
43
+ br.init();
44
+
45
+ afterEach(() => {
46
+ sinon.restore();
47
+ $('.textSelectionSVG').remove();
46
48
  });
47
49
 
48
50
  test("_createPageContainer overridden function still creates a BRpagecontainer element", () => {
@@ -72,8 +74,8 @@ describe("Generic tests", () => {
72
74
  const $container = br.refs.$brContainer;
73
75
  sinon.stub(br.textSelectionPlugin, "getPageText")
74
76
  .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
75
- const pageIndex = br.data.length - 1
76
- await br.textSelectionPlugin.createTextLayer(pageIndex, $container);
77
+ const pageIndex = br.data.length - 1;
78
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: pageIndex, width: 100, height: 100 }});
77
79
  expect($container.find(".textSelectionSVG").length).toBe(1);
78
80
  expect($container.find(".BRparagElement").length).toBe(1);
79
81
  });
@@ -83,17 +85,7 @@ describe("Generic tests", () => {
83
85
  const xml = FAKE_XML_1WORD.replace(/<WORD.*<\/WORD>/, FAKE_XML_1WORD.match(/<WORD.*<\/WORD>/)[0].repeat(3000));
84
86
  sinon.stub(br.textSelectionPlugin, "getPageText")
85
87
  .returns($(new DOMParser().parseFromString(xml, "text/xml")));
86
- await br.textSelectionPlugin.createTextLayer(0, $container);
87
- expect($container.find(".textSelectionSVG").length).toBe(0);
88
- expect($container.find(".BRparagElement").length).toBe(0);
89
- expect($container.find(".BRwordElement").length).toBe(0);
90
- });
91
-
92
- // GRRRR!!! This is a useful test :( But can't get it working for some reason,
93
- // and the error output is super cryptic.
94
- test.skip("createTextLayer will not create text layer if index is more than total number of book pages", async () => {
95
- const $container = br.refs.$brContainer;
96
- await br.textSelectionPlugin.createTextLayer(150, $container);
88
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: 0, width: 100, height: 100 }});
97
89
  expect($container.find(".textSelectionSVG").length).toBe(0);
98
90
  expect($container.find(".BRparagElement").length).toBe(0);
99
91
  expect($container.find(".BRwordElement").length).toBe(0);
@@ -103,7 +95,7 @@ describe("Generic tests", () => {
103
95
  const $container = br.refs.$brContainer;
104
96
  sinon.stub(br.textSelectionPlugin, "getPageText")
105
97
  .returns($(new DOMParser().parseFromString(FAKE_XML_1WORD, "text/xml")));
106
- await br.textSelectionPlugin.createTextLayer(1, $container);
98
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: 1, width: 100, height: 100 }});
107
99
  expect($container.find(".textSelectionSVG").length).toBe(1);
108
100
  expect($container.find(".BRparagElement").length).toBe(1);
109
101
  expect($container.find(".BRwordElement").length).toBe(1);
@@ -114,7 +106,7 @@ describe("Generic tests", () => {
114
106
  const $container = br.refs.$brContainer;
115
107
  sinon.stub(br.textSelectionPlugin, "getPageText")
116
108
  .returns($(new DOMParser().parseFromString(FAKE_XML_MULT_WORDS, "text/xml")));
117
- await br.textSelectionPlugin.createTextLayer(2, $container);
109
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: 2, width: 100, height: 100 }});
118
110
  expect($container.find(".textSelectionSVG").length).toBe(1);
119
111
  expect($container.find(".BRparagElement").length).toBe(1);
120
112
  expect($container.find(".BRwordElement").length).toBe(5);
@@ -125,7 +117,7 @@ describe("Generic tests", () => {
125
117
  const $container = br.refs.$brContainer;
126
118
  sinon.stub(br.textSelectionPlugin, "getPageText")
127
119
  .returns($(new DOMParser().parseFromString(FAKE_XML_5COORDS, "text/xml")));
128
- await br.textSelectionPlugin.createTextLayer(3, $container);
120
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: 3, width: 100, height: 100 }});
129
121
  expect($container.find(".textSelectionSVG").length).toBe(1);
130
122
  expect($container.find(".BRparagElement").length).toBe(1);
131
123
  expect($container.find(".BRwordElement").length).toBe(1);
@@ -135,7 +127,7 @@ describe("Generic tests", () => {
135
127
  const $container = br.refs.$brContainer;
136
128
  sinon.stub(br.textSelectionPlugin, "getPageText")
137
129
  .returns($(new DOMParser().parseFromString(FAKE_XML_EMPTY, "text/xml")));
138
- await br.textSelectionPlugin.createTextLayer(4, $container);
130
+ await br.textSelectionPlugin.createTextLayer({ $container, page: { index: 4, width: 100, height: 100 }});
139
131
  expect($container.find(".textSelectionSVG").length).toBe(1);
140
132
  expect($container.find(".BRparagElement").length).toBe(0);
141
133
  expect($container.find(".BRwordElement").length).toBe(0);
@@ -146,28 +138,28 @@ describe("Generic tests", () => {
146
138
  const $container = br.refs.$brContainer;
147
139
  br.textSelectionPlugin.stopPageFlip($container);
148
140
  const currIndex = br.currentIndex();
149
- $container.find("BRwordElement").mousedown();
141
+ $container.find("BRwordElement").trigger("mousedown");
150
142
  // Waits for long press
151
143
  setTimeout(() => {
152
- $container.find("BRwordElement").mousedown();
144
+ $container.find("BRwordElement").trigger("mousedown");
153
145
  // Waits for flipping animation
154
146
  setTimeout(() => {
155
147
  expect(br.currentIndex()).toBe(currIndex);
156
148
  }, 2000);
157
149
  }, LONG_PRESS_DURATION);
158
150
  });
159
- })
151
+ });
160
152
 
161
153
  describe("textSelectionPlugin constructor", () => {
162
154
  test("textSelectionPlugin constructor with firefox browser", () => {
163
- const tsp = new TextSelectionPlugin({}, {}, true)
155
+ const tsp = new TextSelectionPlugin({}, {}, true);
164
156
  expect(tsp.djvuPagesPromise).toBe(null);
165
157
  expect(tsp.svgParagraphElement).toBe("g");
166
158
  expect(tsp.svgWordElement).toBe("text");
167
159
  });
168
160
 
169
161
  test("textSelectionPlugin constructor not on firefox browser", () => {
170
- const tsp = new TextSelectionPlugin({}, {}, false)
162
+ const tsp = new TextSelectionPlugin({}, {}, false);
171
163
  expect(tsp.djvuPagesPromise).toBe(null);
172
164
  expect(tsp.svgParagraphElement).toBe("text");
173
165
  expect(tsp.svgWordElement).toBe("tspan");
@@ -1,6 +1,6 @@
1
1
 
2
- import BookReader from '../../src/BookReader.js';
3
- import * as util from '../../src/plugins/plugin.vendor-fullscreen.js';
2
+ import BookReader from '@/src/BookReader.js';
3
+ import * as util from '@/src/plugins/plugin.vendor-fullscreen.js';
4
4
 
5
5
  let br;
6
6
  beforeEach(() => {
@@ -1,9 +1,9 @@
1
+ import BookReader from '@/src/BookReader.js';
2
+ import '@/src/plugins/plugin.mobile_nav.js';
3
+ import { marshallSearchResults } from '@/src/plugins/search/plugin.search.js';
4
+ import { deepCopy } from '../../utils.js';
1
5
 
2
- import BookReader from '../../../src/BookReader.js';
3
- import '../../../src/plugins/plugin.mobile_nav.js';
4
- import '../../../src/plugins/search/plugin.search.js';
5
-
6
- jest.mock('../../../src/plugins/search/view.js');
6
+ jest.mock('@/src/plugins/search/view.js');
7
7
 
8
8
  let br;
9
9
  const namespace = 'BookReader:';
@@ -14,31 +14,33 @@ const triggeredEvents = () => {
14
14
  });
15
15
  };
16
16
 
17
+ const DUMMY_RESULTS = {
18
+ ia: "adventuresofoli00dick",
19
+ q: "child",
20
+ indexed: true,
21
+ page_count: 644,
22
+ body_length: 666,
23
+ leaf0_missing: false,
24
+ matches: [{
25
+ text: 'For a long; time after it was ushered into this world of sorrow and trouble, by the parish surgeon, it remained a matter of considerable doubt wliether the {{{child}}} Avould survi^ e to bear any name at all; in which case it is somewhat more than probable that these memoirs would never have appeared; or, if they had, that being comprised within a couple of pages, they would have possessed the inestimable meiit of being the most concise and faithful specimen of biography, extant in the literature of any age or country.',
26
+ par: [{
27
+ boxes: [{r: 1221, b: 2121, t: 2075, page: 37, l: 1107}],
28
+ b: 2535,
29
+ t: 1942,
30
+ page_width: 1790,
31
+ r: 1598,
32
+ l: 50,
33
+ page_height: 2940,
34
+ page: 37
35
+ }]
36
+ }]
37
+ };
38
+
17
39
  beforeEach(() => {
18
40
  $.ajax = jest.fn().mockImplementation(() => {
19
41
  // return from:
20
42
  // `https://ia800304.us.archive.org/fulltext/inside.php?item_id=adventuresofoli00dick&doc=adventuresofoli00dick&path=/30/items/adventuresofoli00dick&q=child&callback=<serialized jQ CB>`
21
- return Promise.resolve({
22
- ia: "adventuresofoli00dick",
23
- q: "child",
24
- indexed: true,
25
- page_count: 644,
26
- body_length: 666,
27
- leaf0_missing: false,
28
- matches: [{
29
- text: 'For a long; time after it was ushered into this world of sorrow and trouble, by the parish surgeon, it remained a matter of considerable doubt wliether the {{{child}}} Avould survi^ e to bear any name at all; in which case it is somewhat more than probable that these memoirs would never have appeared; or, if they had, that being comprised within a couple of pages, they would have possessed the inestimable meiit of being the most concise and faithful specimen of biography, extant in the literature of any age or country.',
30
- par: [{
31
- boxes: [{r: 1221, b: 2121, t: 2075, page: 37, l: 1107}],
32
- b: 2535,
33
- t: 1942,
34
- page_width: 1790,
35
- r: 1598,
36
- l: 50,
37
- page_height: 2940,
38
- page: 37
39
- }]
40
- }]
41
- });
43
+ return Promise.resolve(deepCopy(DUMMY_RESULTS));
42
44
  });
43
45
 
44
46
  $.fn.trigger = jest.fn();
@@ -46,6 +48,7 @@ beforeEach(() => {
46
48
  br = new BookReader();
47
49
  br.initToolbar = jest.fn();
48
50
  br.showProgressPopup = jest.fn();
51
+ br.searchXHR = jest.fn();
49
52
  });
50
53
 
51
54
  afterEach(() => {
@@ -101,7 +104,7 @@ describe('Plugin: Search', () => {
101
104
  expect(br.search.mock.calls[0][1])
102
105
  .toHaveProperty('goToFirstResult', true);
103
106
  expect(br.search.mock.calls[0][1])
104
- .toHaveProperty('suppressFragmentChange', true);
107
+ .toHaveProperty('suppressFragmentChange', false);
105
108
  });
106
109
 
107
110
  test('calling `search` fires ajax call`', () => {
@@ -122,28 +125,24 @@ describe('Plugin: Search', () => {
122
125
  expect(br.options.goToFirstResult).toBeTruthy();
123
126
  });
124
127
 
125
- test('SearchCallback event fires when AJAX search returns results', () => {
128
+ test('SearchCallback event fires when AJAX search returns results', async () => {
126
129
  br.init();
127
- const dfd = br.search('foo');
128
- return dfd.then(() => {
129
- expect(triggeredEvents()).toContain(`${namespace}SearchCallback`);
130
- });
130
+ await br.search('foo');
131
+ expect(triggeredEvents()).toContain(`${namespace}SearchCallback`);
131
132
  });
132
133
 
133
- test('SearchCallbackError event fires when AJAX search returns error', () => {
134
+ test('SearchCallbackError event fires when AJAX search returns error', async () => {
134
135
  $.ajax = jest.fn().mockImplementation(() => {
135
136
  return Promise.resolve({
136
137
  error: true,
137
138
  });
138
139
  });
139
140
  br.init();
140
- const dfd = br.search('foo');
141
- return dfd.then(() => {
142
- expect(triggeredEvents()).toContain(`${namespace}SearchCallbackError`);
143
- });
141
+ await br.search('foo');
142
+ expect(triggeredEvents()).toContain(`${namespace}SearchCallbackError`);
144
143
  });
145
144
 
146
- test('SearchCallbackNotIndexed event fires when AJAX search returns false indexed value', () => {
145
+ test('SearchCallbackNotIndexed event fires when AJAX search returns false indexed value', async () => {
147
146
  $.ajax = jest.fn().mockImplementation(() => {
148
147
  return Promise.resolve({
149
148
  matches: [],
@@ -151,22 +150,33 @@ describe('Plugin: Search', () => {
151
150
  });
152
151
  });
153
152
  br.init();
154
- const dfd = br.search('foo');
155
- return dfd.then(() => {
156
- expect(triggeredEvents()).toContain(`${namespace}SearchCallbackBookNotIndexed`);
157
- });
153
+ await br.search('foo');
154
+ expect(triggeredEvents()).toContain(`${namespace}SearchCallbackBookNotIndexed`);
158
155
  });
159
156
 
160
- test('SearchCallbackEmpty event fires when AJAX search returns no matches', () => {
157
+ test('SearchCallbackEmpty event fires when AJAX search returns no matches', async () => {
161
158
  $.ajax = jest.fn().mockImplementation(() => {
162
159
  return Promise.resolve({
163
160
  matches: [],
164
161
  });
165
162
  });
166
163
  br.init();
167
- const dfd = br.search('foo');
168
- return dfd.then(() => {
169
- expect(triggeredEvents()).toContain(`${namespace}SearchCallbackEmpty`);
170
- });
164
+ await br.search('foo');
165
+ expect(triggeredEvents()).toContain(`${namespace}SearchCallbackEmpty`);
166
+ });
167
+ });
168
+
169
+ describe('marshallSearchResults', () => {
170
+ test('Adds match index', () => {
171
+ const results = deepCopy(DUMMY_RESULTS);
172
+ marshallSearchResults(results, x => x.toString());
173
+ expect(results.matches[0]).toHaveProperty('matchIndex', 0);
174
+ expect(results.matches[0].par[0].boxes[0]).toHaveProperty('matchIndex', 0);
175
+ });
176
+
177
+ test('Adds display page number', () => {
178
+ const results = deepCopy(DUMMY_RESULTS);
179
+ marshallSearchResults(results, x => `n${x}`);
180
+ expect(results.matches[0]).toHaveProperty('displayPageNumber', 'n37');
171
181
  });
172
182
  });
@@ -1,8 +1,8 @@
1
1
 
2
- import BookReader from '../../../src/BookReader.js';
3
- import '../../../src/plugins/plugin.mobile_nav.js';
4
- import '../../../src/plugins/search/plugin.search.js';
5
- import '../../../src/plugins/search/view.js';
2
+ import BookReader from '@/src/BookReader.js';
3
+ import '@/src/plugins/plugin.mobile_nav.js';
4
+ import '@/src/plugins/search/plugin.search.js';
5
+ import '@/src/plugins/search/view.js';
6
6
 
7
7
  let br;
8
8
  const namespace = 'BookReader:';
@@ -27,6 +27,27 @@ const results = {
27
27
  }]
28
28
  }]
29
29
  };
30
+ const resultWithScript = {
31
+ ia: "adventuresofoli00dick",
32
+ q: "child",
33
+ indexed: true,
34
+ page_count: 644,
35
+ body_length: 666,
36
+ leaf0_missing: false,
37
+ matches: [{
38
+ text: 'foo bar <script>alert(1);</script> {{{keyword}}} baz',
39
+ par: [{
40
+ boxes: [{r: 1221, b: 2121, t: 2075, page: 37, l: 1107}],
41
+ b: 2535,
42
+ t: 1942,
43
+ page_width: 1790,
44
+ r: 1598,
45
+ l: 50,
46
+ page_height: 2940,
47
+ page: 37
48
+ }]
49
+ }]
50
+ };
30
51
  beforeEach(() => {
31
52
  $.ajax = jest.fn().mockImplementation(() => {
32
53
  // return from:
@@ -63,14 +84,14 @@ describe('View: Plugin: Search', () => {
63
84
 
64
85
  expect(br.searchView.dom.searchNavigation).toBeUndefined();
65
86
 
66
- br.searchView.handleSearchCallback(event, { results, options})
87
+ br.searchView.handleSearchCallback(event, { results, options});
67
88
  expect(br.searchView.dom.searchNavigation).toBeDefined();
68
89
  });
69
90
  test('has controls', () => {
70
91
  br.init();
71
92
  const event = new CustomEvent(`${namespace}SearchCallback`);
72
93
  const options = { goToFirstResult: false };
73
- br.searchView.handleSearchCallback(event, { results, options})
94
+ br.searchView.handleSearchCallback(event, { results, options});
74
95
 
75
96
  const searchResultsNav = document.querySelector('.BRsearch-navigation');
76
97
  expect(searchResultsNav).toBeDefined();
@@ -81,6 +102,14 @@ describe('View: Plugin: Search', () => {
81
102
  expect(searchResultsNav.querySelector('.prev')).toBeDefined();
82
103
  expect(searchResultsNav.querySelector('.next')).toBeDefined();
83
104
  });
105
+ test('disallows xss from search results', () => {
106
+ br.init();
107
+ const event = new CustomEvent(`${namespace}SearchCallback`);
108
+ const options = { goToFirstResult: false };
109
+ br.searchView.handleSearchCallback(event, { results: resultWithScript, options });
110
+
111
+ expect(br.searchView.dom.searchNavigation.parent().html()).not.toContain('<script>alert(1);</script>');
112
+ });
84
113
 
85
114
  describe('Click events handlers', () => {
86
115
  it('triggers custom event when toggling side menu', () => {
@@ -1,12 +1,12 @@
1
1
  import sinon from 'sinon';
2
2
  import { afterEventLoop } from '../../utils.js';
3
- import AbstractTTSEngine from '../../../src/plugins/tts/AbstractTTSEngine.js';
4
- import PageChunkIterator from '../../../src/plugins/tts/PageChunkIterator.js';
5
- /** @typedef {import('../../../src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
3
+ import AbstractTTSEngine from '@/src/plugins/tts/AbstractTTSEngine.js';
4
+ import PageChunkIterator from '@/src/plugins/tts/PageChunkIterator.js';
5
+ /** @typedef {import('@/src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
6
6
 
7
7
  // Skipping because it's flaky. Fix in #672
8
8
  describe.skip('AbstractTTSEngine', () => {
9
- test('stops playing once done', () => {
9
+ test('stops playing once done', async () => {
10
10
  class DummyEngine extends AbstractTTSEngine {
11
11
  getVoices() { return []; }
12
12
  }
@@ -15,12 +15,12 @@ describe.skip('AbstractTTSEngine', () => {
15
15
  const stopStub = sinon.stub(d, 'stop');
16
16
  expect(stopStub.callCount).toBe(0);
17
17
  d.step();
18
- return afterEventLoop()
19
- .then(() => expect(stopStub.callCount).toBe(1));
18
+ await afterEventLoop();
19
+ expect(stopStub.callCount).toBe(1);
20
20
  });
21
21
  });
22
22
 
23
- for (const dummyVoice of [dummyVoice, dummyVoiceUnderscores]) {
23
+ for (const dummyVoice of [dummyVoiceHyphens, dummyVoiceUnderscores]) {
24
24
  describe(`getBestBookVoice with BCP47 ${dummyVoice == dummyVoiceUnderscores ? '+' : '-'} underscores`, () => {
25
25
  const { getBestBookVoice } = AbstractTTSEngine;
26
26
 
@@ -130,7 +130,7 @@ export const DUMMY_TTS_ENGINE_OPTS = {
130
130
  * @param {SpeechSynthesisVoice}
131
131
  * @return {SpeechSynthesisVoice}
132
132
  **/
133
- function dummyVoice(overrides) {
133
+ function dummyVoiceHyphens(overrides) {
134
134
  return Object.assign({
135
135
  default: false,
136
136
  lang: "en-US",
@@ -147,7 +147,7 @@ function dummyVoice(overrides) {
147
147
  * @return {SpeechSynthesisVoice}
148
148
  **/
149
149
  function dummyVoiceUnderscores(overrides) {
150
- const voice = dummyVoice(overrides);
150
+ const voice = dummyVoiceHyphens(overrides);
151
151
  voice.lang = voice.lang.replace('-', '_');
152
152
  return voice;
153
153
  }
@@ -1,10 +1,10 @@
1
- import FestivalTTSEngine from '../../../src/plugins/tts/FestivalTTSEngine.js';
1
+ import FestivalTTSEngine from '@/src/plugins/tts/FestivalTTSEngine.js';
2
2
  import sinon from 'sinon';
3
3
  import { afterEventLoop } from '../../utils.js';
4
4
  import { DUMMY_TTS_ENGINE_OPTS } from './AbstractTTSEngine.test.js';
5
- import PageChunk from '../../../src/plugins/tts/PageChunk.js';
6
- import PageChunkIterator from '../../../src/plugins/tts/PageChunkIterator.js';
7
- /** @typedef {import('../../../src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
5
+ import PageChunk from '@/src/plugins/tts/PageChunk.js';
6
+ import PageChunkIterator from '@/src/plugins/tts/PageChunkIterator.js';
7
+ /** @typedef {import('@/src/plugins/tts/AbstractTTSEngine.js').TTSEngineOptions} TTSEngineOptions */
8
8
 
9
9
  describe('iOSCaptureUserIntentHack', () => {
10
10
  test('synchronously calls createSound/play to capture user intent', () => {
@@ -1,4 +1,4 @@
1
- import PageChunk from '../../../src/plugins/tts/PageChunk.js';
1
+ import PageChunk from '@/src/plugins/tts/PageChunk.js';
2
2
 
3
3
  describe('_fixChunkRects', () => {
4
4
  const { _fixChunkRects } = PageChunk;
@@ -1,6 +1,6 @@
1
1
  import sinon from 'sinon';
2
- import PageChunkIterator from "../../../src/plugins/tts/PageChunkIterator";
3
- import PageChunk from '../../../src/plugins/tts/PageChunk';
2
+ import PageChunkIterator from "@/src/plugins/tts/PageChunkIterator";
3
+ import PageChunk from '@/src/plugins/tts/PageChunk';
4
4
 
5
5
  describe('Buffers pages', () => {
6
6
  test('Does not error if no room for reverse buffer', async () => {
@@ -109,7 +109,7 @@ describe('Iterates pages', () => {
109
109
  expect(iterator._cursor.chunk).toBe(0);
110
110
 
111
111
  for (let i = 2; i >= 0; i--) {
112
- await iterator.decrement()
112
+ await iterator.decrement();
113
113
  expect(iterator._cursor.page).toBe(49);
114
114
  expect(iterator._cursor.chunk).toBe(i);
115
115
  }
@@ -1,5 +1,5 @@
1
1
  import sinon from 'sinon';
2
- import { WebTTSSound } from '../../../src/plugins/tts/WebTTSEngine.js';
2
+ import WebTTSEngine, { WebTTSSound } from '@/src/plugins/tts/WebTTSEngine.js';
3
3
  import { afterEventLoop, eventTargetMixin } from '../../utils.js';
4
4
 
5
5
  beforeEach(() => {
@@ -8,6 +8,7 @@ beforeEach(() => {
8
8
  speak: sinon.stub(),
9
9
  pause: sinon.stub(),
10
10
  resume: sinon.stub(),
11
+
11
12
  ...eventTargetMixin(),
12
13
  };
13
14
  window.SpeechSynthesisUtterance = function (text) {
@@ -21,6 +22,51 @@ afterEach(() => {
21
22
  delete window.SpeechSynthesisUtterance;
22
23
  });
23
24
 
25
+ describe('WebTTSEngine', () => {
26
+ test('getVoices should include default voice when no actual default', () => {
27
+ // iOS devices set all the voices to default -_-
28
+ speechSynthesis.getVoices = () => [
29
+ {
30
+ default: true,
31
+ lang: "ar-001",
32
+ localService: true,
33
+ name: "Majed",
34
+ voiceURI: "com.apple.voice.compact.ar-001.Maged",
35
+ },
36
+ {
37
+ default: true,
38
+ lang: "bg-BG",
39
+ localService: true,
40
+ name: "Daria",
41
+ voiceURI: "com.apple.voice.compact.bg-BG.Daria",
42
+ }
43
+ ];
44
+ const voices = WebTTSEngine.prototype.getVoices();
45
+ expect(voices.length).toBe(3);
46
+ expect(voices[0].voiceURI).toBe('bookreader.SystemDefault');
47
+ });
48
+
49
+ test('getVoices should not include default voice when there is a default', () => {
50
+ speechSynthesis.getVoices = () => [
51
+ {
52
+ default: true,
53
+ lang: "ar-001",
54
+ localService: true,
55
+ name: "Majed",
56
+ voiceURI: "com.apple.voice.compact.ar-001.Maged",
57
+ },
58
+ {
59
+ default: false,
60
+ lang: "bg-BG",
61
+ localService: true,
62
+ name: "Daria",
63
+ voiceURI: "com.apple.voice.compact.bg-BG.Daria",
64
+ }
65
+ ];
66
+ const voices = WebTTSEngine.prototype.getVoices();
67
+ expect(voices.length).toBe(2);
68
+ });
69
+ });
24
70
 
25
71
  describe('WebTTSSound', () => {
26
72
  describe('setPlaybackRate', () => {
@@ -1,38 +1,4 @@
1
- import sinon from 'sinon';
2
- import { afterEventLoop, eventTargetMixin } from '../../utils.js';
3
- import * as utils from '../../../src/plugins/tts/utils.js';
4
-
5
- describe('promisifyEvent', () => {
6
- const { promisifyEvent } = utils;
7
-
8
- test('Resolves once event fires', async () => {
9
- const fakeTarget = eventTargetMixin();
10
- const resolveSpy = sinon.spy();
11
- promisifyEvent(fakeTarget, 'pause').then(resolveSpy);
12
-
13
- await afterEventLoop()
14
- expect(resolveSpy.callCount).toBe(0);
15
- fakeTarget.dispatchEvent('pause', {});
16
- await afterEventLoop();
17
- expect(resolveSpy.callCount).toBe(1);
18
- });
19
-
20
- test('Only resolves once', async () => {
21
- const fakeTarget = eventTargetMixin();
22
- const resolveSpy = sinon.spy();
23
- promisifyEvent(fakeTarget, 'pause').then(resolveSpy);
24
-
25
- await afterEventLoop()
26
- expect(resolveSpy.callCount).toBe(0);
27
- fakeTarget.dispatchEvent('pause', {});
28
- fakeTarget.dispatchEvent('pause', {});
29
- fakeTarget.dispatchEvent('pause', {});
30
- fakeTarget.dispatchEvent('pause', {});
31
-
32
- await afterEventLoop();
33
- expect(resolveSpy.callCount).toBe(1);
34
- });
35
- });
1
+ import * as utils from '@/src/plugins/tts/utils.js';
36
2
 
37
3
  describe('approximateWordCount', () => {
38
4
  const { approximateWordCount } = utils;
@@ -66,31 +32,6 @@ describe('approximateWordCount', () => {
66
32
  });
67
33
  });
68
34
 
69
- describe('sleep', () => {
70
- const { sleep } = utils;
71
-
72
- test('Sleep 0 doest not called immediately', async () => {
73
- const spy = sinon.spy();
74
- sleep(0).then(spy);
75
- expect(spy.callCount).toBe(0);
76
- await afterEventLoop();
77
- expect(spy.callCount).toBe(1);
78
- });
79
-
80
- test('Waits the appropriate ms', async () => {
81
- const clock = sinon.useFakeTimers();
82
- const spy = sinon.spy();
83
- sleep(10).then(spy);
84
- expect(spy.callCount).toBe(0);
85
- clock.tick(10);
86
- expect(spy.callCount).toBe(0);
87
- clock.restore();
88
-
89
- await afterEventLoop();
90
- expect(spy.callCount).toBe(1);
91
- });
92
- });
93
-
94
35
  describe('toISO6391', () => {
95
36
  const { toISO6391 } = utils;
96
37