@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.
- package/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +72 -10
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +241 -140
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -20
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1519 -0
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +17 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/pause.svg +1 -1
- package/BookReader/icons/playback-speed.svg +1 -1
- package/BookReader/icons/read-aloud.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/images/BRicons.svg +2 -2
- package/BookReader/images/books_graphic.svg +1 -1
- package/BookReader/images/icon_book.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_speaker.svg +1 -1
- package/BookReader/images/icon_speaker_open.svg +1 -1
- package/BookReader/images/marker_chap-off.svg +1 -1
- package/BookReader/images/marker_chap-on.svg +1 -1
- package/BookReader/images/marker_srch-on.svg +1 -1
- package/BookReader/jquery-3.js +2 -0
- package/BookReader/jquery-3.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +1 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.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.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +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/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +14 -1
- package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
- package/BookReaderDemo/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +147 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- package/BookReaderDemo/demo-autoplay.html +2 -1
- package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +2 -1
- package/BookReaderDemo/demo-fullscreen.html +2 -1
- package/BookReaderDemo/demo-iiif.html +2 -1
- package/BookReaderDemo/demo-internetarchive.html +84 -17
- package/BookReaderDemo/demo-multiple.html +2 -1
- package/BookReaderDemo/demo-preview-pages.html +2 -1
- package/BookReaderDemo/demo-simple.html +2 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +2 -1
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +2 -1
- package/BookReaderDemo/immersion-mode.html +2 -1
- package/BookReaderDemo/toggle_controls.html +2 -1
- package/BookReaderDemo/view_mode.html +2 -1
- package/BookReaderDemo/viewmode-cycle.html +2 -3
- package/CHANGELOG.md +244 -0
- package/README.md +14 -1
- package/babel.config.js +19 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/netlify.toml +5 -0
- package/package.json +70 -59
- package/renovate.json +52 -0
- package/scripts/preversion.js +4 -1
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +9 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/src/BookNavigator/assets/icon_volumes.js +11 -0
- package/src/BookNavigator/book-navigator.js +585 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +36 -21
- package/src/BookNavigator/downloads/downloads.js +41 -25
- package/src/BookNavigator/search/search-provider.js +80 -28
- package/src/BookNavigator/search/search-results.js +34 -25
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
- package/src/BookNavigator/volumes/volumes-provider.js +111 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/BookModel.js +59 -30
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +56 -351
- package/src/BookReader/Mode1UpLit.js +391 -0
- package/src/BookReader/Mode2Up.js +73 -1318
- package/src/BookReader/Mode2UpLit.js +781 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +211 -0
- package/src/BookReader/ModeThumb.js +17 -11
- package/src/BookReader/Navbar/Navbar.js +10 -36
- package/src/BookReader/PageContainer.js +69 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +10 -37
- package/src/BookReader/events.js +2 -0
- package/src/BookReader/options.js +24 -2
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +108 -13
- package/src/BookReader.js +481 -828
- package/src/assets/icons/close-circle-dark.svg +1 -0
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/_BRBookmarks.scss +1 -1
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +33 -0
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +147 -40
- package/src/css/_BRsearch.scss +25 -11
- package/src/css/_TextSelection.scss +16 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +17 -5
- package/src/css/_icons.scss +7 -1
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.archive_analytics.js +3 -3
- package/src/plugins/plugin.autoplay.js +4 -9
- package/src/plugins/plugin.chapters.js +28 -35
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +32 -41
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +179 -103
- package/src/plugins/search/view.js +59 -44
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +13 -14
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +87 -71
- package/src/plugins/tts/plugin.tts.js +94 -125
- package/src/plugins/tts/utils.js +0 -25
- package/src/plugins/url/UrlPlugin.js +193 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
- package/src/util/docCookies.js +21 -2
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +7 -7
- package/tests/e2e/helpers/base.js +28 -23
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +14 -13
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/helpers/rightToLeft.js +4 -10
- package/tests/e2e/models/Navigation.js +13 -4
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +40 -33
- package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
- package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
- package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
- package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
- package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
- package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +104 -60
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
- package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +59 -14
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
- package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
- package/tests/jest/BookReader/Mode2Up.test.js +98 -0
- package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
- package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +175 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +217 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
- package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +10 -11
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +57 -47
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +35 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
- package/tests/jest/setup.js +3 -0
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/jest/util/docCookies.test.js +24 -0
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/webpack.config.js +11 -5
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/jquery-1.10.1.js +0 -2
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/karma.conf.js +0 -23
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -438
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookNavigator/search/a-search-result.js +0 -55
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/Mode2Up.test.js +0 -247
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/e2e/ia-production/ia-prod-base.js +0 -17
- package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
- package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,167 @@
|
|
1
|
+
import { fixtureCleanup, fixtureSync } from '@open-wc/testing-helpers';
|
2
|
+
import sinon from 'sinon';
|
3
|
+
import searchProvider from '@/src/BookNavigator/search/search-provider';
|
4
|
+
|
5
|
+
afterEach(() => {
|
6
|
+
sinon.restore();
|
7
|
+
fixtureCleanup();
|
8
|
+
});
|
9
|
+
|
10
|
+
describe('Search Provider', () => {
|
11
|
+
describe('constructor', () => {
|
12
|
+
const provider = new searchProvider({
|
13
|
+
onProviderChange: sinon.fake(),
|
14
|
+
bookreader: {}
|
15
|
+
});
|
16
|
+
|
17
|
+
expect(provider.bookreader).toBeDefined();
|
18
|
+
expect(provider.onProviderChange).toBeDefined();
|
19
|
+
expect(provider.id).toEqual('search');
|
20
|
+
expect(provider.icon).toBeDefined();
|
21
|
+
expect(fixtureSync(provider.icon).tagName).toEqual('IA-ICON-SEARCH');
|
22
|
+
expect(provider.label).toEqual('Search inside');
|
23
|
+
expect(provider.menuDetails).toBeDefined();
|
24
|
+
expect(provider.component).toBeDefined();
|
25
|
+
});
|
26
|
+
describe('Search request life cycles', () => {
|
27
|
+
test('Event: catches `BookReader:SearchStarted`', async() => {
|
28
|
+
const provider = new searchProvider({
|
29
|
+
onProviderChange: sinon.fake(),
|
30
|
+
bookreader: {}
|
31
|
+
});
|
32
|
+
sinon.spy(provider, 'updateMenu');
|
33
|
+
window.dispatchEvent(new CustomEvent('BookReader:SearchStarted', { detail: { props: { term: 'foo' }}}));
|
34
|
+
expect(provider.updateMenu.callCount).toEqual(1);
|
35
|
+
});
|
36
|
+
test('Event: catches `BookReader:SearchCallback`', async() => {
|
37
|
+
const provider = new searchProvider({
|
38
|
+
onProviderChange: sinon.fake(),
|
39
|
+
bookreader: {}
|
40
|
+
});
|
41
|
+
sinon.spy(provider, 'updateMenu');
|
42
|
+
const brStub = {};
|
43
|
+
window.dispatchEvent(new CustomEvent('BookReader:SearchCallback', { detail: { props: { instance: brStub, results: { matches: []} }}}));
|
44
|
+
expect(provider.updateMenu.callCount).toEqual(1);
|
45
|
+
expect(provider.bookreader).toEqual(brStub);
|
46
|
+
});
|
47
|
+
test('Event: catches `BookReader:SearchCallbackEmpty`', async() => {
|
48
|
+
const provider = new searchProvider({
|
49
|
+
onProviderChange: sinon.fake(),
|
50
|
+
bookreader: {}
|
51
|
+
});
|
52
|
+
sinon.spy(provider, 'onSearchRequestError');
|
53
|
+
sinon.spy(provider, 'updateMenu');
|
54
|
+
const brStub = {};
|
55
|
+
window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackEmpty', { detail: { props: { instance: brStub }}}));
|
56
|
+
expect(provider.onSearchRequestError.getCall(0).args[1]).toEqual('noResults');
|
57
|
+
expect(provider.updateMenu.callCount).toEqual(1);
|
58
|
+
expect(provider.bookreader).toEqual(brStub);
|
59
|
+
});
|
60
|
+
test('Event: catches `BookReader:SearchCallbackNotIndexed`', async() => {
|
61
|
+
const provider = new searchProvider({
|
62
|
+
onProviderChange: sinon.fake(),
|
63
|
+
bookreader: {}
|
64
|
+
});
|
65
|
+
const brStub = {};
|
66
|
+
sinon.spy(provider, 'onSearchRequestError');
|
67
|
+
sinon.spy(provider, 'updateMenu');
|
68
|
+
window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackNotIndexed', { detail: { props: { instance: brStub }}}));
|
69
|
+
expect(provider.onSearchRequestError.getCall(0).args[1]).toEqual('notIndexed');
|
70
|
+
expect(provider.updateMenu.callCount).toEqual(1);
|
71
|
+
expect(provider.bookreader).toEqual(brStub);
|
72
|
+
});
|
73
|
+
test('Event: catches `BookReader:SearchCallbackError`', async() => {
|
74
|
+
const provider = new searchProvider({
|
75
|
+
onProviderChange: sinon.fake(),
|
76
|
+
bookreader: {}
|
77
|
+
});
|
78
|
+
sinon.spy(provider, 'onSearchRequestError');
|
79
|
+
sinon.spy(provider, 'updateMenu');
|
80
|
+
const brStub = {};
|
81
|
+
window.dispatchEvent(new CustomEvent('BookReader:SearchCallbackError', { detail: { props: { instance: brStub }}}));
|
82
|
+
expect(provider.onSearchRequestError.getCall(0).args[1]).toEqual(undefined);
|
83
|
+
expect(provider.updateMenu.callCount).toEqual(1);
|
84
|
+
expect(provider.bookreader).toEqual(brStub);
|
85
|
+
});
|
86
|
+
test('Event: catches `component@resultSelected` - user clicks result in side panel - & turns page', async() => {
|
87
|
+
const provider = new searchProvider({
|
88
|
+
onProviderChange: sinon.fake(),
|
89
|
+
bookreader: {
|
90
|
+
leafNumToIndex: sinon.fake(),
|
91
|
+
_searchPluginGoToResult: sinon.fake()
|
92
|
+
}
|
93
|
+
});
|
94
|
+
|
95
|
+
const searchResultStub = {
|
96
|
+
match: { par: [{ text: 'foo', page: 3 }] },
|
97
|
+
};
|
98
|
+
fixtureSync(provider.component).dispatchEvent(
|
99
|
+
new CustomEvent('resultSelected',
|
100
|
+
{ detail: searchResultStub })
|
101
|
+
);
|
102
|
+
|
103
|
+
expect(provider.bookreader._searchPluginGoToResult.callCount).toEqual(1);
|
104
|
+
});
|
105
|
+
test('update url when search is cancelled or input cleared', async() => {
|
106
|
+
const urlPluginMock = {
|
107
|
+
pullFromAddressBar: sinon.fake(),
|
108
|
+
removeUrlParam: sinon.fake()
|
109
|
+
};
|
110
|
+
const provider = new searchProvider({
|
111
|
+
onProviderChange: sinon.fake(),
|
112
|
+
bookreader: {
|
113
|
+
leafNumToIndex: sinon.fake(),
|
114
|
+
_searchPluginGoToResult: sinon.fake(),
|
115
|
+
urlPlugin: urlPluginMock
|
116
|
+
}
|
117
|
+
});
|
118
|
+
|
119
|
+
provider.onSearchCanceled();
|
120
|
+
await provider.updateComplete;
|
121
|
+
|
122
|
+
expect(urlPluginMock.pullFromAddressBar.callCount).toEqual(1);
|
123
|
+
expect(urlPluginMock.removeUrlParam.callCount).toEqual(1);
|
124
|
+
|
125
|
+
provider.onSearchCanceled();
|
126
|
+
await provider.updateComplete;
|
127
|
+
|
128
|
+
expect(urlPluginMock.pullFromAddressBar.callCount).toEqual(2);
|
129
|
+
expect(urlPluginMock.removeUrlParam.callCount).toEqual(2);
|
130
|
+
});
|
131
|
+
it('updateSearchInUrl', async () => {
|
132
|
+
let fieldToSet;
|
133
|
+
let valueOfFieldToSet;
|
134
|
+
let setUrlParamCalled = false;
|
135
|
+
const urlPluginMock = {
|
136
|
+
pullFromAddressBar: sinon.fake(),
|
137
|
+
removeUrlParam: sinon.fake(),
|
138
|
+
setUrlParam: (field, val) => {
|
139
|
+
fieldToSet = field;
|
140
|
+
valueOfFieldToSet = val;
|
141
|
+
setUrlParamCalled = true;
|
142
|
+
}
|
143
|
+
};
|
144
|
+
const provider = new searchProvider({
|
145
|
+
onProviderChange: sinon.fake(),
|
146
|
+
bookreader: {
|
147
|
+
leafNumToIndex: sinon.fake(),
|
148
|
+
_searchPluginGoToResult: sinon.fake(),
|
149
|
+
urlPlugin: urlPluginMock,
|
150
|
+
search: sinon.fake()
|
151
|
+
}
|
152
|
+
});
|
153
|
+
|
154
|
+
const searchInitiatedEvent = new CustomEvent('bookSearchInitiated', { detail: { query: 'foobar' } });
|
155
|
+
// set initial seachState with a query
|
156
|
+
provider.onBookSearchInitiated(searchInitiatedEvent);
|
157
|
+
await provider.updateComplete;
|
158
|
+
// checking this fn:
|
159
|
+
provider.updateSearchInUrl();
|
160
|
+
await provider.updateComplete;
|
161
|
+
|
162
|
+
expect(fieldToSet).toEqual('q');
|
163
|
+
expect(valueOfFieldToSet).toEqual('foobar');
|
164
|
+
expect(setUrlParamCalled).toBe(true);
|
165
|
+
});
|
166
|
+
});
|
167
|
+
});
|
@@ -1,24 +1,22 @@
|
|
1
1
|
import {
|
2
2
|
html,
|
3
3
|
fixture,
|
4
|
-
expect,
|
5
4
|
oneEvent,
|
6
|
-
} from '@open-wc/testing';
|
5
|
+
} from '@open-wc/testing-helpers';
|
7
6
|
import sinon from 'sinon';
|
8
|
-
import { IABookSearchResults } from '
|
7
|
+
import { IABookSearchResults } from '@/src/BookNavigator/search/search-results.js';
|
9
8
|
|
10
9
|
const container = (results = [], query = '') => (
|
11
10
|
html`<ia-book-search-results .results=${results} .query=${query}></ia-book-search-results>`
|
12
11
|
);
|
13
12
|
|
14
|
-
console.log("ia-book-search-results-test")
|
15
|
-
|
16
13
|
const searchQuery = 'Bristol';
|
17
14
|
|
18
15
|
const results = [{
|
19
16
|
text: `In the drawing of caricatures and cartoons\u2014or any other com' mercial art, for that matter\u2014the artist should know something about the processes of reproduction for that particular form of art work. For pen and ink work the engraving is made on a sine printing plate. It is not necessary, however, to know all about these processes of reproduction. The artist should know that all work intended for line rqproducttons should be made on white paper or {{{${searchQuery}}}} Board with black drawing ink. The drawing to be reproduced is photographed on a chemically treated sine plate, which is then treated with acid. This acid eats away the surface of the sine, except the photographed' lines, which are left in relief, somewhat like printing type. Colored inks do not photograph well; neither does black ink on colored paper.`,
|
20
17
|
cover: '//placehold.it/30x44',
|
21
18
|
title: 'Book title',
|
19
|
+
displayPageNumber: 'Page 24',
|
22
20
|
par: [{
|
23
21
|
boxes: [{
|
24
22
|
r: 2672, b: 792, t: 689, page: 24, l: 2424,
|
@@ -33,6 +31,7 @@ const results = [{
|
|
33
31
|
}],
|
34
32
|
}, {
|
35
33
|
text: `Drawings intended for sale should be made on a good grade of {{{${searchQuery}}}} Board, and a margin left all the way around the drawings. They should be mailed flat, and'require first class postage. Enclose postage for the return of the drawings. Only send good drawings of a reason- able quantity. Enclose a neat and terse letter to the one you are sending the drawings to, written with pen and ink or typewriter if possible, on`,
|
34
|
+
displayPageNumber: 'Page 86',
|
36
35
|
par: [{
|
37
36
|
boxes: [{
|
38
37
|
r: 698, b: 4460, t: 4324, page: 86, l: 450,
|
@@ -47,69 +46,101 @@ const results = [{
|
|
47
46
|
}],
|
48
47
|
}];
|
49
48
|
|
49
|
+
const resultWithScript = [{
|
50
|
+
text: `foo bar <script>const msg = 'test' + ' failure'; document.write(msg);</script> {{{${searchQuery}}}} baz`,
|
51
|
+
cover: '//placehold.it/30x44',
|
52
|
+
title: 'Book title',
|
53
|
+
displayPageNumber: 'Page 24',
|
54
|
+
par: [{
|
55
|
+
boxes: [{
|
56
|
+
r: 2672, b: 792, t: 689, page: 24, l: 2424,
|
57
|
+
}],
|
58
|
+
b: 1371,
|
59
|
+
t: 689,
|
60
|
+
page_width: 3658,
|
61
|
+
r: 3192,
|
62
|
+
l: 428,
|
63
|
+
page_height: 5357,
|
64
|
+
page: 24,
|
65
|
+
}],
|
66
|
+
}];
|
67
|
+
|
50
68
|
describe('<ia-book-search-results>', () => {
|
51
69
|
afterEach(() => {
|
52
70
|
sinon.restore();
|
53
71
|
});
|
54
72
|
|
55
|
-
|
73
|
+
test('sets default properties', async () => {
|
56
74
|
const query = 'bristol';
|
57
75
|
const el = await fixture(container(results, query));
|
58
76
|
|
59
|
-
expect(el.results).
|
60
|
-
expect(el.query).
|
77
|
+
expect(el.results).toEqual(results);
|
78
|
+
expect(el.query).toEqual(query);
|
61
79
|
});
|
62
80
|
|
63
|
-
|
81
|
+
test('sets results when passed in via event object', async () => {
|
64
82
|
const el = await fixture(container());
|
65
83
|
|
66
84
|
el.setResults({ detail: { results } });
|
67
|
-
expect(el.results).
|
85
|
+
expect(el.results).toEqual(results);
|
68
86
|
});
|
69
87
|
|
70
|
-
|
88
|
+
test('listens for a custom search callback event on the document', async () => {
|
71
89
|
IABookSearchResults.prototype.setResults = sinon.fake();
|
72
90
|
const el = await fixture(container());
|
73
91
|
const event = new Event('BookReader:SearchCallback');
|
74
92
|
|
75
93
|
event.detail = { results };
|
76
94
|
document.dispatchEvent(event);
|
77
|
-
expect(el.setResults.callCount).
|
78
|
-
expect(el.setResults.firstArg).
|
95
|
+
expect(el.setResults.callCount).toEqual(1);
|
96
|
+
expect(el.setResults.firstArg).toEqual(event);
|
79
97
|
});
|
80
98
|
|
81
|
-
|
99
|
+
test('renders results that contain the book title', async () => {
|
82
100
|
sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
|
83
101
|
const el = await fixture(container(results));
|
84
102
|
|
85
|
-
expect(el.innerHTML).
|
103
|
+
expect(el.innerHTML).toContain(`${results[0].title}`);
|
86
104
|
});
|
87
105
|
|
88
|
-
|
106
|
+
test('renders results that contain a highlighted match', async () => {
|
89
107
|
sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
|
90
108
|
const el = await fixture(container(results));
|
91
109
|
|
92
|
-
|
110
|
+
// Lit inserts HTML comments that inhibit searching for exact innerHTML matches.
|
111
|
+
// So query the DOM for the match instead.
|
112
|
+
const match = el.querySelector('mark');
|
113
|
+
expect(match?.textContent).toEqual(searchQuery);
|
93
114
|
});
|
94
115
|
|
95
|
-
|
116
|
+
test('renders results that contain sanitized HTML tags', async () => {
|
117
|
+
sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
|
118
|
+
// A result whose text contains a <script> tag that will insert 'test failure' into the element if not sanitized
|
119
|
+
const el = await fixture(container(resultWithScript));
|
120
|
+
|
121
|
+
const match = el.querySelector('mark');
|
122
|
+
expect(match?.textContent).toEqual(searchQuery);
|
123
|
+
expect(el.innerHTML).not.toContain('test failure');
|
124
|
+
});
|
125
|
+
|
126
|
+
test('renders results that contain an optional cover image', async () => {
|
96
127
|
sinon.replace(IABookSearchResults.prototype, 'createRenderRoot', function createRenderRoot() { return this; });
|
97
128
|
const el = await fixture(container(results));
|
98
129
|
|
99
|
-
expect(el.innerHTML).
|
130
|
+
expect(el.innerHTML).toContain(`<img src="${results[0].cover}">`);
|
100
131
|
});
|
101
132
|
|
102
|
-
|
133
|
+
test('sets a query prop when search input receives input', async () => {
|
103
134
|
const el = await fixture(container(results));
|
104
135
|
const searchInput = el.shadowRoot.querySelector('[name="query"]');
|
105
136
|
|
106
137
|
searchInput.value = searchQuery;
|
107
138
|
searchInput.dispatchEvent(new Event('keyup'));
|
108
139
|
|
109
|
-
expect(el.query).
|
140
|
+
expect(el.query).toEqual(searchQuery);
|
110
141
|
});
|
111
142
|
|
112
|
-
|
143
|
+
test('emits a custom event when search form submitted when input is populated', async () => {
|
113
144
|
const el = await fixture(container(results));
|
114
145
|
|
115
146
|
setTimeout(() => {
|
@@ -119,122 +150,135 @@ describe('<ia-book-search-results>', () => {
|
|
119
150
|
});
|
120
151
|
const response = await oneEvent(el, 'bookSearchInitiated');
|
121
152
|
|
122
|
-
expect(response).
|
153
|
+
expect(response).toBeDefined();
|
123
154
|
});
|
124
155
|
|
125
|
-
|
156
|
+
test('uses a singular noun when one result given', async () => {
|
126
157
|
const el = await fixture(container([results[0]]));
|
127
158
|
const resultsCount = await fixture(el.resultsCount);
|
128
159
|
|
129
|
-
expect(resultsCount.innerHTML).
|
160
|
+
expect(resultsCount.innerHTML).toContain('1 result');
|
130
161
|
});
|
131
162
|
|
132
|
-
|
163
|
+
test('can render header with active options count', async () => {
|
133
164
|
const el = await fixture(container(results));
|
134
165
|
el.renderHeader = true;
|
135
166
|
|
136
167
|
await el.updateComplete;
|
137
168
|
|
138
|
-
expect(el.shadowRoot.querySelector('header p').
|
169
|
+
expect(el.shadowRoot.querySelector('header p').textContent).toContain('2');
|
139
170
|
});
|
140
171
|
|
141
|
-
|
172
|
+
test('renders search all files checkbox when enabled', async () => {
|
142
173
|
const el = await fixture(container(results));
|
143
174
|
el.renderSearchAllFiles = true;
|
144
175
|
|
145
176
|
await el.updateComplete;
|
146
177
|
|
147
|
-
expect(el.shadowRoot.querySelector('[name="all_files"]')).
|
178
|
+
expect(el.shadowRoot.querySelector('[name="all_files"]')).not.toBeNull();
|
148
179
|
});
|
149
180
|
|
150
|
-
|
181
|
+
test('emits a resultSelected event when a search result is clicked', async () => {
|
151
182
|
const el = await fixture(container(results));
|
152
183
|
|
153
184
|
setTimeout(() => (
|
154
|
-
el.shadowRoot.querySelector('
|
185
|
+
el.shadowRoot.querySelector('li').click()
|
155
186
|
));
|
156
187
|
const response = await oneEvent(el, 'resultSelected');
|
157
188
|
|
158
|
-
expect(response).
|
189
|
+
expect(response).toBeDefined();
|
159
190
|
});
|
160
191
|
|
161
|
-
|
192
|
+
test('emits a closeMenu event when a search result is clicked', async () => {
|
162
193
|
const el = await fixture(container(results));
|
163
194
|
|
164
195
|
setTimeout(() => (
|
165
|
-
el.shadowRoot.querySelector('
|
196
|
+
el.shadowRoot.querySelector('li').click()
|
166
197
|
));
|
167
198
|
const response = await oneEvent(el, 'closeMenu');
|
168
199
|
|
169
|
-
expect(response).
|
200
|
+
expect(response).toBeDefined();
|
170
201
|
});
|
171
202
|
|
172
203
|
describe('Search results placeholders', () => {
|
173
|
-
|
204
|
+
test('renders a loading state when queryInProgress is true', async () => {
|
174
205
|
const el = await fixture(container(results));
|
175
206
|
|
176
207
|
el.queryInProgress = true;
|
177
208
|
await el.updateComplete;
|
178
209
|
|
179
|
-
expect(el.shadowRoot.querySelector('.loading')).
|
210
|
+
expect(el.shadowRoot.querySelector('.loading')).not.toBeNull();
|
180
211
|
});
|
181
|
-
|
212
|
+
test('renders an error message when provided', async () => {
|
182
213
|
const el = await fixture(container([]));
|
183
214
|
const message = 'Sample error message';
|
184
215
|
el.errorMessage = message;
|
185
216
|
await el.updateComplete;
|
186
217
|
|
187
|
-
expect(el.shadowRoot.querySelector('.error-message')).
|
188
|
-
expect(el.shadowRoot.querySelector('.search-cta')).
|
218
|
+
expect(el.shadowRoot.querySelector('.error-message')).toBeDefined();
|
219
|
+
expect(el.shadowRoot.querySelector('.search-cta')).toBeNull();
|
189
220
|
});
|
190
|
-
|
221
|
+
test('displays call to search when no results or search errors are showing', async () => {
|
191
222
|
const el = await fixture(container([]));
|
192
223
|
|
193
|
-
expect(el.shadowRoot.querySelector('.search-cta')).
|
194
|
-
expect(el.shadowRoot.querySelector('.error-message')).
|
195
|
-
expect(el.shadowRoot.querySelector('.results')).
|
224
|
+
expect(el.shadowRoot.querySelector('.search-cta')).toBeDefined();
|
225
|
+
expect(el.shadowRoot.querySelector('.error-message')).toBeNull();
|
226
|
+
expect(el.shadowRoot.querySelector('.results')).toBeNull();
|
196
227
|
});
|
197
228
|
});
|
198
229
|
|
199
|
-
|
230
|
+
test('displays results images when told to', async () => {
|
200
231
|
const el = await fixture(container(results));
|
201
232
|
el.displayResultImages = true;
|
202
233
|
await el.updateComplete;
|
203
234
|
|
204
|
-
expect(el.shadowRoot.querySelector('.results.show-image')).
|
235
|
+
expect(el.shadowRoot.querySelector('.results.show-image')).toBeDefined();
|
205
236
|
});
|
206
237
|
|
207
238
|
describe('search input focus', () => {
|
208
|
-
|
239
|
+
test('will always try to re-focus once the component updates', async () => {
|
209
240
|
const el = await fixture(container(results));
|
210
241
|
el.focusOnInputIfNecessary = sinon.fake();
|
211
242
|
// update any property to fire lifecycle
|
212
243
|
el.results = [];
|
213
244
|
await el.updateComplete;
|
214
245
|
|
215
|
-
expect(el.focusOnInputIfNecessary.callCount).
|
246
|
+
expect(el.focusOnInputIfNecessary.callCount).toEqual(1);
|
216
247
|
});
|
217
|
-
|
248
|
+
test('refocuses on input when results are empty', async () => {
|
218
249
|
const el = await fixture(container(results));
|
219
250
|
el.results = [];
|
220
251
|
await el.updateComplete;
|
221
252
|
|
222
253
|
const searchInputField = el.shadowRoot.querySelector('input[type=\'search\']');
|
223
|
-
expect(searchInputField).
|
254
|
+
expect(searchInputField).toEqual(el.shadowRoot.activeElement);
|
224
255
|
});
|
225
256
|
});
|
226
257
|
|
227
|
-
|
228
|
-
|
258
|
+
test("emits a bookSearchCanceled event when loading state's cancel action clicked", async () => {
|
259
|
+
const el = await fixture(container(results));
|
229
260
|
|
230
|
-
|
231
|
-
|
261
|
+
el.queryInProgress = true;
|
262
|
+
await el.updateComplete;
|
232
263
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
264
|
+
setTimeout(() => (
|
265
|
+
el.shadowRoot.querySelector('button').click()
|
266
|
+
));
|
267
|
+
const response = await oneEvent(el, 'bookSearchCanceled');
|
237
268
|
|
238
|
-
|
239
|
-
|
269
|
+
expect(response).toBeDefined();
|
270
|
+
});
|
271
|
+
it('cancels search when input is cleared', async () => {
|
272
|
+
const el = await fixture(container(results));
|
273
|
+
|
274
|
+
el.cancelSearch = sinon.fake();
|
275
|
+
await el.updateComplete;
|
276
|
+
|
277
|
+
const searchInput = el.shadowRoot.querySelector('[name="query"]');
|
278
|
+
|
279
|
+
searchInput.value = '';
|
280
|
+
searchInput.dispatchEvent(new Event('search'));
|
281
|
+
|
282
|
+
expect(el.cancelSearch.callCount).toEqual(1);
|
283
|
+
});
|
240
284
|
});
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import { fixtureSync } from '@open-wc/testing-helpers';
|
2
|
+
import sinon from 'sinon';
|
3
|
+
import SharingProvider from '@/src/BookNavigator/sharing.js';
|
4
|
+
|
5
|
+
afterEach(() => {
|
6
|
+
sinon.restore();
|
7
|
+
});
|
8
|
+
|
9
|
+
const item = {
|
10
|
+
metadata: {
|
11
|
+
identifier: 'stubby-id',
|
12
|
+
creator: 'mr. big',
|
13
|
+
title: 'Stubby title',
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
const baseHost = 'foo.org';
|
18
|
+
const subPrefix = 'beep-boop_12 4 5';
|
19
|
+
|
20
|
+
describe('Sharing Provider', () => {
|
21
|
+
describe('constructor', () => {
|
22
|
+
const provider = new SharingProvider({
|
23
|
+
item,
|
24
|
+
baseHost,
|
25
|
+
bookreader: {
|
26
|
+
options: { subPrefix }
|
27
|
+
}
|
28
|
+
});
|
29
|
+
|
30
|
+
expect(provider.id).toEqual('share');
|
31
|
+
expect(provider.icon).toBeDefined();
|
32
|
+
expect(provider.label).toEqual('Share this book');
|
33
|
+
expect(fixtureSync(provider.component).tagName).toContain('IA-SHARING-OPTIONS');
|
34
|
+
});
|
35
|
+
|
36
|
+
describe('Handles being a sub file/volume', () => {
|
37
|
+
test('encodes the subprefix if it has one', async () => {
|
38
|
+
const provider = new SharingProvider({
|
39
|
+
item,
|
40
|
+
baseHost,
|
41
|
+
bookreader: {
|
42
|
+
options: { subPrefix }
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
expect(fixtureSync(provider.component).fileSubPrefix).toEqual(subPrefix);
|
47
|
+
});
|
48
|
+
});
|
49
|
+
});
|