@internetarchive/bookreader 5.0.0-8 → 5.0.0-80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +73 -10
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +398 -1133
  6. package/BookReader/BookReader.js +1 -1
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1782 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +7 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -1
  13. package/BookReader/icons/2up.svg +1 -1
  14. package/BookReader/icons/advance.svg +1 -1
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -1
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -1
  19. package/BookReader/icons/fullscreen_exit.svg +1 -1
  20. package/BookReader/icons/hamburger.svg +1 -1
  21. package/BookReader/icons/left-arrow.svg +1 -1
  22. package/BookReader/icons/magnify-minus.svg +1 -1
  23. package/BookReader/icons/magnify-plus.svg +1 -1
  24. package/BookReader/icons/magnify.svg +1 -1
  25. package/BookReader/icons/pause.svg +1 -1
  26. package/BookReader/icons/play.svg +1 -1
  27. package/BookReader/icons/playback-speed.svg +1 -1
  28. package/BookReader/icons/read-aloud.svg +1 -1
  29. package/BookReader/icons/review.svg +1 -1
  30. package/BookReader/icons/thumbnails.svg +1 -1
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -1
  33. package/BookReader/images/BRicons.svg +3 -3
  34. package/BookReader/images/books_graphic.svg +1 -1
  35. package/BookReader/images/icon_book.svg +1 -1
  36. package/BookReader/images/icon_bookmark.svg +1 -1
  37. package/BookReader/images/icon_gear.svg +1 -1
  38. package/BookReader/images/icon_hamburger.svg +1 -1
  39. package/BookReader/images/icon_home.svg +1 -1
  40. package/BookReader/images/icon_info.svg +1 -1
  41. package/BookReader/images/icon_one_page.svg +1 -1
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -1
  45. package/BookReader/images/icon_search_button.svg +1 -1
  46. package/BookReader/images/icon_share.svg +1 -1
  47. package/BookReader/images/icon_skip-ahead.svg +1 -1
  48. package/BookReader/images/icon_skip-back.svg +1 -1
  49. package/BookReader/images/icon_speaker.svg +1 -1
  50. package/BookReader/images/icon_speaker_open.svg +1 -1
  51. package/BookReader/images/icon_thumbnails.svg +1 -1
  52. package/BookReader/images/icon_toc.svg +1 -1
  53. package/BookReader/images/icon_two_pages.svg +1 -1
  54. package/BookReader/images/marker_chap-off.svg +1 -1
  55. package/BookReader/images/marker_chap-on.svg +1 -1
  56. package/BookReader/images/marker_srch-on.svg +1 -1
  57. package/BookReader/jquery-3.js +2 -0
  58. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  59. package/BookReader/plugins/plugin.archive_analytics.js +1 -1
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -1
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +25 -1
  64. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  65. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  66. package/BookReader/plugins/plugin.iframe.js +1 -1
  67. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  68. package/BookReader/plugins/plugin.iiif.js +2 -0
  69. package/BookReader/plugins/plugin.iiif.js.map +1 -0
  70. package/BookReader/plugins/plugin.resume.js +1 -1
  71. package/BookReader/plugins/plugin.resume.js.map +1 -1
  72. package/BookReader/plugins/plugin.search.js +2 -1
  73. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  74. package/BookReader/plugins/plugin.search.js.map +1 -1
  75. package/BookReader/plugins/plugin.text_selection.js +2 -1
  76. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  77. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  78. package/BookReader/plugins/plugin.tts.js +1 -1
  79. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  80. package/BookReader/plugins/plugin.tts.js.map +1 -1
  81. package/BookReader/plugins/plugin.url.js +1 -1
  82. package/BookReader/plugins/plugin.url.js.map +1 -1
  83. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
  84. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  85. package/BookReader/webcomponents-bundle.js +3 -0
  86. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  87. package/BookReader/webcomponents-bundle.js.map +1 -0
  88. package/BookReaderDemo/BookReaderDemo.css +18 -19
  89. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  90. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  91. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  92. package/BookReaderDemo/IADemoBr.js +147 -0
  93. package/BookReaderDemo/demo-advanced.html +2 -2
  94. package/BookReaderDemo/demo-autoplay.html +2 -3
  95. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  96. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  97. package/BookReaderDemo/demo-fullscreen.html +2 -4
  98. package/BookReaderDemo/demo-iiif.html +99 -12
  99. package/BookReaderDemo/demo-internetarchive.html +214 -18
  100. package/BookReaderDemo/demo-multiple.html +2 -1
  101. package/BookReaderDemo/demo-preview-pages.html +2 -1
  102. package/BookReaderDemo/demo-simple.html +2 -1
  103. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  104. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  105. package/BookReaderDemo/immersion-1up.html +2 -2
  106. package/BookReaderDemo/immersion-mode.html +2 -4
  107. package/BookReaderDemo/toggle_controls.html +3 -2
  108. package/BookReaderDemo/view_mode.html +2 -1
  109. package/BookReaderDemo/viewmode-cycle.html +2 -3
  110. package/CHANGELOG.md +536 -33
  111. package/README.md +14 -1
  112. package/babel.config.js +20 -0
  113. package/codecov.yml +6 -0
  114. package/index.html +4 -1
  115. package/jsconfig.json +19 -0
  116. package/netlify.toml +9 -0
  117. package/package.json +70 -60
  118. package/renovate.json +52 -0
  119. package/scripts/preversion.js +0 -1
  120. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  121. package/src/BookNavigator/assets/button-base.js +4 -2
  122. package/src/BookNavigator/assets/ia-logo.js +17 -0
  123. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  124. package/src/BookNavigator/assets/icon_close.js +1 -1
  125. package/src/BookNavigator/book-navigator.js +590 -0
  126. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  127. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  128. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  129. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  130. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  131. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  132. package/src/BookNavigator/delete-modal-actions.js +1 -1
  133. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  134. package/src/BookNavigator/downloads/downloads.js +41 -25
  135. package/src/BookNavigator/search/search-provider.js +49 -27
  136. package/src/BookNavigator/search/search-results.js +23 -9
  137. package/src/BookNavigator/sharing.js +27 -0
  138. package/src/BookNavigator/viewable-files.js +95 -0
  139. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  140. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  141. package/src/BookReader/BookModel.js +64 -34
  142. package/src/BookReader/DragScrollable.js +233 -0
  143. package/src/BookReader/Mode1Up.js +56 -351
  144. package/src/BookReader/Mode1UpLit.js +388 -0
  145. package/src/BookReader/Mode2Up.js +73 -1318
  146. package/src/BookReader/Mode2UpLit.js +776 -0
  147. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  148. package/src/BookReader/ModeSmoothZoom.js +312 -0
  149. package/src/BookReader/ModeThumb.js +18 -12
  150. package/src/BookReader/Navbar/Navbar.js +14 -40
  151. package/src/BookReader/PageContainer.js +81 -6
  152. package/src/BookReader/ReduceSet.js +1 -1
  153. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  154. package/src/BookReader/events.js +2 -3
  155. package/src/BookReader/options.js +27 -2
  156. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  157. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  158. package/src/BookReader/utils/SelectionObserver.js +45 -0
  159. package/src/BookReader/utils.js +118 -13
  160. package/src/BookReader.js +427 -1061
  161. package/src/assets/icons/magnify-minus.svg +3 -7
  162. package/src/assets/icons/magnify-plus.svg +3 -7
  163. package/src/assets/icons/voice.svg +1 -0
  164. package/src/css/BookReader.scss +1 -5
  165. package/src/css/_BRBookmarks.scss +1 -1
  166. package/src/css/_BRComponent.scss +1 -1
  167. package/src/css/_BRmain.scss +16 -3
  168. package/src/css/_BRnav.scss +12 -39
  169. package/src/css/_BRpages.scss +149 -40
  170. package/src/css/_BRsearch.scss +68 -25
  171. package/src/css/_BRtoolbar.scss +5 -5
  172. package/src/css/_TextSelection.scss +87 -27
  173. package/src/css/_colorbox.scss +2 -2
  174. package/src/css/_controls.scss +20 -7
  175. package/src/css/_icons.scss +1 -1
  176. package/src/ia-bookreader/ia-bookreader.js +224 -0
  177. package/src/plugins/plugin.archive_analytics.js +3 -3
  178. package/src/plugins/plugin.autoplay.js +5 -11
  179. package/src/plugins/plugin.chapters.js +237 -191
  180. package/src/plugins/plugin.iiif.js +151 -0
  181. package/src/plugins/plugin.resume.js +3 -3
  182. package/src/plugins/plugin.text_selection.js +464 -134
  183. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  184. package/src/plugins/search/plugin.search.js +142 -125
  185. package/src/plugins/search/utils.js +43 -0
  186. package/src/plugins/search/view.js +33 -58
  187. package/src/plugins/tts/AbstractTTSEngine.js +71 -40
  188. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  189. package/src/plugins/tts/PageChunk.js +15 -21
  190. package/src/plugins/tts/PageChunkIterator.js +8 -12
  191. package/src/plugins/tts/WebTTSEngine.js +87 -71
  192. package/src/plugins/tts/plugin.tts.js +96 -127
  193. package/src/plugins/tts/utils.js +15 -25
  194. package/src/plugins/url/UrlPlugin.js +191 -0
  195. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  196. package/src/util/browserSniffing.js +22 -0
  197. package/src/util/docCookies.js +21 -2
  198. package/tests/e2e/README.md +37 -0
  199. package/tests/e2e/autoplay.test.js +2 -2
  200. package/tests/e2e/base.test.js +8 -16
  201. package/tests/e2e/helpers/base.js +53 -48
  202. package/tests/e2e/helpers/debug.js +1 -1
  203. package/tests/e2e/helpers/params.js +17 -0
  204. package/tests/e2e/helpers/rightToLeft.js +8 -14
  205. package/tests/e2e/helpers/search.js +73 -0
  206. package/tests/e2e/models/Navigation.js +20 -37
  207. package/tests/e2e/rightToLeft.test.js +4 -5
  208. package/tests/e2e/viewmode.test.js +40 -33
  209. package/tests/jest/BookNavigator/book-navigator.test.js +661 -0
  210. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  211. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  212. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  213. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  214. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  215. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  216. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  217. package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
  218. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  219. package/tests/jest/BookNavigator/viewable-files/viewable-files-provider.test.js +80 -0
  220. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  221. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  222. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  223. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  224. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  225. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  226. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  227. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  228. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  229. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  230. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  231. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  232. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  233. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  234. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  235. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  236. package/tests/jest/BookReader/utils/SelectionObserver.test.js +57 -0
  237. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  238. package/tests/jest/BookReader/utils.test.js +229 -0
  239. package/tests/jest/BookReader.keyboard.test.js +190 -0
  240. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  241. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  242. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  243. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  244. package/tests/jest/plugins/plugin.chapters.test.js +195 -0
  245. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  246. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  247. package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
  248. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  249. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
  250. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
  251. package/tests/jest/plugins/search/utils.js +25 -0
  252. package/tests/jest/plugins/search/utils.test.js +29 -0
  253. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +29 -9
  254. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  255. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  256. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  257. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  258. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  259. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  260. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  261. package/tests/jest/setup.js +3 -0
  262. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  263. package/tests/jest/util/docCookies.test.js +24 -0
  264. package/tests/{util → jest/util}/strings.test.js +1 -1
  265. package/tests/{utils.js → jest/utils.js} +38 -0
  266. package/webpack.config.js +12 -6
  267. package/.babelrc +0 -12
  268. package/.dependabot/config.yml +0 -6
  269. package/.testcaferc.json +0 -5
  270. package/BookReader/bookreader-component-bundle.js +0 -1450
  271. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  272. package/BookReader/bookreader-component-bundle.js.map +0 -1
  273. package/BookReader/jquery-1.10.1.js +0 -2
  274. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  275. package/BookReader/plugins/plugin.menu_toggle.js +0 -2
  276. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  277. package/BookReader/plugins/plugin.mobile_nav.js +0 -2
  278. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  279. package/BookReaderDemo/IIIFBookReader.js +0 -207
  280. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  281. package/BookReaderDemo/demo-iiif.js +0 -26
  282. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  283. package/karma.conf.js +0 -23
  284. package/src/BookNavigator/BookModel.js +0 -14
  285. package/src/BookNavigator/BookNavigator.js +0 -446
  286. package/src/BookNavigator/assets/book-loader.js +0 -27
  287. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  288. package/src/BookNavigator/search/a-search-result.js +0 -55
  289. package/src/BookReader/DebugConsole.js +0 -54
  290. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  291. package/src/ItemNavigator/ItemNavigator.js +0 -376
  292. package/src/ItemNavigator/providers/sharing.js +0 -29
  293. package/src/css/_MobileNav.scss +0 -194
  294. package/src/dragscrollable-br.js +0 -261
  295. package/src/lit-wrapper.js +0 -2
  296. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  297. package/src/plugins/plugin.mobile_nav.js +0 -287
  298. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  299. package/tests/BookReader/DebugConsole.test.js +0 -25
  300. package/tests/BookReader/Mode1Up.test.js +0 -164
  301. package/tests/BookReader/Mode2Up.test.js +0 -247
  302. package/tests/BookReader/utils.test.js +0 -109
  303. package/tests/e2e/helpers/desktopSearch.js +0 -72
  304. package/tests/e2e/helpers/mobileSearch.js +0 -85
  305. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  306. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  307. package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
  308. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  309. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  310. package/tests/plugins/plugin.chapters.test.js +0 -130
  311. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  312. package/tests/plugins/plugin.text_selection.test.js +0 -203
  313. package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,661 @@
