@internetarchive/bookreader 5.0.0-26 → 5.0.0-29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/_/husky.sh +30 -0
- package/BookReader/BookReader.css +1 -1
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bookreader-component-bundle.js +570 -542
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +23 -0
- package/BookReader/bookreader-component-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReaderDemo/BookReaderDemo.css +14 -1
- package/BookReaderDemo/IADemoBr.js +104 -0
- package/BookReaderDemo/demo-internetarchive.html +65 -98
- package/CHANGELOG.md +10 -0
- package/package.json +9 -6
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/book-navigator.js +521 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +20 -8
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +84 -51
- package/src/BookNavigator/downloads/downloads-provider.js +5 -9
- package/src/BookNavigator/downloads/downloads.js +1 -0
- package/src/BookNavigator/search/search-provider.js +15 -8
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +9 -8
- package/src/BookNavigator/volumes/volumes-provider.js +44 -13
- package/src/BookNavigator/volumes/volumes.js +14 -3
- package/src/BookReader/options.js +6 -0
- package/src/BookReader.js +20 -8
- package/src/BookReaderComponent/BookReaderComponent.js +53 -32
- package/src/css/_BRComponent.scss +1 -1
- package/src/plugins/search/plugin.search.js +10 -9
- package/src/plugins/tts/FestivalTTSEngine.js +1 -1
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/url/plugin.url.js +220 -0
- package/{src → stat}/BookNavigator/BookModel.js +0 -0
- package/{src → stat}/BookNavigator/BookNavigator.js +109 -102
- package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
- package/stat/BookNavigator/assets/button-base.js +61 -0
- package/stat/BookNavigator/assets/ia-logo.js +17 -0
- package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
- package/stat/BookNavigator/assets/icon_close.js +3 -0
- package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
- package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/stat/BookNavigator/assets/icon_volumes.js +11 -0
- package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
- package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
- package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
- package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
- package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
- package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
- package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
- package/stat/BookNavigator/delete-modal-actions.js +49 -0
- package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
- package/stat/BookNavigator/downloads/downloads.js +139 -0
- package/stat/BookNavigator/provider-config.js +0 -0
- package/stat/BookNavigator/search/a-search-result.js +55 -0
- package/stat/BookNavigator/search/search-provider.js +180 -0
- package/stat/BookNavigator/search/search-results.js +360 -0
- package/{src/ItemNavigator/providers → stat/BookNavigator}/sharing.js +3 -5
- package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
- package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
- package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
- package/stat/BookNavigator/volumes/volumes.js +178 -0
- package/stat/BookReader/BookModel.js +518 -0
- package/stat/BookReader/DebugConsole.js +54 -0
- package/stat/BookReader/DragScrollable.js +233 -0
- package/stat/BookReader/ImageCache.js +116 -0
- package/stat/BookReader/Mode1Up.js +102 -0
- package/stat/BookReader/Mode1UpLit.js +434 -0
- package/stat/BookReader/Mode2Up.js +1372 -0
- package/stat/BookReader/ModeSmoothZoom.js +177 -0
- package/stat/BookReader/ModeThumb.js +344 -0
- package/stat/BookReader/Navbar/Navbar.js +310 -0
- package/stat/BookReader/PageContainer.js +120 -0
- package/stat/BookReader/ReduceSet.js +26 -0
- package/stat/BookReader/Toolbar/Toolbar.js +384 -0
- package/stat/BookReader/events.js +20 -0
- package/stat/BookReader/options.js +324 -0
- package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/stat/BookReader/utils/classes.js +36 -0
- package/stat/BookReader/utils.js +240 -0
- package/stat/BookReader.js +2550 -0
- package/stat/BookReaderComponent/BookReaderComponent.js +117 -0
- package/stat/assets/icons/1up.svg +12 -0
- package/stat/assets/icons/2up.svg +15 -0
- package/stat/assets/icons/advance.svg +26 -0
- package/stat/assets/icons/chevron-right.svg +1 -0
- package/stat/assets/icons/close-circle-dark.svg +1 -0
- package/stat/assets/icons/close-circle.svg +1 -0
- package/stat/assets/icons/fullscreen.svg +17 -0
- package/stat/assets/icons/fullscreen_exit.svg +17 -0
- package/stat/assets/icons/hamburger.svg +15 -0
- package/stat/assets/icons/left-arrow.svg +12 -0
- package/stat/assets/icons/magnify-minus.svg +16 -0
- package/stat/assets/icons/magnify-plus.svg +17 -0
- package/stat/assets/icons/magnify.svg +15 -0
- package/stat/assets/icons/pause.svg +23 -0
- package/stat/assets/icons/play.svg +22 -0
- package/stat/assets/icons/playback-speed.svg +34 -0
- package/stat/assets/icons/read-aloud.svg +22 -0
- package/stat/assets/icons/review.svg +22 -0
- package/stat/assets/icons/thumbnails.svg +17 -0
- package/stat/assets/icons/voice.svg +1 -0
- package/stat/assets/icons/volume-full.svg +22 -0
- package/stat/assets/images/BRicons.png +0 -0
- package/stat/assets/images/BRicons.svg +94 -0
- package/stat/assets/images/BRicons_ia.png +0 -0
- package/stat/assets/images/back_pages.png +0 -0
- package/stat/assets/images/book_bottom_icon.png +0 -0
- package/stat/assets/images/book_down_icon.png +0 -0
- package/stat/assets/images/book_left_icon.png +0 -0
- package/stat/assets/images/book_leftmost_icon.png +0 -0
- package/stat/assets/images/book_right_icon.png +0 -0
- package/stat/assets/images/book_rightmost_icon.png +0 -0
- package/stat/assets/images/book_top_icon.png +0 -0
- package/stat/assets/images/book_up_icon.png +0 -0
- package/stat/assets/images/books_graphic.svg +177 -0
- package/stat/assets/images/booksplit.png +0 -0
- package/stat/assets/images/control_pause_icon.png +0 -0
- package/stat/assets/images/control_play_icon.png +0 -0
- package/stat/assets/images/embed_icon.png +0 -0
- package/stat/assets/images/icon-home-ia.png +0 -0
- package/stat/assets/images/icon_OL-logo-xs.png +0 -0
- package/stat/assets/images/icon_alert-xs.png +0 -0
- package/stat/assets/images/icon_book.svg +12 -0
- package/stat/assets/images/icon_bookmark.svg +12 -0
- package/stat/assets/images/icon_close-pop.png +0 -0
- package/stat/assets/images/icon_download.png +0 -0
- package/stat/assets/images/icon_gear.svg +14 -0
- package/stat/assets/images/icon_hamburger.svg +20 -0
- package/stat/assets/images/icon_home.png +0 -0
- package/stat/assets/images/icon_home.svg +21 -0
- package/stat/assets/images/icon_home_ia.png +0 -0
- package/stat/assets/images/icon_indicator.png +0 -0
- package/stat/assets/images/icon_info.svg +11 -0
- package/stat/assets/images/icon_one_page.svg +8 -0
- package/stat/assets/images/icon_pause.svg +1 -0
- package/stat/assets/images/icon_play.svg +1 -0
- package/stat/assets/images/icon_playback-rate.svg +15 -0
- package/stat/assets/images/icon_return.png +0 -0
- package/stat/assets/images/icon_search_button.svg +8 -0
- package/stat/assets/images/icon_share.svg +9 -0
- package/stat/assets/images/icon_skip-ahead.svg +6 -0
- package/stat/assets/images/icon_skip-back.svg +13 -0
- package/stat/assets/images/icon_speaker.svg +18 -0
- package/stat/assets/images/icon_speaker_open.svg +10 -0
- package/stat/assets/images/icon_thumbnails.svg +12 -0
- package/stat/assets/images/icon_toc.svg +5 -0
- package/stat/assets/images/icon_two_pages.svg +9 -0
- package/stat/assets/images/icon_zoomer.png +0 -0
- package/stat/assets/images/loading.gif +0 -0
- package/stat/assets/images/logo_icon.png +0 -0
- package/stat/assets/images/marker_chap-off.png +0 -0
- package/stat/assets/images/marker_chap-off.svg +11 -0
- package/stat/assets/images/marker_chap-off_ia.png +0 -0
- package/stat/assets/images/marker_chap-on.png +0 -0
- package/stat/assets/images/marker_chap-on.svg +11 -0
- package/stat/assets/images/marker_srch-on.svg +11 -0
- package/stat/assets/images/marker_srchchap-off.png +0 -0
- package/stat/assets/images/marker_srchchap-on.png +0 -0
- package/stat/assets/images/nav_control-dn.png +0 -0
- package/stat/assets/images/nav_control-dn_ia.png +0 -0
- package/stat/assets/images/nav_control-up.png +0 -0
- package/stat/assets/images/nav_control-up_ia.png +0 -0
- package/stat/assets/images/nav_control.png +0 -0
- package/stat/assets/images/one_page_mode_icon.png +0 -0
- package/stat/assets/images/paper-badge.png +0 -0
- package/stat/assets/images/print_icon.png +0 -0
- package/stat/assets/images/progressbar.gif +0 -0
- package/stat/assets/images/right_edges.png +0 -0
- package/stat/assets/images/slider.png +0 -0
- package/stat/assets/images/slider_ia.png +0 -0
- package/stat/assets/images/thumbnail_mode_icon.png +0 -0
- package/stat/assets/images/transparent.png +0 -0
- package/stat/assets/images/two_page_mode_icon.png +0 -0
- package/stat/assets/images/zoom_in_icon.png +0 -0
- package/stat/assets/images/zoom_out_icon.png +0 -0
- package/stat/css/BookReader.scss +89 -0
- package/stat/css/_BRBookmarks.scss +29 -0
- package/stat/css/_BRComponent.scss +13 -0
- package/stat/css/_BRfloat.scss +197 -0
- package/stat/css/_BRicon.scss +48 -0
- package/stat/css/_BRmain.scss +251 -0
- package/stat/css/_BRnav.scss +359 -0
- package/stat/css/_BRpages.scss +139 -0
- package/stat/css/_BRsearch.scss +226 -0
- package/stat/css/_BRtoolbar.scss +84 -0
- package/stat/css/_BRvendor.scss +5 -0
- package/stat/css/_MobileNav.scss +194 -0
- package/stat/css/_TextSelection.scss +32 -0
- package/stat/css/_colorbox.scss +52 -0
- package/stat/css/_controls.scss +253 -0
- package/stat/css/_icons.scss +121 -0
- package/stat/jquery-wrapper.js +4 -0
- package/stat/plugins/plugin.archive_analytics.js +86 -0
- package/stat/plugins/plugin.autoplay.js +129 -0
- package/stat/plugins/plugin.chapters.js +248 -0
- package/stat/plugins/plugin.iframe.js +48 -0
- package/stat/plugins/plugin.mobile_nav.js +288 -0
- package/stat/plugins/plugin.resume.js +68 -0
- package/stat/plugins/plugin.text_selection.js +291 -0
- package/{src → stat}/plugins/plugin.url.js +0 -0
- package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
- package/stat/plugins/search/plugin.search.js +439 -0
- package/stat/plugins/search/view.js +439 -0
- package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
- package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
- package/stat/plugins/tts/PageChunk.js +107 -0
- package/stat/plugins/tts/PageChunkIterator.js +163 -0
- package/stat/plugins/tts/WebTTSEngine.js +357 -0
- package/stat/plugins/tts/plugin.tts.js +357 -0
- package/stat/plugins/tts/tooltip_dict.js +15 -0
- package/stat/plugins/tts/utils.js +91 -0
- package/stat/util/browserSniffing.js +30 -0
- package/stat/util/debouncer.js +26 -0
- package/stat/util/docCookies.js +67 -0
- package/stat/util/strings.js +34 -0
- package/tests/e2e/viewmode.test.js +30 -30
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +64 -52
- package/tests/jest/BookReader.test.js +1 -1
- package/tests/jest/plugins/url/UrlPlugin.test.js +175 -0
- package/tests/jest/plugins/{plugin.url.test.js → url/plugin.url.test.js} +3 -2
- package/tests/karma/BookNavigator/book-navigator.test.js +413 -108
- package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
- package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +6 -3
- package/tests/karma/BookNavigator/search/search-provider.test.js +106 -6
- package/tests/karma/BookNavigator/search/search-results.test.js +0 -2
- package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +29 -20
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +46 -22
- package/webpack.config.js +1 -1
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/ItemNavigator/ItemNavigator.js +0 -377
|
@@ -6,175 +6,480 @@ import {
|
|
|
6
6
|
expect,
|
|
7
7
|
} from '@open-wc/testing';
|
|
8
8
|
import sinon from 'sinon';
|
|
9
|
+
import DownloadsProvider from '../../../src/BookNavigator/downloads/downloads-provider.js';
|
|
10
|
+
import SearchProvider from '../../../src/BookNavigator/search/search-provider.js';
|
|
11
|
+
import SharingProvider from '../../../src/BookNavigator/sharing.js';
|
|
12
|
+
import VisualAdjustmentsProvider from '../../../src/BookNavigator/visual-adjustments/visual-adjustments-provider.js';
|
|
13
|
+
import VolumesProvider from '../../../src/BookNavigator/volumes/volumes-provider.js';
|
|
14
|
+
import { ModalManager } from '@internetarchive/modal-manager';
|
|
15
|
+
import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
|
|
16
|
+
import '../../../src/BookNavigator/book-navigator.js';
|
|
9
17
|
|
|
10
|
-
|
|
11
|
-
import BRFullscreenMgr from '../../../src/BookNavigator/br-fullscreen-mgr.js';
|
|
18
|
+
const promise0 = () => new Promise(res => setTimeout(res, 0));
|
|
12
19
|
|
|
13
|
-
const container = () => {
|
|
14
|
-
const
|
|
20
|
+
const container = (sharedObserver = null) => {
|
|
21
|
+
const itemStub = {
|
|
22
|
+
metadata: {
|
|
23
|
+
identifier: 'foo',
|
|
24
|
+
creator: 'bar',
|
|
25
|
+
title: 'baz',
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const modalMgr = new ModalManager();
|
|
15
29
|
return html`
|
|
16
30
|
<book-navigator
|
|
17
|
-
.
|
|
18
|
-
.baseHost
|
|
31
|
+
.itemMD=${itemStub}
|
|
32
|
+
.baseHost=${`https://foo.archive.org`}
|
|
33
|
+
.sharedObserver=${sharedObserver || new SharedResizeObserver()}
|
|
34
|
+
.modal=${modalMgr}
|
|
19
35
|
>
|
|
20
|
-
<div slot="
|
|
36
|
+
<div slot="theater-main">
|
|
37
|
+
<div id="BookReader"></div>
|
|
21
38
|
<p class="visible-in-reader">now showing</p>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</
|
|
39
|
+
<\div>
|
|
40
|
+
</book-navigator>
|
|
25
41
|
`;
|
|
26
42
|
};
|
|
27
43
|
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
const body = document.querySelector('body');
|
|
30
|
-
const brHook = document.createElement('div');
|
|
31
|
-
brHook.setAttribute('id', 'BookReader');
|
|
32
|
-
body.appendChild(brHook);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
44
|
afterEach(() => {
|
|
36
45
|
window.br = null;
|
|
37
46
|
fixtureCleanup();
|
|
47
|
+
const body = document.querySelector('body');
|
|
48
|
+
body.innerHTML = '';
|
|
49
|
+
sinon.restore();
|
|
38
50
|
});
|
|
39
51
|
|
|
40
52
|
|
|
41
53
|
describe('<book-navigator>', () => {
|
|
42
|
-
describe(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
describe("How it loads", () => {
|
|
55
|
+
describe('Attaches BookReader listeners before `br.init` is called', () => {
|
|
56
|
+
it('binds global event listeners', async () => {
|
|
57
|
+
const el = fixtureSync(container());
|
|
58
|
+
const spy = sinon.spy(el, 'bindEventListeners');
|
|
59
|
+
await elementUpdated(el);
|
|
60
|
+
expect(spy.callCount).to.equal(1);
|
|
61
|
+
});
|
|
62
|
+
it('Listens for Global Event @BookReader:PostInit', async () => {
|
|
63
|
+
const brStub = {
|
|
64
|
+
resize: sinon.fake(),
|
|
65
|
+
currentIndex: sinon.fake(),
|
|
66
|
+
jumpToIndex: sinon.fake(),
|
|
67
|
+
options: { enableMultipleBooks: false }, // for multipleBooks
|
|
68
|
+
el: '#BookReader'
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const sharedObserver = new SharedResizeObserver();
|
|
72
|
+
sinon.spy(sharedObserver, 'addObserver');
|
|
73
|
+
const el = fixtureSync(container(sharedObserver));
|
|
74
|
+
|
|
75
|
+
el.initializeBookSubmenus = sinon.fake();
|
|
76
|
+
el.emitLoadingStatusUpdate = sinon.fake();
|
|
77
|
+
el.handleResize = sinon.fake();
|
|
78
|
+
await elementUpdated(el);
|
|
79
|
+
|
|
80
|
+
expect(brStub.resize.callCount).to.equal(0);
|
|
81
|
+
|
|
82
|
+
window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
|
|
83
|
+
detail: { props: brStub }
|
|
84
|
+
}));
|
|
85
|
+
await elementUpdated(el);
|
|
86
|
+
|
|
87
|
+
expect(el.emitLoadingStatusUpdate.callCount).to.equal(1);
|
|
88
|
+
expect(el.bookreader).to.equal(brStub); // sets bookreader
|
|
89
|
+
expect(el.bookReaderLoaded).to.be.true; // notes bookreader is loaded
|
|
90
|
+
expect(el.bookReaderCannotLoad).to.be.false;
|
|
91
|
+
expect(sharedObserver.addObserver.callCount).to.equal(1);
|
|
92
|
+
|
|
93
|
+
await promise0();
|
|
49
94
|
|
|
50
|
-
|
|
95
|
+
expect(brStub.resize.callCount > 0).to.be.true;
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
it('Emits a BrBookNav:PostInit event at completion', async () => {
|
|
51
99
|
let initEventFired = false;
|
|
52
100
|
window.addEventListener('BrBookNav:PostInit', (e) => {
|
|
53
101
|
initEventFired = true;
|
|
54
102
|
});
|
|
55
103
|
const el = fixtureSync(container());
|
|
56
104
|
const spy = sinon.spy(el, 'emitPostInit');
|
|
105
|
+
|
|
57
106
|
await elementUpdated(el);
|
|
58
107
|
|
|
59
108
|
expect(initEventFired).to.be.true;
|
|
60
109
|
expect(spy.callCount).to.equal(1);
|
|
61
110
|
});
|
|
62
|
-
});
|
|
63
111
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
el
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
await elementUpdated(el);
|
|
78
|
-
window.dispatchEvent(new CustomEvent('BookReader:PostInit', {
|
|
79
|
-
detail: { props: brStub }
|
|
80
|
-
}));
|
|
81
|
-
await elementUpdated(el);
|
|
82
|
-
|
|
83
|
-
expect(initializeBookSubmenus.callCount).to.equal(1);
|
|
84
|
-
expect(el.bookreader).to.equal(brStub); // sets bookreader
|
|
85
|
-
expect(el.bookReaderLoaded).to.be.true; // notes bookreader is loaded
|
|
86
|
-
expect(el.bookReaderCannotLoad).to.be.false;
|
|
87
|
-
expect(el.fullscreenMgr).to.an.instanceof(BRFullscreenMgr);
|
|
88
|
-
expect(el.brResizeObserver).to.an.instanceof(window.ResizeObserver);
|
|
89
|
-
expect(setTimeoutSpy.callCount).to.equal(1); // resizes at end
|
|
112
|
+
it('creates an item image from metadata', async () => {
|
|
113
|
+
const el = fixtureSync(container());
|
|
114
|
+
el.item = {
|
|
115
|
+
metadata: { identifier: 'foo' },
|
|
116
|
+
};
|
|
117
|
+
await elementUpdated(el);
|
|
118
|
+
|
|
119
|
+
const itemImage = fixtureSync(el.itemImage);
|
|
120
|
+
expect(itemImage).to.be.instanceOf(HTMLImageElement);
|
|
121
|
+
expect(itemImage.getAttribute('class')).to.equal('cover-img');
|
|
122
|
+
expect(itemImage.getAttribute('src')).to.equal('https://https://foo.archive.org/services/img/foo');
|
|
123
|
+
});
|
|
90
124
|
});
|
|
125
|
+
describe('Menu/Layer Provider', () => {
|
|
126
|
+
describe('Connecting with a provider:', () => {
|
|
127
|
+
// loads Providers with base shared resources
|
|
128
|
+
it('We load 3 Sub Menus by default', async() => {
|
|
129
|
+
const el = fixtureSync(container());
|
|
130
|
+
const $brContainer = document.createElement('div');
|
|
131
|
+
const brStub = {
|
|
132
|
+
resize: sinon.fake(),
|
|
133
|
+
currentIndex: sinon.fake(),
|
|
134
|
+
jumpToIndex: sinon.fake(),
|
|
135
|
+
options: {},
|
|
136
|
+
refs: {
|
|
137
|
+
$brContainer
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
el.bookreader = brStub;
|
|
141
|
+
await el.elementUpdated;
|
|
142
|
+
|
|
143
|
+
el.initializeBookSubmenus();
|
|
144
|
+
await el.elementUpdated;
|
|
145
|
+
const defaultMenus = Object.keys(el.menuProviders);
|
|
146
|
+
expect(defaultMenus).to.contain('downloads');
|
|
147
|
+
expect(el.menuProviders.downloads).to.be.instanceOf(DownloadsProvider);
|
|
91
148
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const brStub = {
|
|
95
|
-
resize: sinon.fake(),
|
|
96
|
-
currentIndex: sinon.fake(),
|
|
97
|
-
jumpToIndex: sinon.fake(),
|
|
98
|
-
options: { enableMultipleBooks: true },
|
|
99
|
-
};
|
|
149
|
+
expect(defaultMenus).to.contain('share');
|
|
150
|
+
expect(el.menuProviders.share).to.be.instanceOf(SharingProvider);
|
|
100
151
|
|
|
101
|
-
|
|
102
|
-
|
|
152
|
+
expect(defaultMenus).to.contain('visualAdjustments');
|
|
153
|
+
expect(el.menuProviders.visualAdjustments).to.be.instanceOf(VisualAdjustmentsProvider);
|
|
154
|
+
});
|
|
155
|
+
describe('Loading Sub Menus By Plugin Flags', async() => {
|
|
156
|
+
it('Search: uses `enableSearch` flag', async() => {
|
|
157
|
+
const el = fixtureSync(container());
|
|
158
|
+
const $brContainer = document.createElement('div');
|
|
159
|
+
const brStub = {
|
|
160
|
+
resize: sinon.fake(),
|
|
161
|
+
currentIndex: sinon.fake(),
|
|
162
|
+
jumpToIndex: sinon.fake(),
|
|
163
|
+
options: { enableSearch: true },
|
|
164
|
+
refs: {
|
|
165
|
+
$brContainer
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
el.bookreader = brStub;
|
|
169
|
+
await el.elementUpdated;
|
|
103
170
|
|
|
104
|
-
|
|
105
|
-
|
|
171
|
+
el.initializeBookSubmenus();
|
|
172
|
+
await el.elementUpdated;
|
|
106
173
|
|
|
107
|
-
|
|
174
|
+
expect(el.menuProviders.search).to.exist;
|
|
175
|
+
expect(el.menuProviders.search).to.be.instanceOf(SearchProvider);
|
|
108
176
|
|
|
109
|
-
|
|
110
|
-
|
|
177
|
+
// also adds a menu shortcut
|
|
178
|
+
expect(el.menuShortcuts.find(m => m.id === 'search')).to.exist;
|
|
179
|
+
});
|
|
180
|
+
it('Volumes/Multiple Books: uses `enableMultipleBooks` flag', async() => {
|
|
181
|
+
const el = fixtureSync(container());
|
|
182
|
+
const $brContainer = document.createElement('div');
|
|
183
|
+
const brStub = {
|
|
184
|
+
resize: sinon.fake(),
|
|
185
|
+
currentIndex: sinon.fake(),
|
|
186
|
+
jumpToIndex: sinon.fake(),
|
|
187
|
+
options: {
|
|
188
|
+
enableMultipleBooks: true,
|
|
189
|
+
multipleBooksList: {
|
|
190
|
+
by_subprefix: {
|
|
191
|
+
fooSubprefix: 'beep'
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
refs: {
|
|
196
|
+
$brContainer
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
el.bookreader = brStub;
|
|
200
|
+
await el.elementUpdated;
|
|
111
201
|
|
|
112
|
-
|
|
113
|
-
|
|
202
|
+
el.initializeBookSubmenus();
|
|
203
|
+
await el.elementUpdated;
|
|
114
204
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
205
|
+
expect(el.menuProviders.volumes).to.exist;
|
|
206
|
+
expect(el.menuProviders.volumes).to.be.instanceOf(VolumesProvider);
|
|
207
|
+
|
|
208
|
+
// also adds a menu shortcut
|
|
209
|
+
expect(el.menuShortcuts.find(m => m.id === 'volumes')).to.be.exist;
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
it('keeps track of base shared resources for providers in: `baseProviderConfig`', () => {
|
|
213
|
+
const el = fixtureSync(container());
|
|
214
|
+
const baseConfigKeys = Object.keys(el.baseProviderConfig);
|
|
215
|
+
expect(baseConfigKeys).to.contain('baseHost');
|
|
216
|
+
expect(baseConfigKeys).to.contain('modal');
|
|
217
|
+
expect(baseConfigKeys).to.contain('sharedObserver');
|
|
218
|
+
expect(baseConfigKeys).to.contain('bookreader');
|
|
219
|
+
expect(baseConfigKeys).to.contain('item');
|
|
220
|
+
expect(baseConfigKeys).to.contain('signedIn');
|
|
221
|
+
expect(baseConfigKeys).to.contain('isAdmin');
|
|
222
|
+
expect(baseConfigKeys).to.contain('onProviderChange');
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('Controlling Menu Side Panel & Shortcuts', () => {
|
|
227
|
+
describe('Side Menu Panels', () => {
|
|
228
|
+
describe('Control which side menu to toggle open by using: `this.updateSideMenu`', () => {
|
|
229
|
+
it('Emits `@updateSideMenu` to signal which menu gets the update', async () => {
|
|
230
|
+
const el = fixtureSync(container());
|
|
231
|
+
const brStub = {
|
|
232
|
+
resize: sinon.fake(),
|
|
233
|
+
currentIndex: sinon.fake(),
|
|
234
|
+
jumpToIndex: sinon.fake(),
|
|
235
|
+
options: { enableMultipleBooks: true }
|
|
236
|
+
};
|
|
237
|
+
el.bookreader = brStub;
|
|
238
|
+
await elementUpdated(el);
|
|
239
|
+
|
|
240
|
+
let initEventFired = false;
|
|
241
|
+
let eventDetails = {};
|
|
242
|
+
el.addEventListener('updateSideMenu', (e) => {
|
|
243
|
+
eventDetails = e.detail;
|
|
244
|
+
initEventFired = true;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
el.updateSideMenu('foo', 'open');
|
|
248
|
+
expect(initEventFired).to.equal(true);
|
|
249
|
+
expect(eventDetails.menuId).to.equal('foo');
|
|
250
|
+
expect(eventDetails.action).to.equal('open');
|
|
251
|
+
});
|
|
252
|
+
it('Will Not Emit `@updateSideMenu` if menu ID is missing', async() => {
|
|
253
|
+
const el = fixtureSync(container());
|
|
254
|
+
const brStub = {
|
|
255
|
+
resize: sinon.fake(),
|
|
256
|
+
currentIndex: sinon.fake(),
|
|
257
|
+
jumpToIndex: sinon.fake(),
|
|
258
|
+
options: { enableMultipleBooks: true }
|
|
259
|
+
};
|
|
260
|
+
el.bookreader = brStub;
|
|
261
|
+
await elementUpdated(el);
|
|
262
|
+
|
|
263
|
+
let initEventFired = false;
|
|
264
|
+
el.addEventListener('updateSideMenu', (e) => {
|
|
265
|
+
initEventFired = true;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
el.updateSideMenu('', 'open');
|
|
269
|
+
expect(initEventFired).to.equal(false);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('Shortcuts', () => {
|
|
275
|
+
it('has specific order of menu shortcuts to show', () => {
|
|
276
|
+
const el = fixtureSync(container());
|
|
277
|
+
expect(el.shortcutOrder[0]).to.equal('fullscreen');
|
|
278
|
+
expect(el.shortcutOrder[1]).to.equal('volumes');
|
|
279
|
+
expect(el.shortcutOrder[2]).to.equal('search');
|
|
280
|
+
expect(el.shortcutOrder[3]).to.equal('bookmarks');
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('Behaviors for specific menus', () => {
|
|
285
|
+
describe('Search menu - ref: plugin.search.js', () => {
|
|
286
|
+
it('Event: listens for `BookReader:ToggleSearchMenu to open search side panel', async () => {
|
|
287
|
+
const el = fixtureSync(container());
|
|
288
|
+
const brStub = {
|
|
289
|
+
resize: sinon.fake(),
|
|
290
|
+
currentIndex: sinon.fake(),
|
|
291
|
+
jumpToIndex: sinon.fake(),
|
|
292
|
+
options: { enableMultipleBooks: true }
|
|
293
|
+
};
|
|
294
|
+
el.bookreader = brStub;
|
|
295
|
+
await elementUpdated(el);
|
|
296
|
+
|
|
297
|
+
let sidePanelConfig = {};
|
|
298
|
+
el.addEventListener('updateSideMenu', (e) => {
|
|
299
|
+
console.log();
|
|
300
|
+
sidePanelConfig = e.detail;
|
|
301
|
+
});
|
|
302
|
+
const toggleSearchMenuEvent = new Event('BookReader:ToggleSearchMenu');
|
|
303
|
+
window.dispatchEvent(toggleSearchMenuEvent);
|
|
304
|
+
|
|
305
|
+
await elementUpdated(el);
|
|
306
|
+
expect(sidePanelConfig.menuId).to.equal('search');
|
|
307
|
+
expect(sidePanelConfig.action).to.equal('toggle');
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
});
|
|
134
312
|
});
|
|
135
313
|
|
|
136
|
-
describe(
|
|
137
|
-
it('
|
|
314
|
+
describe('Resizing',() => {
|
|
315
|
+
it('keeps track of `brWidth` and `brHeight`', async () => {
|
|
138
316
|
const el = fixtureSync(container());
|
|
139
317
|
const brStub = {
|
|
140
318
|
resize: sinon.fake(),
|
|
319
|
+
};
|
|
320
|
+
el.bookreader = brStub;
|
|
321
|
+
await elementUpdated(el);
|
|
322
|
+
expect(el.brWidth).to.equal(0);
|
|
323
|
+
expect(el.brHeight).to.equal(0);
|
|
324
|
+
|
|
325
|
+
const mockResizeEvent = {
|
|
326
|
+
contentRect: {
|
|
327
|
+
height: 500,
|
|
328
|
+
width: 900
|
|
329
|
+
},
|
|
330
|
+
target: el.mainBRContainer
|
|
331
|
+
};
|
|
332
|
+
el.handleResize(mockResizeEvent);
|
|
333
|
+
|
|
334
|
+
await elementUpdated(el);
|
|
335
|
+
await promise0();
|
|
336
|
+
|
|
337
|
+
expect(el.brHeight).to.equal(500);
|
|
338
|
+
expect(el.brWidth).to.equal(900);
|
|
339
|
+
});
|
|
340
|
+
it('resizes if height/width changes && is not animating', async () => {
|
|
341
|
+
const el = fixtureSync(container());
|
|
342
|
+
const brStub = {
|
|
343
|
+
animating: false,
|
|
344
|
+
resize: sinon.fake(),
|
|
345
|
+
};
|
|
346
|
+
el.bookreader = brStub;
|
|
347
|
+
await elementUpdated(el);
|
|
348
|
+
expect(el.brWidth).to.equal(0);
|
|
349
|
+
expect(el.brHeight).to.equal(0);
|
|
350
|
+
|
|
351
|
+
const mockResizeEvent = {
|
|
352
|
+
contentRect: {
|
|
353
|
+
height: 500,
|
|
354
|
+
width: 900
|
|
355
|
+
},
|
|
356
|
+
target: el.mainBRContainer
|
|
357
|
+
};
|
|
358
|
+
el.handleResize(mockResizeEvent);
|
|
359
|
+
|
|
360
|
+
await elementUpdated(el);
|
|
361
|
+
await promise0();
|
|
362
|
+
|
|
363
|
+
expect(brStub.resize.callCount).to.equal(1);
|
|
364
|
+
});
|
|
365
|
+
it('does not resize bookreader if animating', async () => {
|
|
366
|
+
const el = fixtureSync(container());
|
|
367
|
+
const brStub = {
|
|
368
|
+
animating: true, // <-- testing for this
|
|
369
|
+
resize: sinon.fake(),
|
|
141
370
|
currentIndex: sinon.fake(),
|
|
142
371
|
jumpToIndex: sinon.fake(),
|
|
143
372
|
options: { enableMultipleBooks: true }
|
|
144
373
|
};
|
|
374
|
+
|
|
145
375
|
el.bookreader = brStub;
|
|
146
376
|
await elementUpdated(el);
|
|
147
377
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
el.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
378
|
+
expect(el.bookreader.resize.callCount).to.equal(0);
|
|
379
|
+
expect(el.bookreader.currentIndex.callCount).to.equal(0);
|
|
380
|
+
expect(el.bookreader.jumpToIndex.callCount).to.equal(0);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
describe('Fullscreen Management', () => {
|
|
385
|
+
it('needs option: `enableFSLogoShortcut` to use FS logo', async () => {
|
|
386
|
+
const el = fixtureSync(container());
|
|
387
|
+
const brStub = {
|
|
388
|
+
isFullscreen: () => true,
|
|
389
|
+
options: {
|
|
390
|
+
enableFSLogoShortcut: false,
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
el.bookreader = brStub;
|
|
395
|
+
el.emitMenuShortcutsUpdated = sinon.fake();
|
|
396
|
+
await elementUpdated(el);
|
|
397
|
+
|
|
398
|
+
el.manageFullScreenBehavior();
|
|
399
|
+
await elementUpdated(el);
|
|
400
|
+
expect(el.menuShortcuts.length).to.equal(0);
|
|
401
|
+
});
|
|
402
|
+
it('sets fullscreen shortcut when entering Fullscreen', async () => {
|
|
403
|
+
const el = fixtureSync(container());
|
|
404
|
+
const brStub = {
|
|
405
|
+
isFullscreen: () => true,
|
|
406
|
+
options: {
|
|
407
|
+
enableFSLogoShortcut: true,
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
el.bookreader = brStub;
|
|
412
|
+
el.emitMenuShortcutsUpdated = sinon.fake();
|
|
413
|
+
await elementUpdated(el);
|
|
414
|
+
|
|
415
|
+
el.manageFullScreenBehavior();
|
|
416
|
+
await elementUpdated(el);
|
|
417
|
+
expect(el.menuShortcuts.length).to.equal(1);
|
|
418
|
+
expect(el.menuShortcuts[0].id).to.equal('fullscreen');
|
|
419
|
+
expect(el.menuShortcuts[0].icon).to.exist;
|
|
420
|
+
expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
|
|
421
|
+
});
|
|
422
|
+
it('clicking Fullscreen shortcut closes fullscreen', async () => {
|
|
423
|
+
const el = fixtureSync(container());
|
|
424
|
+
const brStub = {
|
|
425
|
+
isFullscreen: () => true,
|
|
426
|
+
options: {
|
|
427
|
+
enableFSLogoShortcut: true,
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
el.bookreader = brStub;
|
|
432
|
+
el.emitMenuShortcutsUpdated = sinon.fake();
|
|
433
|
+
el.closeFullscreen = sinon.fake();
|
|
434
|
+
await elementUpdated(el);
|
|
435
|
+
|
|
436
|
+
el.manageFullScreenBehavior();
|
|
437
|
+
await elementUpdated(el);
|
|
438
|
+
|
|
439
|
+
fixtureSync(el.menuShortcuts[0].icon).click();
|
|
440
|
+
await elementUpdated(el);
|
|
154
441
|
|
|
155
|
-
el.
|
|
156
|
-
expect(initEventFired).to.equal(true);
|
|
157
|
-
expect(eventDetails.menuId).to.equal('foo');
|
|
158
|
-
expect(eventDetails.action).to.equal('open');
|
|
442
|
+
expect(el.closeFullscreen.callCount).to.equal(1);
|
|
159
443
|
});
|
|
160
|
-
it('
|
|
444
|
+
it('removes Fullscreen shortcut when leaving fullscreen', async() => {
|
|
161
445
|
const el = fixtureSync(container());
|
|
162
446
|
const brStub = {
|
|
447
|
+
isFullscreen: () => false,
|
|
448
|
+
options: {
|
|
449
|
+
enableFSLogoShortcut: true,
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
el.bookreader = brStub;
|
|
454
|
+
el.emitMenuShortcutsUpdated = sinon.fake();
|
|
455
|
+
await elementUpdated(el);
|
|
456
|
+
|
|
457
|
+
el.manageFullScreenBehavior();
|
|
458
|
+
await elementUpdated(el);
|
|
459
|
+
expect(el.menuShortcuts.length).to.equal(0);
|
|
460
|
+
expect(el.emitMenuShortcutsUpdated.callCount).to.equal(1);
|
|
461
|
+
});
|
|
462
|
+
it('Event: Listens for `BookReader:FullscreenToggled', async() => {
|
|
463
|
+
const el = fixtureSync(container());
|
|
464
|
+
const brStub = {
|
|
465
|
+
isFullscreen: () => true,
|
|
163
466
|
resize: sinon.fake(),
|
|
164
467
|
currentIndex: sinon.fake(),
|
|
165
468
|
jumpToIndex: sinon.fake(),
|
|
166
|
-
options: {
|
|
469
|
+
options: {
|
|
470
|
+
enableFSLogoShortcut: true,
|
|
471
|
+
}
|
|
167
472
|
};
|
|
168
473
|
el.bookreader = brStub;
|
|
474
|
+
el.manageFullScreenBehavior = sinon.fake();
|
|
169
475
|
await elementUpdated(el);
|
|
170
476
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
477
|
+
window.dispatchEvent(new CustomEvent('BookReader:fullscreenToggled', {
|
|
478
|
+
detail: { props: brStub }
|
|
479
|
+
}));
|
|
480
|
+
await elementUpdated(el);
|
|
175
481
|
|
|
176
|
-
el.
|
|
177
|
-
expect(initEventFired).to.equal(false);
|
|
482
|
+
expect(el.manageFullScreenBehavior.callCount).to.equal(1);
|
|
178
483
|
});
|
|
179
484
|
});
|
|
180
485
|
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
html,
|
|
3
|
+
fixtureSync,
|
|
4
|
+
expect,
|
|
5
|
+
fixtureCleanup,
|
|
6
|
+
} from '@open-wc/testing';
|
|
7
|
+
import '../../../../src/BookNavigator/bookmarks/bookmark-button.js';
|
|
8
|
+
import sinon from 'sinon';
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
sinon.restore();
|
|
12
|
+
fixtureCleanup();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('<bookmark-button>', () => {
|
|
16
|
+
it('sets default properties', async () => {
|
|
17
|
+
const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
|
|
18
|
+
|
|
19
|
+
expect(el.side).to.be.undefined;
|
|
20
|
+
expect(el.state).to.equal('hollow');
|
|
21
|
+
});
|
|
22
|
+
it('Event: fires `@bookmarkButtonClicked on click', async () => {
|
|
23
|
+
const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
|
|
24
|
+
let buttonClicked = false;
|
|
25
|
+
el.addEventListener('bookmarkButtonClicked', () => { buttonClicked = true; });
|
|
26
|
+
const eventStub = { preventDefault: sinon.fake()};
|
|
27
|
+
el.handleClick(eventStub);
|
|
28
|
+
await el.updateComplete;
|
|
29
|
+
|
|
30
|
+
expect(buttonClicked).to.be.true;
|
|
31
|
+
expect(eventStub.preventDefault.callCount).to.equal(1);
|
|
32
|
+
});
|
|
33
|
+
it('Title: Toggles title between `Add/Remove bookmark`', async () => {
|
|
34
|
+
const el = fixtureSync(html`<bookmark-button></bookmark-button>`);
|
|
35
|
+
expect(el.title).to.equal('Add bookmark');
|
|
36
|
+
expect(el.state).to.equal('hollow');
|
|
37
|
+
|
|
38
|
+
el.state = 'filled';
|
|
39
|
+
await el.updateComplete;
|
|
40
|
+
|
|
41
|
+
expect(el.title).to.equal('Remove bookmark');
|
|
42
|
+
expect(el.state).to.not.equal('hollow');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect } from '@open-wc/testing';
|
|
1
|
+
import { expect, fixtureCleanup, fixtureSync } from '@open-wc/testing';
|
|
2
2
|
import sinon from 'sinon';
|
|
3
3
|
import DownloadsProvider from '../../../../src/BookNavigator/downloads/downloads-provider';
|
|
4
4
|
|
|
@@ -25,6 +25,7 @@ const downloads = [
|
|
|
25
25
|
|
|
26
26
|
afterEach(() => {
|
|
27
27
|
sinon.restore();
|
|
28
|
+
fixtureCleanup();
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
describe('Downloads Provider', () => {
|
|
@@ -34,6 +35,7 @@ describe('Downloads Provider', () => {
|
|
|
34
35
|
|
|
35
36
|
expect(provider.id).to.equal('downloads');
|
|
36
37
|
expect(provider.icon).to.exist;
|
|
38
|
+
expect(fixtureSync(provider.icon).tagName).to.equal('IA-ICON-DL');
|
|
37
39
|
expect(provider.label).to.equal('Downloadable files');
|
|
38
40
|
expect(provider.menuDetails).to.exist;
|
|
39
41
|
expect(provider.component).to.exist;
|
|
@@ -49,8 +51,9 @@ describe('Downloads Provider', () => {
|
|
|
49
51
|
});
|
|
50
52
|
|
|
51
53
|
it('render view if book is protected', () => {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
+
const provider = new DownloadsProvider({
|
|
55
|
+
bookreader: { options: { isProtected: true } }
|
|
56
|
+
});
|
|
54
57
|
|
|
55
58
|
expect(provider.isBookProtected).to.equal(true);
|
|
56
59
|
|