@internetarchive/bookreader 5.0.0-4 → 5.0.0-40-a1
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/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +75 -4
- package/.github/workflows/npm-publish.yml +2 -16
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +83 -323
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -0
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1623 -0
- package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
- 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/voice.svg +1 -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/IADemoBr.js +120 -0
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -0
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
- package/BookReaderDemo/demo-fullscreen.html +1 -0
- package/BookReaderDemo/demo-iiif.html +1 -0
- package/BookReaderDemo/demo-internetarchive.html +74 -17
- package/BookReaderDemo/demo-multiple.html +1 -0
- package/BookReaderDemo/demo-preview-pages.html +1 -0
- package/BookReaderDemo/demo-simple.html +1 -0
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +1 -0
- package/BookReaderDemo/immersion-mode.html +1 -0
- package/BookReaderDemo/toggle_controls.html +1 -0
- package/BookReaderDemo/view_mode.html +1 -0
- package/BookReaderDemo/viewmode-cycle.html +1 -2
- package/CHANGELOG.md +166 -0
- package/README.md +14 -1
- package/babel.config.js +18 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +62 -47
- package/renovate.json +43 -0
- 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 +556 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +23 -17
- package/src/BookNavigator/downloads/downloads.js +17 -25
- package/src/BookNavigator/search/a-search-result.js +3 -3
- package/src/BookNavigator/search/search-provider.js +57 -24
- package/src/BookNavigator/search/search-results.js +8 -20
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +51 -351
- package/src/BookReader/Mode1UpLit.js +441 -0
- package/src/BookReader/Mode2Up.js +104 -71
- package/src/BookReader/ModeSmoothZoom.js +179 -0
- package/src/BookReader/ModeThumb.js +16 -8
- package/src/BookReader/Navbar/Navbar.js +2 -31
- package/src/BookReader/PageContainer.js +57 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +7 -7
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +68 -13
- package/src/BookReader.js +375 -289
- 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/BookReader.scss +0 -12
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +19 -24
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +35 -0
- package/src/css/_BRsearch.scss +11 -215
- package/src/css/_TextSelection.scss +14 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +16 -3
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.chapters.js +26 -33
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +26 -39
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +106 -107
- package/src/plugins/search/view.js +50 -163
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +12 -13
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +64 -68
- package/src/plugins/tts/plugin.tts.js +79 -108
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
- 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 +8 -3
- 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/models/Navigation.js +12 -3
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +38 -33
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -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 +88 -0
- package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -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 +136 -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} +20 -4
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
- 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 +24 -25
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
- 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 +1 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/{util → jest/util}/docCookies.test.js +1 -1
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
- package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
- package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
- package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
- package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
- package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
- package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
- package/webpack.config.js +10 -4
- 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.map +0 -1
- 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/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -435
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- 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/utils.test.js +0 -109
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -0,0 +1,149 @@
|
|
1
|
+
import sinon from 'sinon';
|
2
|
+
import { EventTargetSpy } from '../utils.js';
|
3
|
+
import { ModeSmoothZoom } from '@/src/BookReader/ModeSmoothZoom.js';
|
4
|
+
/** @typedef {import('@/src/BookReader/ModeSmoothZoom.js').SmoothZoomable} SmoothZoomable */
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @param {Partial<SmoothZoomable>} overrides
|
8
|
+
* @returns {SmoothZoomable}
|
9
|
+
*/
|
10
|
+
function dummy_mode(overrides = {}) {
|
11
|
+
return {
|
12
|
+
$container: document.createElement('div'),
|
13
|
+
$visibleWorld: document.createElement('div'),
|
14
|
+
scale: 1,
|
15
|
+
htmlDimensionsCacher: {
|
16
|
+
clientWidth: 100,
|
17
|
+
clientHeight: 100,
|
18
|
+
boundingClientRect: { left: 0, top: 0 },
|
19
|
+
},
|
20
|
+
scaleCenter: {x: 0.5, y: 0.5},
|
21
|
+
...overrides
|
22
|
+
};
|
23
|
+
}
|
24
|
+
|
25
|
+
afterEach(() => sinon.restore());
|
26
|
+
|
27
|
+
describe('ModeSmoothZoom', () => {
|
28
|
+
test('preventsDefault on iOS-only gesture events', () => {
|
29
|
+
const mode = dummy_mode();
|
30
|
+
const msz = new ModeSmoothZoom(mode);
|
31
|
+
msz.attach();
|
32
|
+
for (const event_name of ['gesturestart', 'gesturechange', 'gestureend']) {
|
33
|
+
const ev = new Event(event_name, {});
|
34
|
+
const prevDefaultSpy = sinon.spy(ev, 'preventDefault');
|
35
|
+
mode.$container.dispatchEvent(ev);
|
36
|
+
expect(prevDefaultSpy.callCount).toBe(1);
|
37
|
+
}
|
38
|
+
});
|
39
|
+
|
40
|
+
test('pinchCancel alias for pinchEnd', () => {
|
41
|
+
const mode = dummy_mode();
|
42
|
+
const msz = new ModeSmoothZoom(mode);
|
43
|
+
const pinchEndSpy = sinon.spy(msz, '_pinchEnd');
|
44
|
+
msz._pinchStart();
|
45
|
+
msz._pinchCancel();
|
46
|
+
expect(pinchEndSpy.callCount).toBe(1);
|
47
|
+
});
|
48
|
+
|
49
|
+
test('sets will-change', async () => {
|
50
|
+
const mode = dummy_mode();
|
51
|
+
const msz = new ModeSmoothZoom(mode);
|
52
|
+
expect(mode.$visibleWorld.style.willChange).toBeFalsy();
|
53
|
+
msz._pinchStart();
|
54
|
+
expect(mode.$visibleWorld.style.willChange).toBe('transform');
|
55
|
+
await msz._pinchEnd();
|
56
|
+
expect(mode.$visibleWorld.style.willChange).toBe('auto');
|
57
|
+
});
|
58
|
+
|
59
|
+
test('pinch move updates scale', () => {
|
60
|
+
const mode = dummy_mode();
|
61
|
+
const msz = new ModeSmoothZoom(mode);
|
62
|
+
// disable buffering
|
63
|
+
msz.bufferFn = (callback) => callback();
|
64
|
+
msz._pinchStart();
|
65
|
+
expect(mode.scale).toBe(1);
|
66
|
+
msz._pinchMove({ scale: 2, center: { x: 0, y: 0 }});
|
67
|
+
expect(mode.scale).toBe(2);
|
68
|
+
});
|
69
|
+
|
70
|
+
test('updateScaleCenter sets scaleCenter in unitless coordinates', () => {
|
71
|
+
const mode = dummy_mode({
|
72
|
+
htmlDimensionsCacher: {
|
73
|
+
clientWidth: 200,
|
74
|
+
clientHeight: 100,
|
75
|
+
boundingClientRect: {
|
76
|
+
left: 5,
|
77
|
+
top: 50
|
78
|
+
}
|
79
|
+
}
|
80
|
+
});
|
81
|
+
const msz = new ModeSmoothZoom(mode);
|
82
|
+
expect(mode.scaleCenter).toEqual({ x: 0.5, y: 0.5 });
|
83
|
+
msz.updateScaleCenter({ clientX: 85, clientY: 110 });
|
84
|
+
expect(mode.scaleCenter).toEqual({ x: 0.4, y: 0.6 });
|
85
|
+
});
|
86
|
+
|
87
|
+
test('detaches all listeners', () => {
|
88
|
+
const mode = dummy_mode();
|
89
|
+
const msz = new ModeSmoothZoom(mode);
|
90
|
+
const containerEventSpy = EventTargetSpy.wrap(mode.$container);
|
91
|
+
const visibleWorldSpy = EventTargetSpy.wrap(mode.$visibleWorld);
|
92
|
+
const hammerEventSpy = new EventTargetSpy();
|
93
|
+
msz.hammer.on = hammerEventSpy.addEventListener.bind(hammerEventSpy);
|
94
|
+
msz.hammer.off = hammerEventSpy.removeEventListener.bind(hammerEventSpy);
|
95
|
+
|
96
|
+
msz.attach();
|
97
|
+
expect(containerEventSpy._totalListenerCount).toBeGreaterThan(0);
|
98
|
+
expect(hammerEventSpy._totalListenerCount).toBeGreaterThan(0);
|
99
|
+
|
100
|
+
msz.detach();
|
101
|
+
expect(containerEventSpy._totalListenerCount).toBe(0);
|
102
|
+
expect(visibleWorldSpy._totalListenerCount).toBe(0);
|
103
|
+
expect(hammerEventSpy._totalListenerCount).toBe(0);
|
104
|
+
});
|
105
|
+
|
106
|
+
test('attach can be called twice without double attachments', () => {
|
107
|
+
const mode = dummy_mode();
|
108
|
+
const msz = new ModeSmoothZoom(mode);
|
109
|
+
const containerEventSpy = EventTargetSpy.wrap(mode.$container);
|
110
|
+
const visibleWorldSpy = EventTargetSpy.wrap(mode.$visibleWorld);
|
111
|
+
const hammerEventSpy = new EventTargetSpy();
|
112
|
+
msz.hammer.on = hammerEventSpy.addEventListener.bind(hammerEventSpy);
|
113
|
+
msz.hammer.off = hammerEventSpy.removeEventListener.bind(hammerEventSpy);
|
114
|
+
msz.attach();
|
115
|
+
|
116
|
+
const containerListenersCount = containerEventSpy._totalListenerCount;
|
117
|
+
const visibleWorldListenersCount = visibleWorldSpy._totalListenerCount;
|
118
|
+
const hammerListenersCount = hammerEventSpy._totalListenerCount;
|
119
|
+
|
120
|
+
msz.attach();
|
121
|
+
expect(containerEventSpy._totalListenerCount).toBe(containerListenersCount);
|
122
|
+
expect(visibleWorldSpy._totalListenerCount).toBe(visibleWorldListenersCount);
|
123
|
+
expect(hammerEventSpy._totalListenerCount).toBe(hammerListenersCount);
|
124
|
+
});
|
125
|
+
|
126
|
+
describe('_handleCtrlWheel', () => {
|
127
|
+
test('non-ctrl wheel events ignored', () => {
|
128
|
+
const mode = dummy_mode();
|
129
|
+
const msz = new ModeSmoothZoom(mode);
|
130
|
+
expect(mode.scale).toBe(1);
|
131
|
+
const ev = new WheelEvent('wheel', { ctrlKey: false, deltaY: 20 });
|
132
|
+
const preventDefaultSpy = sinon.spy(ev, 'preventDefault');
|
133
|
+
msz._handleCtrlWheel(ev);
|
134
|
+
expect(preventDefaultSpy.callCount).toBe(0);
|
135
|
+
expect(mode.scale).toBe(1);
|
136
|
+
});
|
137
|
+
|
138
|
+
test('ctrl-wheel events update scale', () => {
|
139
|
+
const mode = dummy_mode();
|
140
|
+
const msz = new ModeSmoothZoom(mode);
|
141
|
+
expect(mode.scale).toBe(1);
|
142
|
+
const ev = new WheelEvent('wheel', { ctrlKey: true, deltaY: 20 });
|
143
|
+
const preventDefaultSpy = sinon.spy(ev, 'preventDefault');
|
144
|
+
msz._handleCtrlWheel(ev);
|
145
|
+
expect(preventDefaultSpy.callCount).toBe(1);
|
146
|
+
expect(mode.scale).not.toBe(1);
|
147
|
+
});
|
148
|
+
});
|
149
|
+
});
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
import sinon from 'sinon';
|
3
|
+
import BookReader from '@/src/BookReader.js';
|
4
|
+
/** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
|
5
|
+
|
6
|
+
beforeAll(() => {
|
7
|
+
global.alert = jest.fn();
|
8
|
+
});
|
9
|
+
afterEach(() => {
|
10
|
+
jest.restoreAllMocks();
|
11
|
+
sinon.restore();
|
12
|
+
});
|
13
|
+
|
14
|
+
/** @type {BookReaderOptions['data']} */
|
15
|
+
const SAMPLE_DATA = [
|
16
|
+
[
|
17
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image0.jpg', pageNum: '1' },
|
18
|
+
],
|
19
|
+
[
|
20
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image1.jpg', pageNum: '2' },
|
21
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '3' },
|
22
|
+
],
|
23
|
+
[
|
24
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image3.jpg', pageNum: '4' },
|
25
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image4.jpg', pageNum: '5' },
|
26
|
+
],
|
27
|
+
[
|
28
|
+
{ width: 123, height: 123, uri: 'https://archive.org/image5.jpg', pageNum: '6' },
|
29
|
+
],
|
30
|
+
];
|
31
|
+
|
32
|
+
describe('zoom', () => {
|
33
|
+
const br = new BookReader({ data: SAMPLE_DATA });
|
34
|
+
br.init();
|
35
|
+
|
36
|
+
test('initializes with default columns', () => {
|
37
|
+
expect(br.thumbColumns).toBe(br.options.thumbColumns);
|
38
|
+
});
|
39
|
+
|
40
|
+
test('removes column and redraws zooming in', () => {
|
41
|
+
const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
|
42
|
+
const startColumns = br.thumbColumns;
|
43
|
+
br._modes.modeThumb.zoom('in');
|
44
|
+
expect(br.thumbColumns).toBe(startColumns - 1);
|
45
|
+
expect(prepare.callCount).toBe(1);
|
46
|
+
});
|
47
|
+
|
48
|
+
test('adds column and redraws zooming out', () => {
|
49
|
+
const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
|
50
|
+
const startColumns = br.thumbColumns;
|
51
|
+
br._modes.modeThumb.zoom('out');
|
52
|
+
expect(br.thumbColumns).toBe(startColumns + 1);
|
53
|
+
expect(prepare.callCount).toBe(1);
|
54
|
+
});
|
55
|
+
|
56
|
+
test('keeps columns and no redraw at zooming in limit', () => {
|
57
|
+
const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
|
58
|
+
br.thumbColumns = br.options.thumbMinZoomColumns;
|
59
|
+
br._modes.modeThumb.zoom('in');
|
60
|
+
expect(br.thumbColumns).toBe(br.options.thumbMinZoomColumns);
|
61
|
+
expect(prepare.callCount).toBe(0);
|
62
|
+
});
|
63
|
+
|
64
|
+
test('keeps columns and no redraw at zooming out limit', () => {
|
65
|
+
const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
|
66
|
+
br.thumbColumns = br.options.thumbMaxZoomColumns;
|
67
|
+
br._modes.modeThumb.zoom('out');
|
68
|
+
expect(br.thumbColumns).toBe(br.options.thumbMaxZoomColumns);
|
69
|
+
expect(prepare.callCount).toBe(0);
|
70
|
+
});
|
71
|
+
});
|
@@ -1,19 +1,19 @@
|
|
1
1
|
import sinon from 'sinon';
|
2
|
-
import { getNavPageNumHtml } from '
|
3
|
-
import BookReader from '
|
2
|
+
import { getNavPageNumHtml } from '@/src/BookReader/Navbar/Navbar.js';
|
3
|
+
import BookReader from '@/src/BookReader.js';
|
4
4
|
|
5
5
|
describe('getNavPageNumHtml', () => {
|
6
6
|
const f = getNavPageNumHtml;
|
7
7
|
test('handle n-prefixed page numbers', () => {
|
8
|
-
expect(f(3, 40, 'n3', '', 40)).toBe('
|
8
|
+
expect(f(3, 40, 'n3', '', 40)).toBe('(4 of 40)');
|
9
9
|
});
|
10
10
|
|
11
11
|
test('handle regular page numbers', () => {
|
12
|
-
expect(f(3, 40, '14', '', 40)).toBe('
|
12
|
+
expect(f(3, 40, '14', '', 40)).toBe('14 of 40');
|
13
13
|
});
|
14
14
|
|
15
15
|
test('handle no max page', () => {
|
16
|
-
expect(f(3, 40, '14', '', null)).toBe('
|
16
|
+
expect(f(3, 40, '14', '', null)).toBe('14');
|
17
17
|
});
|
18
18
|
});
|
19
19
|
|
@@ -97,9 +97,9 @@ describe('Navbar controls overrides', () => {
|
|
97
97
|
const $viewMode = navbar.$root.find('.viewmode');
|
98
98
|
|
99
99
|
expect($viewMode.find('.icon-thumb').length).toBe(1);
|
100
|
-
$viewMode.click
|
100
|
+
$viewMode.trigger("click");
|
101
101
|
expect($viewMode.find('.icon-twopg').length).toBe(1);
|
102
|
-
$viewMode.click
|
102
|
+
$viewMode.trigger("click");
|
103
103
|
expect($viewMode.find('.icon-thumb').length).toBe(1);
|
104
104
|
});
|
105
105
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {PageContainer} from '
|
1
|
+
import {PageContainer, boxToSVGRect, createSVGPageLayer, renderBoxesInPageContainerLayer} from '@/src/BookReader/PageContainer.js';
|
2
2
|
|
3
3
|
describe('constructor', () => {
|
4
4
|
test('protected books', () => {
|
@@ -31,7 +31,7 @@ describe('constructor', () => {
|
|
31
31
|
});
|
32
32
|
});
|
33
33
|
|
34
|
-
describe('update',
|
34
|
+
describe('update', () => {
|
35
35
|
test('dimensions sets CSS', () => {
|
36
36
|
const pc = new PageContainer(null, {});
|
37
37
|
pc.update({ dimensions: { left: 20 } });
|
@@ -62,17 +62,18 @@ describe('update', async () => {
|
|
62
62
|
expect(pc.$img[0].style.background).toBe('');
|
63
63
|
});
|
64
64
|
|
65
|
-
test('removes image between updates', () => {
|
65
|
+
test('removes image between updates only if changed', () => {
|
66
66
|
const fakeImageCache = {
|
67
67
|
imageLoaded: () => true,
|
68
|
-
image: () => $(
|
68
|
+
image: (index, reduce) => $(`<img src="page${index}-${reduce}.jpg" />`),
|
69
69
|
};
|
70
70
|
const pc = new PageContainer({index: 12}, {imageCache: fakeImageCache});
|
71
71
|
pc.update({ reduce: 7 });
|
72
72
|
const $im1 = pc.$img;
|
73
73
|
pc.update({ reduce: 7 });
|
74
|
-
|
75
|
-
|
74
|
+
expect(pc.$img).toBe($im1);
|
75
|
+
pc.update({ reduce: 16 });
|
76
|
+
expect(pc.$img).not.toBe($im1);
|
76
77
|
expect($im1.parent().length).toBe(0);
|
77
78
|
});
|
78
79
|
|
@@ -113,3 +114,75 @@ describe('update', async () => {
|
|
113
114
|
expect(pc.$img.css('background')).toBeFalsy();
|
114
115
|
});
|
115
116
|
});
|
117
|
+
|
118
|
+
describe('createSVGPageLayer', () => {
|
119
|
+
test('Does what it says', () => {
|
120
|
+
const svg = createSVGPageLayer({ width: 100, height: 200}, 'myClass');
|
121
|
+
expect(svg.getAttribute('viewBox')).toBe('0 0 100 200');
|
122
|
+
expect(svg.getAttribute('class')).toContain('myClass');
|
123
|
+
});
|
124
|
+
});
|
125
|
+
|
126
|
+
describe('boxToSVGRect', () => {
|
127
|
+
test('Does what it says', () => {
|
128
|
+
const rect = boxToSVGRect({ l: 100, r: 200, t: 300, b: 500 });
|
129
|
+
expect(rect.getAttribute('x')).toBe('100');
|
130
|
+
expect(rect.getAttribute('y')).toBe('300');
|
131
|
+
expect(rect.getAttribute('width')).toBe('100');
|
132
|
+
expect(rect.getAttribute('height')).toBe('200');
|
133
|
+
});
|
134
|
+
});
|
135
|
+
|
136
|
+
describe('renderBoxesInPageContainerLayer', () => {
|
137
|
+
test('Handles missing layer', () => {
|
138
|
+
const container = document.createElement('div');
|
139
|
+
const page = { width: 100, height: 200 };
|
140
|
+
const boxes = [{l: 1, r: 2, t: 3, b: 4}];
|
141
|
+
renderBoxesInPageContainerLayer('foo', boxes, page, container);
|
142
|
+
expect(container.querySelector('.foo')).toBeTruthy();
|
143
|
+
expect(container.querySelectorAll('.foo rect').length).toBe(1);
|
144
|
+
});
|
145
|
+
|
146
|
+
test('Handles existing layer', () => {
|
147
|
+
const container = document.createElement('div');
|
148
|
+
const layer = document.createElement('svg');
|
149
|
+
layer.classList.add('foo');
|
150
|
+
container.append(layer);
|
151
|
+
|
152
|
+
const page = { width: 100, height: 200 };
|
153
|
+
const boxes = [{l: 1, r: 2, t: 3, b: 4}];
|
154
|
+
renderBoxesInPageContainerLayer('foo', boxes, page, container);
|
155
|
+
expect(container.querySelector('.foo')).toBe(layer);
|
156
|
+
expect(container.querySelectorAll('.foo rect').length).toBe(1);
|
157
|
+
});
|
158
|
+
|
159
|
+
test('Adds layer after image if it exists', () => {
|
160
|
+
const container = document.createElement('div');
|
161
|
+
const img = document.createElement('img');
|
162
|
+
img.classList.add('BRpageimage');
|
163
|
+
container.append(img);
|
164
|
+
|
165
|
+
const page = { width: 100, height: 200 };
|
166
|
+
const boxes = [{l: 1, r: 2, t: 3, b: 4}];
|
167
|
+
renderBoxesInPageContainerLayer('foo', boxes, page, container);
|
168
|
+
expect(container.querySelector('.foo')).toBeTruthy();
|
169
|
+
expect(container.children[0].getAttribute('class')).toBe('BRpageimage');
|
170
|
+
expect(container.children[1].getAttribute('class')).toBe('BRPageLayer foo');
|
171
|
+
});
|
172
|
+
|
173
|
+
test('Renders all boxes', () => {
|
174
|
+
const container = document.createElement('div');
|
175
|
+
const page = { width: 100, height: 200 };
|
176
|
+
const boxes = [{l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}, {l: 1, r: 2, t: 3, b: 4}];
|
177
|
+
renderBoxesInPageContainerLayer('foo', boxes, page, container);
|
178
|
+
expect(container.querySelectorAll('.foo rect').length).toBe(3);
|
179
|
+
});
|
180
|
+
|
181
|
+
test('Handles no boxes', () => {
|
182
|
+
const container = document.createElement('div');
|
183
|
+
const page = { width: 100, height: 200 };
|
184
|
+
const boxes = [];
|
185
|
+
renderBoxesInPageContainerLayer('foo', boxes, page, container);
|
186
|
+
expect(container.querySelectorAll('.foo rect').length).toBe(0);
|
187
|
+
});
|
188
|
+
});
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import sinon from 'sinon';
|
2
2
|
|
3
|
-
import { createPopup } from '
|
3
|
+
import { createPopup } from '@/src/BookReader/Toolbar/Toolbar.js';
|
4
4
|
|
5
5
|
afterEach(() => {
|
6
6
|
sinon.restore();
|
7
|
-
})
|
7
|
+
});
|
8
8
|
|
9
9
|
describe('createPopup', () => {
|
10
10
|
test('calls window.open', () => {
|
@@ -0,0 +1,59 @@
|
|
1
|
+
// @ts-check
|
2
|
+
import sinon from 'sinon';
|
3
|
+
import { HTMLDimensionsCacher } from '@/src/BookReader/utils/HTMLDimensionsCacher';
|
4
|
+
|
5
|
+
describe('HTMLDimensionsCacher', () => {
|
6
|
+
test('Does not read from element directly', () => {
|
7
|
+
const element = document.createElement('div');
|
8
|
+
const getBoundingClientRectStub = element.getBoundingClientRect = sinon.stub().returns({ top: 10, left: 20 });
|
9
|
+
const clientWidthStub = sinon.stub().returns(300);
|
10
|
+
const clientHeightStub = sinon.stub().returns(500);
|
11
|
+
Object.defineProperty(element, 'clientWidth', { get: clientWidthStub });
|
12
|
+
Object.defineProperty(element, 'clientHeight', { get: clientHeightStub });
|
13
|
+
|
14
|
+
const hdc = new HTMLDimensionsCacher(element);
|
15
|
+
hdc.clientHeight;
|
16
|
+
expect(getBoundingClientRectStub.callCount).toBe(0);
|
17
|
+
expect(clientWidthStub.callCount).toBe(0);
|
18
|
+
expect(clientHeightStub.callCount).toBe(0);
|
19
|
+
});
|
20
|
+
|
21
|
+
test('Read from element when calling update', () => {
|
22
|
+
const element = document.createElement('div');
|
23
|
+
const getBoundingClientRectStub = element.getBoundingClientRect = sinon.stub().returns({ top: 10, left: 20 });
|
24
|
+
const clientWidthStub = sinon.stub().returns(300);
|
25
|
+
const clientHeightStub = sinon.stub().returns(500);
|
26
|
+
Object.defineProperty(element, 'clientWidth', { get: clientWidthStub });
|
27
|
+
Object.defineProperty(element, 'clientHeight', { get: clientHeightStub });
|
28
|
+
|
29
|
+
const hdc = new HTMLDimensionsCacher(element);
|
30
|
+
hdc.updateClientSizes();
|
31
|
+
expect(getBoundingClientRectStub.callCount).toBe(1);
|
32
|
+
expect(clientWidthStub.callCount).toBe(1);
|
33
|
+
expect(clientHeightStub.callCount).toBe(1);
|
34
|
+
|
35
|
+
expect(hdc.boundingClientRect).toEqual({ top: 10, left: 20 });
|
36
|
+
expect(hdc.clientWidth).toBe(300);
|
37
|
+
expect(hdc.clientHeight).toBe(500);
|
38
|
+
});
|
39
|
+
|
40
|
+
test('Does not listen for window resizes when not attached', () => {
|
41
|
+
const element = document.createElement('div');
|
42
|
+
const hdc = new HTMLDimensionsCacher(element);
|
43
|
+
const dummyWindow = new EventTarget();
|
44
|
+
const debouncedUpdateSpy = sinon.spy(hdc, 'debouncedUpdateClientSizes');
|
45
|
+
|
46
|
+
dummyWindow.dispatchEvent(new Event('resize', {}));
|
47
|
+
expect(debouncedUpdateSpy.callCount).toBe(0);
|
48
|
+
|
49
|
+
hdc.attachResizeListener(dummyWindow);
|
50
|
+
|
51
|
+
dummyWindow.dispatchEvent(new Event('resize', {}));
|
52
|
+
expect(debouncedUpdateSpy.callCount).toBe(1);
|
53
|
+
|
54
|
+
hdc.detachResizeListener(dummyWindow);
|
55
|
+
|
56
|
+
dummyWindow.dispatchEvent(new Event('resize', {}));
|
57
|
+
expect(debouncedUpdateSpy.callCount).toBe(1);
|
58
|
+
});
|
59
|
+
});
|
@@ -0,0 +1,49 @@
|
|
1
|
+
// @ts-check
|
2
|
+
import sinon from 'sinon';
|
3
|
+
import { ScrollClassAdder } from '@/src/BookReader/utils/ScrollClassAdder';
|
4
|
+
|
5
|
+
describe('ScrollClassAdder', () => {
|
6
|
+
test('Does not attach during construction', () => {
|
7
|
+
const element = document.createElement('div');
|
8
|
+
const attachSpy = sinon.spy(ScrollClassAdder.prototype, 'attach');
|
9
|
+
new ScrollClassAdder(element, 'foo');
|
10
|
+
expect(attachSpy.callCount).toBe(0);
|
11
|
+
});
|
12
|
+
|
13
|
+
test('Attach/detach call correct methods', () => {
|
14
|
+
const el = document.createElement('div');
|
15
|
+
const addEventListenerSpy = sinon.spy(el, 'addEventListener');
|
16
|
+
const removeEventListenerSpy = sinon.spy(el, 'removeEventListener');
|
17
|
+
const sca = new ScrollClassAdder(el, 'foo');
|
18
|
+
expect(addEventListenerSpy.callCount).toBe(0);
|
19
|
+
sca.attach();
|
20
|
+
expect(addEventListenerSpy.callCount).toBe(1);
|
21
|
+
sca.detach();
|
22
|
+
expect(removeEventListenerSpy.callCount).toBe(1);
|
23
|
+
});
|
24
|
+
|
25
|
+
test('onScroll adds class at right time', () => {
|
26
|
+
const clock = sinon.useFakeTimers();
|
27
|
+
const el = document.createElement('div');
|
28
|
+
const sca = new ScrollClassAdder(el, 'foo');
|
29
|
+
expect(el.getAttribute('class')).toBeFalsy();
|
30
|
+
sca.onScroll();
|
31
|
+
expect(el.getAttribute('class')).toBe('foo');
|
32
|
+
clock.tick(600);
|
33
|
+
expect(el.getAttribute('class')).toBeFalsy();
|
34
|
+
|
35
|
+
sca.onScroll();
|
36
|
+
expect(el.getAttribute('class')).toBe('foo');
|
37
|
+
clock.tick(500);
|
38
|
+
expect(el.getAttribute('class')).toBe('foo');
|
39
|
+
sca.onScroll();
|
40
|
+
expect(el.getAttribute('class')).toBe('foo');
|
41
|
+
clock.tick(100);
|
42
|
+
expect(el.getAttribute('class')).toBe('foo');
|
43
|
+
clock.tick(499);
|
44
|
+
expect(el.getAttribute('class')).toBe('foo');
|
45
|
+
clock.tick(1);
|
46
|
+
expect(el.getAttribute('class')).toBeFalsy();
|
47
|
+
clock.restore();
|
48
|
+
});
|
49
|
+
});
|
@@ -0,0 +1,136 @@
|
|
1
|
+
import sinon from 'sinon';
|
2
|
+
import {
|
3
|
+
clamp,
|
4
|
+
cssPercentage,
|
5
|
+
debounce,
|
6
|
+
decodeURIComponentPlus,
|
7
|
+
encodeURIComponentPlus,
|
8
|
+
escapeHTML,
|
9
|
+
getActiveElement,
|
10
|
+
isInputActive,
|
11
|
+
polyfillCustomEvent,
|
12
|
+
PolyfilledCustomEvent,
|
13
|
+
} from '@/src/BookReader/utils.js';
|
14
|
+
|
15
|
+
test('clamp function returns Math.min(Math.max(value, min), max)', () => {
|
16
|
+
expect(clamp(2,1,3)).toEqual(2);
|
17
|
+
});
|
18
|
+
|
19
|
+
test('calculate a percentage suitable for CSS', () => {
|
20
|
+
expect(cssPercentage(2,1)).toEqual('200%');
|
21
|
+
});
|
22
|
+
|
23
|
+
test('escapeHTML function which replaces the string', () => {
|
24
|
+
expect(escapeHTML('Me & You')).toEqual('Me & You');
|
25
|
+
expect(escapeHTML('Me > You')).toEqual('Me > You');
|
26
|
+
expect(escapeHTML('Me < You')).toEqual('Me < You');
|
27
|
+
expect(escapeHTML('Me " You')).toEqual('Me " You');
|
28
|
+
});
|
29
|
+
|
30
|
+
test('Decodes a URI component and converts + to emptyStr', () => {
|
31
|
+
expect(decodeURIComponentPlus("https%3A%2F%2Farchive.org%2Fskr+")).toEqual("https://archive.org/skr ");
|
32
|
+
expect(decodeURIComponentPlus("%3Fx%3D+test")).toEqual("?x= test");
|
33
|
+
});
|
34
|
+
|
35
|
+
test('Encodes a URI component and converts emptyStr to +', () => {
|
36
|
+
expect(encodeURIComponentPlus("?x=test ")).toEqual("%3Fx%3Dtest+");
|
37
|
+
expect(encodeURIComponentPlus("ABC abc 123")).toEqual("ABC+abc+123");
|
38
|
+
});
|
39
|
+
|
40
|
+
describe('getActiveElement', () => {
|
41
|
+
test('Can ignore shadow DOM', () => {
|
42
|
+
const doc = {activeElement: { shadowRoot: {activeElement: {}}}};
|
43
|
+
expect(getActiveElement(doc, false)).toBe(doc.activeElement);
|
44
|
+
});
|
45
|
+
|
46
|
+
test('Can traverse shadow DOM', () => {
|
47
|
+
const doc = {activeElement: { shadowRoot: {activeElement: {}}}};
|
48
|
+
expect(getActiveElement(doc, true)).toBe(doc.activeElement.shadowRoot.activeElement);
|
49
|
+
});
|
50
|
+
|
51
|
+
test('Handles non-shadow elements', () => {
|
52
|
+
const doc = {activeElement: {}};
|
53
|
+
expect(getActiveElement(doc, true)).toBe(doc.activeElement);
|
54
|
+
});
|
55
|
+
|
56
|
+
test('Handles no active element', () => {
|
57
|
+
const doc = {activeElement: null};
|
58
|
+
expect(getActiveElement(doc, true)).toBe(null);
|
59
|
+
});
|
60
|
+
});
|
61
|
+
|
62
|
+
describe('isInputActive', () => {
|
63
|
+
test('Handles no activeElement', () => {
|
64
|
+
expect(isInputActive({activeElement: null})).toBe(false);
|
65
|
+
});
|
66
|
+
|
67
|
+
test('Handles deep input activeElement', () => {
|
68
|
+
const doc = {activeElement: { shadowRoot: {activeElement: { tagName: 'INPUT' }}}};
|
69
|
+
expect(isInputActive(doc)).toBe(true);
|
70
|
+
});
|
71
|
+
|
72
|
+
test('Handles deep non-input activeElement', () => {
|
73
|
+
const doc = {activeElement: { shadowRoot: {activeElement: { tagName: 'A' }}}};
|
74
|
+
expect(isInputActive(doc)).toBe(false);
|
75
|
+
});
|
76
|
+
|
77
|
+
test('Handles textarea activeElement', () => {
|
78
|
+
const doc = {activeElement: { tagName: 'TEXTAREA' }};
|
79
|
+
expect(isInputActive(doc)).toBe(true);
|
80
|
+
});
|
81
|
+
});
|
82
|
+
|
83
|
+
describe('debounce', () => {
|
84
|
+
/** @type {sinon.SinonFakeTimers} */
|
85
|
+
let clock;
|
86
|
+
beforeEach(() => clock = sinon.useFakeTimers());
|
87
|
+
afterEach(() => clock.restore());
|
88
|
+
|
89
|
+
test('testing debounce', () => {
|
90
|
+
const func = jest.fn();
|
91
|
+
const debouncedFunc = debounce(func, 1000);
|
92
|
+
// Call it immediately
|
93
|
+
debouncedFunc();
|
94
|
+
expect(func).toHaveBeenCalledTimes(0); // func not called
|
95
|
+
|
96
|
+
// Call it several times with 500ms between each call
|
97
|
+
for (let i = 0; i < 10; i++) {
|
98
|
+
clock.tick(500);
|
99
|
+
debouncedFunc();
|
100
|
+
}
|
101
|
+
expect(func).toHaveBeenCalledTimes(0); // func not called
|
102
|
+
|
103
|
+
// wait 1000ms
|
104
|
+
clock.tick(1000);
|
105
|
+
expect(func).toHaveBeenCalledTimes(1); // func called
|
106
|
+
});
|
107
|
+
});
|
108
|
+
|
109
|
+
|
110
|
+
describe('polyfillCustomEvent', () => {
|
111
|
+
test('Overrides when missing', () => {
|
112
|
+
const win = {};
|
113
|
+
polyfillCustomEvent(win);
|
114
|
+
expect(win).toHaveProperty('CustomEvent');
|
115
|
+
});
|
116
|
+
|
117
|
+
test('Overrides when not a function', () => {
|
118
|
+
const win = { CustomEvent: {} };
|
119
|
+
polyfillCustomEvent(win);
|
120
|
+
expect(typeof win.CustomEvent).toBe('function');
|
121
|
+
});
|
122
|
+
});
|
123
|
+
|
124
|
+
describe('PolyfilledCustomEvent', () => {
|
125
|
+
test('Can be called as a constructor', () => {
|
126
|
+
new PolyfilledCustomEvent('foo');
|
127
|
+
});
|
128
|
+
|
129
|
+
test('Calls deprecated browser methods', () => {
|
130
|
+
const createEventSpy = sinon.spy(document, 'createEvent');
|
131
|
+
const initCustomEventSpy = sinon.spy(CustomEvent.prototype, 'initCustomEvent');
|
132
|
+
new PolyfilledCustomEvent('foo');
|
133
|
+
expect(createEventSpy.callCount).toBe(1);
|
134
|
+
expect(initCustomEventSpy.callCount).toBe(1);
|
135
|
+
});
|
136
|
+
});
|