1
+ import {
2
+ html,
3
+ elementUpdated,
4
+ fixtureCleanup,
5
+ fixtureSync,
6
+ } from '@open-wc/testing-helpers';
7
+ import sinon from 'sinon';
8
+ import DownloadsProvider from '@/src/BookNavigator/downloads/downloads-provider.js';
9
+ import SearchProvider from '@/src/BookNavigator/search/search-provider.js';
10
+ import SharingProvider from '@/src/BookNavigator/sharing.js';
11
+ import VisualAdjustmentsProvider from '@/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js';
12
+ import ViewableFilesProvider from '@/src/BookNavigator/viewable-files.js';
13
+ import { ModalManager } from '@internetarchive/modal-manager';
14
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
15
+ import '@/src/BookNavigator/book-navigator.js';
16
+
17
+ const promise0 = () => new Promise(res => setTimeout(res, 0));
18
+
19
+ const container = (sharedObserver = null) => {
20
+ const itemStub = {
21
+ metadata: {
22
+ identifier: 'foo',
23
+ creator: 'bar',
24
+ title: 'baz',
25
+ }
26
+ };
27
+ const modalMgr = new ModalManager();
28
+ return html`
29
+ <book-navigator
30
+ .itemMD=${itemStub}
31
+ .baseHost=${`https://foo.archive.org`}
32
+ .sharedObserver=${sharedObserver || new SharedResizeObserver()}
33
+ .modal=${modalMgr}
34
+ >
35
+ <div slot="main">
36
+ <div id="BookReader"></div>
37
+ <p class="visible-in-reader">now showing</p>
38
+ <\div>
39
+ </book-navigator>
40
+ `;
41
+ };
42
+
43
+ window.ResizeObserver = class ResizeObserver {
44
+ observe = sinon.fake()
45
+ unobserve = sinon.fake()
46
+ disconnect = sinon.fake()
47
+ };
48
+
49
+ beforeEach(() => {
50
+ window.archive_analytics = {
51
+ send_event_no_sampling: sinon.fake(),
52
+ send_event: sinon.fake()
53
+ };
54
+ });
55
+
56
+ afterEach(() => {
57
+ window.br = null;
58
+ fixtureCleanup();
59
+ const body = document.querySelector('body');
60
+ body.innerHTML = '';
61
+ sinon.restore();
62
+ });
63
+
64
+
65
+ describe('<book-navigator>', () => {
66
+ describe("How it loads", () => {
67
+ describe('Attaches BookReader listeners before `br.init` is called', () => {
68
+ test('binds global event listeners', async () => {
69
+ const el = fixtureSync(container());
70
+ const spy = sinon.spy(el, 'bindEventListeners');
71
+ await elementUpdated(el);
72
+ expect(spy.callCount).toEqual(1);
73
+ });
74
+ test('Listens for Global Event @BookReader:PostInit', async () => {
75
+ const brStub = {
76
+ resize: sinon.fake(),
77
+ currentIndex: sinon.fake(),
78
+ jumpToIndex: sinon.fake(),
79
+ options: { enableMultipleBooks: false }, // for multipleBooks
80
+ el: '#BookReader',
81
+ refs: {}
82
+ };
83
+
84
+ const sharedObserver = new SharedResizeObserver();
85
+ sinon.spy(sharedObserver, 'addObserver');
86
+ const el = fixtureSync(container(sharedObserver));
87
+
88
+ el.initializeBookSubmenus = sinon.fake();
89
+ el.emitLoadingStatusUpdate = sinon.fake();
90
+ el.handleResize = sinon.fake();
91
+ await elementUpdated(el);
92
+
93
+ expect(brStub.resize.callCount).toEqual(0);
94
+
95
+ window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
96
+ detail: { props: brStub }
97
+ }));
98
+ await elementUpdated(el);
99
+
100
+ expect(el.emitLoadingStatusUpdate.callCount).toEqual(1);
101
+ expect(el.bookreader).toEqual(brStub); // sets bookreader
102
+ expect(el.bookReaderLoaded).toBeTruthy(); // notes bookreader is loaded
103
+ expect(el.bookReaderCannotLoad).toBeFalsy();
104
+ expect(sharedObserver.addObserver.callCount).toEqual(1);
105
+
106
+ await promise0();
107
+
108
+ expect(brStub.resize.callCount > 0).toBeTruthy();
109
+ });
110
+ });
111
+ test('Emits a BrBookNav:PostInit event at completion', async () => {
112
+ let initEventFired = false;
113
+ window.addEventListener('BrBookNav:PostInit', (e) => {
114
+ initEventFired = true;
115
+ });
116
+ const el = fixtureSync(container());
117
+ const spy = sinon.spy(el, 'emitPostInit');
118
+
119
+ await elementUpdated(el);
120
+
121
+ expect(initEventFired).toBeTruthy();
122
+ expect(spy.callCount).toEqual(1);
123
+ });
124
+
125
+ test('creates an item image from metadata', async () => {
126
+ const el = fixtureSync(container());
127
+ const itemImage = fixtureSync(el.itemImage);
128
+ expect(itemImage).toBeInstanceOf(HTMLImageElement);
129
+ expect(itemImage.getAttribute('class')).toEqual('cover-img');
130
+ expect(itemImage.getAttribute('src')).toEqual('https://https://foo.archive.org/services/img/foo');
131
+ });
132
+ });
133
+ describe('Menu/Layer Provider', () => {
134
+ describe('Connecting with a provider:', () => {
135
+ // loads Providers with base shared resources
136
+ test('We load 3 Sub Menus by default', async() => {
137
+ const el = fixtureSync(container());
138
+ const $brContainer = document.createElement('div');
139
+ const brStub = {
140
+ resize: sinon.fake(),
141
+ currentIndex: sinon.fake(),
142
+ jumpToIndex: sinon.fake(),
143
+ options: {},
144
+ refs: {
145
+ $brContainer
146
+ }
147
+ };
148
+ el.bookreader = brStub;
149
+ await el.elementUpdated;
150
+
151
+ el.downloadableTypes = ['foo/bar'];
152
+ await el.elementUpdated;
153
+
154
+ el.initializeBookSubmenus();
155
+ await el.elementUpdated;
156
+ const defaultMenus = Object.keys(el.menuProviders);
157
+ expect(defaultMenus).toContain('downloads');
158
+ expect(el.menuProviders.downloads).toBeInstanceOf(DownloadsProvider);
159
+
160
+ expect(defaultMenus).toContain('share');
161
+ expect(el.menuProviders.share).toBeInstanceOf(SharingProvider);
162
+
163
+ expect(defaultMenus).toContain('visualAdjustments');
164
+ expect(el.menuProviders.visualAdjustments).toBeInstanceOf(VisualAdjustmentsProvider);
165
+ });
166
+ describe('Loading Sub Menus By Plugin Flags', () => {
167
+ test('Search: uses `enableSearch` flag', async() => {
168
+ const el = fixtureSync(container());
169
+ const $brContainer = document.createElement('div');
170
+ const brStub = {
171
+ resize: sinon.fake(),
172
+ currentIndex: sinon.fake(),
173
+ jumpToIndex: sinon.fake(),
174
+ options: { enableSearch: true },
175
+ refs: {
176
+ $brContainer
177
+ }
178
+ };
179
+ el.bookreader = brStub;
180
+ await el.elementUpdated;
181
+
182
+ el.initializeBookSubmenus();
183
+ await el.elementUpdated;
184
+
185
+ expect(el.menuProviders.search).toBeDefined();
186
+ expect(el.menuProviders.search).toBeInstanceOf(SearchProvider);
187
+
188
+ // also adds a menu shortcut
189
+ expect(el.menuShortcuts.find(m => m.id === 'search')).toBeDefined();
190
+ });
191
+ test('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
192
+ const el = fixtureSync(container());
193
+ const $brContainer = document.createElement('div');
194
+ const brStub = {
195
+ resize: sinon.fake(),
196
+ currentIndex: sinon.fake(),
197
+ jumpToIndex: sinon.fake(),
198
+ options: {
199
+ enableMultipleBooks: true,
200
+ multipleBooksList: {
201
+ by_subprefix: {
202
+ fooSubprefix: 'beep'
203
+ }
204
+ }
205
+ },
206
+ refs: {
207
+ $brContainer
208
+ }
209
+ };
210
+ el.bookreader = brStub;
211
+ await el.elementUpdated;
212
+
213
+ el.initializeBookSubmenus();
214
+ await el.elementUpdated;
215
+
216
+ expect(el.menuProviders.volumes).toBeDefined();
217
+ expect(el.menuProviders.volumes).toBeInstanceOf(ViewableFilesProvider);
218
+
219
+ // also adds a menu shortcut
220
+ expect(el.menuShortcuts.find(m => m.id === 'volumes')).toBeDefined();
221
+ });
222
+ });
223
+ test('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
224
+ const el = fixtureSync(container());
225
+ const baseConfigKeys = Object.keys(el.baseProviderConfig);
226
+ expect(baseConfigKeys).toContain('baseHost');
227
+ expect(baseConfigKeys).toContain('modal');
228
+ expect(baseConfigKeys).toContain('sharedObserver');
229
+ expect(baseConfigKeys).toContain('bookreader');
230
+ expect(baseConfigKeys).toContain('item');
231
+ expect(baseConfigKeys).toContain('signedIn');
232
+ expect(baseConfigKeys).toContain('isAdmin');
233
+ expect(baseConfigKeys).toContain('onProviderChange');
234
+ });
235
+
236
+ test('Downloads panel - does not show if no available `downloadableTypes`', async () => {
237
+ const el = fixtureSync(container());
238
+ const $brContainer = document.createElement('div');
239
+ const brStub = {
240
+ resize: sinon.fake(),
241
+ currentIndex: sinon.fake(),
242
+ jumpToIndex: sinon.fake(),
243
+ options: {},
244
+ refs: {
245
+ $brContainer
246
+ }
247
+ };
248
+ el.bookreader = brStub;
249
+ await el.elementUpdated;
250
+
251
+ el.initializeBookSubmenus();
252
+ await el.elementUpdated;
253
+ const defaultMenus = Object.keys(el.menuProviders);
254
+ expect(defaultMenus.find(menu => menu === 'downloads')).toBeUndefined;
255
+ });
256
+ });
257
+
258
+ describe('Controlling Menu Side Panel & Shortcuts', () => {
259
+ describe('Side Menu Panels', () => {
260
+ test('`isWideEnoughToOpenMenu` checks if menu should be open', async () => {
261
+ const el = fixtureSync(container());
262
+ el.brWidth = 300;
263
+ await el.elementUpdated;
264
+
265
+ expect(el.isWideEnoughToOpenMenu).toEqual(false);
266
+
267
+ el.brWidth = 641;
268
+ await el.elementUpdated;
269
+
270
+ expect(el.isWideEnoughToOpenMenu).toEqual(true);
271
+ });
272
+ describe('Control which side menu to toggle open by using: `this.updateSideMenu`', () => {
273
+ test('Emits `@updateSideMenu` to signal which menu gets the update', async () => {
274
+ const el = fixtureSync(container());
275
+ const brStub = {
276
+ resize: sinon.fake(),
277
+ currentIndex: sinon.fake(),
278
+ jumpToIndex: sinon.fake(),
279
+ options: { enableMultipleBooks: true },
280
+ refs: {},
281
+ };
282
+ el.bookreader = brStub;
283
+ await elementUpdated(el);
284
+
285
+ let initEventFired = false;
286
+ let eventDetails = {};
287
+ el.addEventListener('updateSideMenu', (e) => {
288
+ eventDetails = e.detail;
289
+ initEventFired = true;
290
+ });
291
+
292
+ el.updateSideMenu('foo', 'open');
293
+ expect(initEventFired).toEqual(true);
294
+ expect(eventDetails.menuId).toEqual('foo');
295
+ expect(eventDetails.action).toEqual('open');
296
+ });
297
+ test('Will Not Emit `@updateSideMenu` if menu ID is missing', async() => {
298
+ const el = fixtureSync(container());
299
+ const brStub = {
300
+ resize: sinon.fake(),
301
+ currentIndex: sinon.fake(),
302
+ jumpToIndex: sinon.fake(),
303
+ options: { enableMultipleBooks: true },
304
+ refs: {},
305
+ };
306
+ el.bookreader = brStub;
307
+ await elementUpdated(el);
308
+
309
+ let initEventFired = false;
310
+ el.addEventListener('updateSideMenu', (e) => {
311
+ initEventFired = true;
312
+ });
313
+
314
+ el.updateSideMenu('', 'open');
315
+ expect(initEventFired).toEqual(false);
316
+ });
317
+ });
318
+ });
319
+
320
+ describe('Shortcuts', () => {
321
+ test('has specific order of menu shortcuts to show', () => {
322
+ const el = fixtureSync(container());
323
+ expect(el.shortcutOrder).toEqual([
324
+ 'fullscreen',
325
+ 'volumes',
326
+ 'chapters',
327
+ 'search',
328
+ 'bookmarks'
329
+ ]);
330
+ });
331
+ });
332
+
333
+ describe('Behaviors for specific menus', () => {
334
+ describe('Search menu - ref: plugin.search.js', () => {
335
+ test('Event: listens for `BookReader:ToggleSearchMenu to open search side panel', async () => {
336
+ const el = fixtureSync(container());
337
+ const brStub = {
338
+ resize: sinon.fake(),
339
+ currentIndex: sinon.fake(),
340
+ jumpToIndex: sinon.fake(),
341
+ options: { enableMultipleBooks: true },
342
+ refs: {},
343
+ };
344
+ el.bookreader = brStub;
345
+ await elementUpdated(el);
346
+
347
+ let sidePanelConfig = {};
348
+ el.addEventListener('updateSideMenu', (e) => {
349
+ console.log();
350
+ sidePanelConfig = e.detail;
351
+ });
352
+ const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
353
+ window.dispatchEvent(toggleSearchMenuEvent);
354
+
355
+ await elementUpdated(el);
356
+ expect(sidePanelConfig.menuId).toEqual('search');
357
+ expect(sidePanelConfig.action).toEqual('toggle');
358
+ });
359
+ });
360
+ });
361
+ });
362
+ });
363
+
364
+ describe('Resizing',() => {
365
+ test('keeps track of `brWidth` and `brHeight`', async () => {
366
+ const el = fixtureSync(container());
367
+ const brStub = {
368
+ resize: sinon.fake(),
369
+ options: {},
370
+ refs: {
371
+ $brContainer: document.createElement('div')
372
+ }
373
+ };
374
+ el.bookreader = brStub;
375
+ await elementUpdated(el);
376
+ expect(el.brWidth).toEqual(0);
377
+ expect(el.brHeight).toEqual(0);
378
+
379
+ const mockResizeEvent = {
380
+ contentRect: {
381
+ height: 500,
382
+ width: 900
383
+ },
384
+ target: el.mainBRContainer
385
+ };
386
+ el.handleResize(mockResizeEvent);
387
+
388
+ await elementUpdated(el);
389
+ await promise0();
390
+
391
+ expect(el.brHeight).toEqual(500);
392
+ expect(el.brWidth).toEqual(900);
393
+ });
394
+ test('resizes if height/width changes && is not animating', async () => {
395
+ const el = fixtureSync(container());
396
+ const brStub = {
397
+ animating: false,
398
+ resize: sinon.fake(),
399
+ options: {},
400
+ refs: {
401
+ $brContainer: document.createElement('div')
402
+ }
403
+ };
404
+
405
+ el.bookreader = brStub;
406
+ await elementUpdated(el);
407
+ expect(el.brWidth).toEqual(0);
408
+ expect(el.brHeight).toEqual(0);
409
+
410
+ const mockResizeEvent = {
411
+ contentRect: {
412
+ height: 500,
413
+ width: 900
414
+ },
415
+ target: el.mainBRContainer
416
+ };
417
+ el.handleResize(mockResizeEvent);
418
+
419
+ await elementUpdated(el);
420
+ await promise0();
421
+
422
+ expect(brStub.resize.callCount).toEqual(1);
423
+ });
424
+ test('does not resize bookreader if animating', async () => {
425
+ const el = fixtureSync(container());
426
+ const brStub = {
427
+ animating: true, // <-- testing for this
428
+ resize: sinon.fake(),
429
+ currentIndex: sinon.fake(),
430
+ jumpToIndex: sinon.fake(),
431
+ options: { enableMultipleBooks: true },
432
+ refs: {},
433
+ };
434
+
435
+ el.bookreader = brStub;
436
+ await elementUpdated(el);
437
+
438
+ expect(el.bookreader.resize.callCount).toEqual(0);
439
+ expect(el.bookreader.currentIndex.callCount).toEqual(0);
440
+ expect(el.bookreader.jumpToIndex.callCount).toEqual(0);
441
+ });
442
+ });
443
+
444
+ describe('Fullscreen Management', () => {
445
+ test('needs option: `enableFSLogoShortcut` to use FS logo', async () => {
446
+ const el = fixtureSync(container());
447
+ const brStub = {
448
+ isFullscreen: () => true,
449
+ options: {
450
+ enableFSLogoShortcut: false,
451
+ },
452
+ refs: {},
453
+ };
454
+
455
+ el.bookreader = brStub;
456
+ el.emitMenuShortcutsUpdated = sinon.fake();
457
+ await elementUpdated(el);
458
+
459
+ el.manageFullScreenBehavior();
460
+ await elementUpdated(el);
461
+ expect(el.menuShortcuts.length).toEqual(0);
462
+ });
463
+ test('sets fullscreen shortcut when entering Fullscreen', async () => {
464
+ const el = fixtureSync(container());
465
+ const brStub = {
466
+ isFullscreen: () => true,
467
+ options: {
468
+ enableFSLogoShortcut: true,
469
+ },
470
+ refs: {},
471
+ };
472
+
473
+ el.bookreader = brStub;
474
+ el.emitMenuShortcutsUpdated = sinon.fake();
475
+ await elementUpdated(el);
476
+
477
+ el.manageFullScreenBehavior();
478
+ await elementUpdated(el);
479
+ expect(el.menuShortcuts.length).toEqual(1);
480
+ expect(el.menuShortcuts[0].id).toEqual('fullscreen');
481
+ expect(el.menuShortcuts[0].icon).toBeDefined();
482
+ expect(el.emitMenuShortcutsUpdated.callCount).toEqual(1);
483
+ });
484
+ test('clicking Fullscreen shortcut closes fullscreen', async () => {
485
+ const el = fixtureSync(container());
486
+ const brStub = {
487
+ isFullscreen: () => true,
488
+ options: {
489
+ enableFSLogoShortcut: true,
490
+ },
491
+ refs: {},
492
+ };
493
+
494
+ el.bookreader = brStub;
495
+ el.emitMenuShortcutsUpdated = sinon.fake();
496
+ el.closeFullscreen = sinon.fake();
497
+ await elementUpdated(el);
498
+
499
+ el.manageFullScreenBehavior();
500
+ await elementUpdated(el);
501
+
502
+ fixtureSync(el.menuShortcuts[0].icon).click();
503
+ await elementUpdated(el);
504
+
505
+ expect(el.closeFullscreen.callCount).toEqual(1);
506
+ });
507
+ test('removes Fullscreen shortcut when leaving fullscreen', async() => {
508
+ const el = fixtureSync(container());
509
+ const brStub = {
510
+ isFullscreen: () => false,
511
+ options: {
512
+ enableFSLogoShortcut: true,
513
+ },
514
+ refs: {},
515
+ };
516
+
517
+ el.bookreader = brStub;
518
+ el.emitMenuShortcutsUpdated = sinon.fake();
519
+ await elementUpdated(el);
520
+
521
+ el.manageFullScreenBehavior();
522
+ await elementUpdated(el);
523
+ expect(el.menuShortcuts.length).toEqual(0);
524
+ expect(el.emitMenuShortcutsUpdated.callCount).toEqual(1);
525
+ });
526
+ test('Event: Listens for `BookReader:FullscreenToggled', async() => {
527
+ const el = fixtureSync(container());
528
+ const brStub = {
529
+ isFullscreen: () => true,
530
+ resize: sinon.fake(),
531
+ currentIndex: sinon.fake(),
532
+ jumpToIndex: sinon.fake(),
533
+ options: {
534
+ enableFSLogoShortcut: true,
535
+ },
536
+ refs: {},
537
+ };
538
+ el.bookreader = brStub;
539
+ el.manageFullScreenBehavior = sinon.fake();
540
+ await elementUpdated(el);
541
+
542
+ window.dispatchEvent(new CustomEvent('BookReader:fullscreenToggled', {
543
+ detail: { props: brStub }
544
+ }));
545
+ await elementUpdated(el);
546
+
547
+ expect(el.manageFullScreenBehavior.callCount).toEqual(1);
548
+ });
549
+ });
550
+ describe('Handles Restricted Books', () => {
551
+ describe('contextMenu is prevented when book is restricted', () => {
552
+ it('watches on `div.BRscreen`', async () => {
553
+ const el = fixtureSync(container());
554
+ const brStub = {
555
+ options: { restricted: true },
556
+ };
557
+
558
+ el.bookreader = brStub;
559
+ el.bookIsRestricted = true;
560
+
561
+ const elSpy = sinon.spy(el.manageContextMenuVisibility);
562
+ await el.elementUpdated;
563
+
564
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
565
+ expect(window.archive_analytics.send_event.called).toEqual(false);
566
+ expect(elSpy.called).toEqual(false);
567
+
568
+ const body = document.querySelector('body');
569
+
570
+ const divBRscreen = document.createElement('div');
571
+ divBRscreen.classList.add('BRscreen');
572
+ body.appendChild(divBRscreen);
573
+
574
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
575
+
576
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
577
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
578
+ expect(preventDefaultSpy.called).toEqual(false);
579
+
580
+ divBRscreen.dispatchEvent(contextMenuEvent);
581
+
582
+ // analytics fires
583
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
584
+ false
585
+ );
586
+ expect(window.archive_analytics.send_event.called).toEqual(true);
587
+ // we prevent default
588
+ expect(preventDefaultSpy.called).toEqual(true);
589
+ });
590
+ it('watches on `img.BRpageimage`', async () => {
591
+ const el = fixtureSync(container());
592
+ const brStub = {
593
+ options: { restricted: true },
594
+ };
595
+
596
+ el.bookreader = brStub;
597
+ el.bookIsRestricted = true;
598
+
599
+ await el.elementUpdated;
600
+
601
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
602
+ expect(window.archive_analytics.send_event.called).toEqual(false);
603
+
604
+ const body = document.querySelector('body');
605
+ // const element stub for img.BRpageimage
606
+ const imgBRpageimage = document.createElement('img');
607
+ imgBRpageimage.classList.add('BRpageimage');
608
+ body.appendChild(imgBRpageimage);
609
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
610
+
611
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
612
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
613
+ expect(preventDefaultSpy.called).toEqual(false);
614
+
615
+ imgBRpageimage.dispatchEvent(contextMenuEvent);
616
+
617
+ // analytics fires
618
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
619
+ expect(window.archive_analytics.send_event.called).toEqual(true);
620
+ // we prevent default
621
+ expect(preventDefaultSpy.called).toEqual(true);
622
+ });
623
+ });
624
+ it('Allows unrestricted books access to context menu', async () => {
625
+ const el = fixtureSync(container());
626
+ const brStub = {
627
+ options: { restricted: false },
628
+ };
629
+
630
+ el.bookreader = brStub;
631
+ el.bookIsRestricted = false;
632
+
633
+ await el.elementUpdated;
634
+
635
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(
636
+ false
637
+ );
638
+ expect(window.archive_analytics.send_event.called).toEqual(false);
639
+
640
+
641
+ const body = document.querySelector('body');
642
+ // const element stub for img.BRpageimage
643
+ const imgBRpageimage = document.createElement('img');
644
+ imgBRpageimage.classList.add('not-targeted-element');
645
+ body.appendChild(imgBRpageimage);
646
+ const contextMenuEvent = new Event('contextmenu', { bubbles: true });
647
+
648
+ // Set spy on contextMenuEvent to check if `preventDefault` is called
649
+ const preventDefaultSpy = sinon.spy(contextMenuEvent, 'preventDefault');
650
+ expect(preventDefaultSpy.called).toEqual(false);
651
+
652
+ imgBRpageimage.dispatchEvent(contextMenuEvent);
653
+
654
+ // analytics fires
655
+ expect(window.archive_analytics.send_event_no_sampling.called).toEqual(false);
656
+ expect(window.archive_analytics.send_event.called).toEqual(true);
657
+ // we do not prevent default
658
+ expect(preventDefaultSpy.called).toEqual(false);
659
+ });
660
+ });
661
+ });
@@ -0,0 +1,43 @@
1
+ import {
2
+ html,
3
+ fixtureSync,
4
+ fixtureCleanup,
5
+ } from '@open-wc/testing-helpers';
6
+ import '@/src/BookNavigator/bookmarks/bookmark-button.js';
7
+ import sinon from 'sinon';
8
+
9
+ afterEach(() => {
10
+ sinon.restore();
11
+ fixtureCleanup();
12
+ });
13
+
14
+ describe('<bookmark-button>', () => {
15
+ test('sets default properties', async () => {
16
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
17
+
18
+ expect(el.side).toBeUndefined();
19
+ expect(el.state).toEqual('hollow');
20
+ });
21
+ test('Event: fires `@bookmarkButtonClicked on click', async () => {
22
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
23
+ let buttonClicked = false;
24
+ el.addEventListener('bookmarkButtonClicked', () => { buttonClicked = true; });
25
+ const eventStub = { preventDefault: sinon.fake()};
26
+ el.handleClick(eventStub);
27
+ await el.updateComplete;
28
+
29
+ expect(buttonClicked).toBeTruthy();
30
+ expect(eventStub.preventDefault.callCount).toEqual(1);
31
+ });
32
+ test('Title: Toggles title between `Add/Remove bookmark`', async () => {
33
+ const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
34
+ expect(el.title).toEqual('Add bookmark');
35
+ expect(el.state).toEqual('hollow');
36
+
37
+ el.state = 'filled';
38
+ await el.updateComplete;
39
+
40
+ expect(el.title).toEqual('Remove bookmark');
41
+ expect(el.state).not.toEqual('hollow');
42
+ });
43
+ });