@internetarchive/ia-item-navigator 0.0.0-a10 → 0.0.0-a12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. package/demo/app-root.ts +6 -4
  2. package/dist/demo/app-root.d.ts +0 -1
  3. package/dist/demo/app-root.js +1 -3
  4. package/dist/demo/app-root.js.map +1 -1
  5. package/dist/src/interfaces/nav-controller-interface.d.ts +9 -0
  6. package/dist/src/interfaces/nav-controller-interface.js.map +1 -1
  7. package/dist/src/item-inspector/item-inspector.d.ts +0 -47
  8. package/dist/src/item-inspector/item-inspector.js +253 -271
  9. package/dist/src/item-inspector/item-inspector.js.map +1 -1
  10. package/dist/src/item-navigator.d.ts +14 -7
  11. package/dist/src/item-navigator.js +60 -30
  12. package/dist/src/item-navigator.js.map +1 -1
  13. package/dist/src/no-theater-available.d.ts +9 -0
  14. package/dist/src/no-theater-available.js +79 -0
  15. package/dist/src/no-theater-available.js.map +1 -0
  16. package/dist/test/book-nav-stub.d.ts +17 -0
  17. package/dist/test/book-nav-stub.js +42 -0
  18. package/dist/test/book-nav-stub.js.map +1 -0
  19. package/dist/test/ia-item-navigator.test.d.ts +1 -0
  20. package/dist/test/ia-item-navigator.test.js +146 -114
  21. package/dist/test/ia-item-navigator.test.js.map +1 -1
  22. package/dist/test/ia-stub.d.ts +22 -0
  23. package/dist/test/ia-stub.js +34 -3
  24. package/dist/test/ia-stub.js.map +1 -1
  25. package/dist/test/no-theater-available.test.d.ts +1 -0
  26. package/dist/test/no-theater-available.test.js +27 -0
  27. package/dist/test/no-theater-available.test.js.map +1 -0
  28. package/package.json +3 -2
  29. package/src/interfaces/nav-controller-interface.ts +13 -0
  30. package/src/item-navigator.ts +69 -36
  31. package/src/no-theater-available.ts +87 -0
  32. package/test/book-nav-stub.ts +35 -0
  33. package/test/ia-item-navigator.test.ts +191 -143
  34. package/test/ia-stub.ts +78 -2
  35. package/test/no-theater-available.test.ts +32 -0
  36. package/src/item-inspector/item-inspector.ts +0 -296
@@ -1,129 +1,113 @@
1
1
  /* eslint-disable camelcase */
2
- /* eslint-disable import/no-duplicates */
3
2
  import { html, fixture, expect } from '@open-wc/testing';
4
3
  import Sinon from 'sinon';
5
- // import { MetadataResponse, Metadata, File, Review, SpeechMusicASREntry } from '@internetarchive/search-service';
6
- import {
7
- SharedResizeObserver,
8
- // SharedResizeObserverInterface
9
- } from '@internetarchive/shared-resize-observer';
10
4
 
11
- // import { IntLoadingStateUpdatedEvent } from '../src/interfaces/event-interfaces';
5
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
6
+ import { IntNavController } from '../src/interfaces/nav-controller-interface';
12
7
  import { ItemNavigator } from '../src/item-navigator';
13
8
  import '../src/item-navigator';
14
- // import { IaItemInspector } from '../src/item-inspector/item-inspector';
15
9
 
16
- // class ItemStub implements MetadataResponse {
17
- // constructor() {
18
- // this.rawResponse = '';
19
- // this.created = 1;
20
- // this.d1 = 'hello';
21
- // this.d2 = 'boop';
22
- // this.dir = 'whee';
23
- // this.files = [];
24
- // this.files_count = 0;
25
- // this.item_last_updated = 2020;
26
- // this.item_size = 111;
27
- // this.metadata = { identifier: 'foo' } as Metadata;
28
- // this.server = 'foo-server';
29
- // this.uniq = 2;
30
- // this.workable_servers = ['abc'];
31
- // }
32
-
33
- // rawResponse: any;
34
-
35
- // created: number;
36
-
37
- // d1: string;
38
-
39
- // d2: string;
40
-
41
- // dir: string;
42
-
43
- // files: File[];
44
-
45
- // files_count: number;
46
-
47
- // item_last_updated: number;
48
-
49
- // item_size: number;
50
-
51
- // metadata: Metadata;
52
-
53
- // server: string;
54
-
55
- // uniq: number;
56
-
57
- // workable_servers: string[];
58
-
59
- // speech_vs_music_asr?: SpeechMusicASREntry[] | undefined;
60
-
61
- // reviews?: Review[] | undefined;
62
- // };
10
+ import '../test/book-nav-stub';
11
+ import { ItemStub, menuProvider, shortcut } from '../test/ia-stub';
12
+ import { IntManageSideMenuEvent } from '../src/interfaces/event-interfaces';
63
13
 
64
14
  afterEach(() => {
65
15
  Sinon.restore();
66
16
  });
67
17
 
68
18
  describe('ItemNavigator', () => {
69
- describe('Loading Behavior', () => {
70
- it('shows the spinning loader', async () => {
19
+ describe('Theaters', () => {
20
+ it('shows <ia-no-theater-available> by default', async () => {
71
21
  const el = await fixture<ItemNavigator>(
72
- html`<ia-item-navigator></ia-item-navigator>`
22
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
73
23
  );
74
- expect(el.shadowRoot?.querySelector('ia-itemnav-loader')).to.be.exist;
24
+ expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.exist;
25
+ });
26
+
27
+ it('shows <book-navigator> if `this.itemType = "bookreader"`', async () => {
28
+ const el = await fixture<ItemNavigator>(
29
+ html`<ia-item-navigator
30
+ .itemType=${`bookreader`}
31
+ .item=${new ItemStub()}
32
+ ></ia-item-navigator>`
33
+ );
34
+
35
+ await el.updateComplete;
36
+
37
+ el.toggleMenu();
38
+ await el.updateComplete;
39
+
40
+ const bookNavigator = el.shadowRoot?.querySelector(
41
+ 'book-navigator'
42
+ ) as IntNavController;
43
+ await bookNavigator.updateComplete;
44
+
45
+ console.log('132234234324324324');
46
+ // TODO: add BookNavigator type & import via @internetarchive/bookreader
47
+ // For now, let's check that the BookNavigator element and its properties exist w/ stub
48
+ expect(bookNavigator).to.exist;
49
+ expect(bookNavigator?.modal).to.exist;
50
+ expect(bookNavigator?.baseHost).to.exist;
51
+ expect(bookNavigator?.book).to.exist;
52
+ expect(bookNavigator?.signedIn).to.be.null;
53
+ expect(bookNavigator?.sharedObserver).to.exist;
54
+ expect(bookNavigator?.sideMenuOpen).to.exist;
75
55
  });
76
- it('hides reader section if not `loaded`', async () => {
56
+ });
57
+ describe('`el.loaded`', () => {
58
+ it('toggles the spinning loader', async () => {
77
59
  const el = await fixture<ItemNavigator>(
78
60
  html`<ia-item-navigator></ia-item-navigator>`
79
61
  );
80
- const mainTheaterSection = el.shadowRoot?.querySelector('#reader');
81
- expect(mainTheaterSection).to.be.exist;
82
- expect(mainTheaterSection?.classList.contains('hide')).to.be.true;
83
- expect(el.loaded).to.be.false;
84
- expect(el.hasAttribute('loaded')).to.equal(false);
62
+ expect(el.loaded).to.be.null; // initial load
63
+ expect(el.shadowRoot?.querySelector('ia-itemnav-loader')).to.exist;
85
64
  });
86
- it('shows reader once `loaded`', async () => {
65
+ it('hides reader section if `!loaded`', async () => {
87
66
  const el = await fixture<ItemNavigator>(
88
67
  html`<ia-item-navigator></ia-item-navigator>`
89
68
  );
90
- el.loaded = true;
91
- await el.updateComplete;
69
+
70
+ expect(
71
+ el.shadowRoot?.querySelector('#reader')?.getAttribute('class')
72
+ ).to.contain('hide');
73
+ });
74
+ it('shows reader when `loaded` ', async () => {
75
+ const el = await fixture<ItemNavigator>(
76
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
77
+ );
92
78
 
93
79
  const mainTheaterSection = el.shadowRoot?.querySelector('#reader');
94
80
  expect(mainTheaterSection?.classList.contains('hide')).to.be.false;
95
81
  expect(el.loaded).to.be.true;
96
82
  // `loaded` property is reflected as DOM attribute
97
83
  expect(el.hasAttribute('loaded')).to.equal(true);
84
+ expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.exist;
98
85
  });
86
+ it('listens to `@loadingStateUpdated` to update `loaded`', async () => {
87
+ const el = await fixture<ItemNavigator>(
88
+ html`<ia-item-navigator></ia-item-navigator>`
89
+ );
99
90
 
100
- // it('listens to event `loadingStateUpdated` to signal load', async () => {
101
- // const item = new ItemStub() as MetadataResponse;
102
- // const el = await fixture<ItemNavigator>(
103
- // html`<ia-item-navigator .item=${item}></ia-item-navigator>`
104
- // );
105
- // // const loadSpy = Sinon.spy();
106
- // // el.loadingStateUpdated = loadSpy;
107
- // await el.updateComplete;
108
-
109
- // expect(el?.item).to.not.be.undefined;
110
-
111
- // const mainTheaterSection = el.shadowRoot?.querySelector('#reader');
112
-
113
- // const contentController = mainTheaterSection?.querySelector('ia-item-inspector');
114
-
115
- // expect(contentController).to.equal(32324);
116
-
117
- // // const loadingEvent = new CustomEvent('loadingStateUpdated', { detail: { loaded: true }}) as IntLoadingStateUpdatedEvent;
118
- // // contentController?.emitLoadingStatusUpdate(true);
91
+ await el.updateComplete;
92
+ const spy = Sinon.spy();
93
+ el.loadingStateUpdated = spy;
94
+ el.loaded = false;
95
+ await el.updateComplete;
96
+ // check base properties
97
+ expect(el.loaded).to.equal(false);
98
+ expect(el.item).to.be.undefined;
119
99
 
120
- // // await contentController?.updateComplete;
121
- // // await el.updateComplete;
100
+ // hydrate item
101
+ el.item = new ItemStub();
102
+ await el.updateComplete;
122
103
 
123
- // });
104
+ // spy fires
105
+ expect(spy.called).to.equal(true);
106
+ expect(spy.callCount).to.equal(1);
107
+ });
124
108
  });
125
109
 
126
- describe('It uses a shared ResizeObserver', () => {
110
+ describe('`el.sharedObserver`', () => {
127
111
  it('can create one', async () => {
128
112
  const el = await fixture<ItemNavigator>(
129
113
  html`<ia-item-navigator></ia-item-navigator>`
@@ -146,7 +130,7 @@ describe('ItemNavigator', () => {
146
130
  });
147
131
  });
148
132
 
149
- describe('It uses a shared modal component', () => {
133
+ describe('`el.modal`', () => {
150
134
  it('can create one', async () => {
151
135
  const el = await fixture<ItemNavigator>(
152
136
  html`<ia-item-navigator></ia-item-navigator>`
@@ -171,59 +155,123 @@ describe('ItemNavigator', () => {
171
155
  });
172
156
  });
173
157
 
174
- // describe('full browser window immersion "fullscreen"', () => {
175
- // it('creates reflected attribute `viewportinfullscreen`', () =>{
176
- // /** to help with external styling adjustmnents */
177
- // });
178
- // });
158
+ describe('full browser window immersion "fullscreen"', () => {
159
+ it('creates reflected attribute `viewportinfullscreen`', async () => {
160
+ /** to help with external styling adjustmnents */
161
+ const el = await fixture<ItemNavigator>(
162
+ html`<ia-item-navigator></ia-item-navigator>`
163
+ );
164
+ expect(el.getAttribute('viewportinfullscreen')).to.be.null;
165
+
166
+ el.viewportInFullscreen = true;
167
+ await el.updateComplete;
168
+
169
+ expect(el.getAttribute('viewportinfullscreen')).to.exist;
170
+ });
171
+ });
179
172
 
180
- // describe('Loads side menu contents', () =>{
181
- // });
173
+ /* Side menu & shortcuts tests */
174
+ describe('el.menuOpened', () => {
175
+ it('toggles side menu open', async () => {
176
+ const el = await fixture<ItemNavigator>(
177
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
178
+ );
182
179
 
183
- // describe('Menu Shortcuts', () => {
184
- // });
180
+ el.menuContents = [menuProvider];
181
+ await el.updateComplete;
185
182
 
186
- // it('passes the a11y audit', async () => {
187
- // const el = await fixture<YourWebComponent>(
188
- // html`<your-webcomponent></your-webcomponent>`
189
- // );
183
+ const nav = el.shadowRoot?.querySelector('nav');
190
184
 
191
- // await expect(el).shadowDom.to.be.accessible();
192
- // });
193
- });
185
+ expect(nav?.querySelector('#menu')).to.exist;
186
+ // side menu starts closed
187
+ expect(el.menuOpened).to.be.false;
188
+ expect(nav?.querySelector('#menu')?.getAttribute('class')).to.contain(
189
+ 'hidden'
190
+ );
191
+
192
+ // let's open menu
193
+ el.toggleMenu();
194
+ await el.updateComplete;
195
+
196
+ expect(el.menuOpened).to.be.true;
197
+ expect(nav?.querySelector('#menu')?.getAttribute('class')).to.not.contain(
198
+ 'hidden'
199
+ );
200
+ });
201
+
202
+ it('opens menu shortcut with `@manageSideMenuEvents`', async () => {
203
+ const el = await fixture<ItemNavigator>(
204
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
205
+ );
206
+ const detail = {
207
+ menuId: 'fullscreen',
208
+ action: 'open',
209
+ };
210
+
211
+ el.menuContents = [menuProvider];
212
+ await el.updateComplete;
213
+ const frame = el.shadowRoot?.querySelector('#frame');
214
+ // default menu open behavior is to side menu open, not overlay
215
+ expect(frame?.getAttribute('class')).to.contain('shift');
216
+
217
+ expect(el.menuOpened).to.be.false;
218
+ expect(el.openMenu).to.be.empty;
219
+ expect(frame?.getAttribute('class')).to.not.contain('open');
220
+
221
+ const event = new CustomEvent('updateSideMenu', {
222
+ detail,
223
+ }) as IntManageSideMenuEvent;
224
+ el.manageSideMenuEvents(event);
225
+ await el.updateComplete;
226
+
227
+ expect(el.shouldRenderMenu).to.be.true;
228
+ expect(el.menuOpened).to.be.true;
229
+ expect(el.openMenu).to.equal(detail.menuId);
230
+
231
+ expect(frame?.getAttribute('class')).to.contain('open');
232
+ });
233
+ });
234
+
235
+ describe('el.menuContents', () => {
236
+ it('draws side menu when populated', async () => {
237
+ const el = await fixture<ItemNavigator>(
238
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
239
+ );
240
+
241
+ el.menuContents = [menuProvider];
242
+ await el.updateComplete;
243
+ expect(el.menuContents.length).to.exist;
244
+ expect(el.shouldRenderMenu).to.be.true;
245
+
246
+ const nav = el.shadowRoot?.querySelector('nav');
247
+ expect(nav).to.exist;
194
248
 
195
- // describe('YourWebComponent', () => {
196
- // it('has a default title "Hey there" and counter 5', async () => {
197
- // const el = await fixture<YourWebComponent>(
198
- // html`<your-webcomponent></your-webcomponent>`
199
- // );
200
-
201
- // expect(el.title).to.equal('Hey there');
202
- // expect(el.counter).to.equal(5);
203
- // });
204
-
205
- // it('increases the counter on button click', async () => {
206
- // const el = await fixture<YourWebComponent>(
207
- // html`<your-webcomponent></your-webcomponent>`
208
- // );
209
- // el.shadowRoot!.querySelector('button')!.click();
210
-
211
- // expect(el.counter).to.equal(6);
212
- // });
213
-
214
- // it('can override the title via attribute', async () => {
215
- // const el = await fixture<YourWebComponent>(
216
- // html`<your-webcomponent title="attribute title"></your-webcomponent>`
217
- // );
218
-
219
- // expect(el.title).to.equal('attribute title');
220
- // });
221
-
222
- // it('passes the a11y audit', async () => {
223
- // const el = await fixture<YourWebComponent>(
224
- // html`<your-webcomponent></your-webcomponent>`
225
- // );
226
-
227
- // await expect(el).shadowDom.to.be.accessible();
228
- // });
229
- // });
249
+ const menuSlider = nav?.querySelector('ia-menu-slider');
250
+ expect(menuSlider).to.exist;
251
+ expect(menuSlider?.getAttribute('manuallyhandleclose')).to.exist;
252
+ expect(menuSlider?.getAttribute('open')).to.exist;
253
+ });
254
+ });
255
+
256
+ describe('`el.menuShortcuts`', () => {
257
+ it('displays shortcut & toggle side menu button', async () => {
258
+ const el = await fixture<ItemNavigator>(
259
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
260
+ );
261
+
262
+ el.menuContents = [menuProvider];
263
+ el.menuShortcuts = [shortcut];
264
+ await el.updateComplete;
265
+
266
+ const nav = el.shadowRoot?.querySelector('nav');
267
+
268
+ expect(el.menuShortcuts.length).to.exist;
269
+ expect(nav).to.exist;
270
+ expect(nav?.querySelector('.shortcuts')).to.exist;
271
+ expect(
272
+ nav?.querySelector('.shortcuts')?.querySelector('i.fullscreen-test')
273
+ ).to.exist;
274
+ expect(nav?.querySelector('.toggle-menu')).to.exist;
275
+ });
276
+ });
277
+ });
package/test/ia-stub.ts CHANGED
@@ -1,3 +1,79 @@
1
- // const parsed = JSON.parse(raw);
1
+ /* eslint-disable camelcase */
2
+ import {
3
+ MetadataResponse,
4
+ Metadata,
5
+ File,
6
+ Review,
7
+ SpeechMusicASREntry,
8
+ } from '@internetarchive/search-service';
9
+ import { html } from 'lit-html';
10
+ import {
11
+ IntMenuShortcut,
12
+ IntMenuProvider,
13
+ } from '../src/interfaces/menu-interfaces';
2
14
 
3
- // export default parsed;
15
+ export class ItemStub implements MetadataResponse {
16
+ constructor() {
17
+ this.rawResponse = '';
18
+ this.created = 1;
19
+ this.d1 = 'hello';
20
+ this.d2 = 'boop';
21
+ this.dir = 'whee';
22
+ this.files = [];
23
+ this.files_count = 0;
24
+ this.item_last_updated = 2020;
25
+ this.item_size = 111;
26
+ this.metadata = { identifier: 'foo' } as Metadata;
27
+ this.server = 'foo-server';
28
+ this.uniq = 2;
29
+ this.workable_servers = ['abc'];
30
+ }
31
+
32
+ rawResponse: any;
33
+
34
+ created: number;
35
+
36
+ d1: string;
37
+
38
+ d2: string;
39
+
40
+ dir: string;
41
+
42
+ files: File[];
43
+
44
+ files_count: number;
45
+
46
+ item_last_updated: number;
47
+
48
+ item_size: number;
49
+
50
+ metadata: Metadata;
51
+
52
+ server: string;
53
+
54
+ uniq: number;
55
+
56
+ workable_servers: string[];
57
+
58
+ speech_vs_music_asr?: SpeechMusicASREntry[] | undefined;
59
+
60
+ reviews?: Review[] | undefined;
61
+ }
62
+
63
+ export const shortcut = {
64
+ id: 'fullscreen',
65
+ icon: html`<i class="fas fullscreen-test"></i>`,
66
+ } as IntMenuShortcut;
67
+
68
+ export const menuProvider = {
69
+ ...shortcut,
70
+ label: 'foo',
71
+ menuDetails: html`<div>foo</div>`,
72
+ selected: true,
73
+ followable: false,
74
+ href: 'https://archive.foo',
75
+ item: new ItemStub(),
76
+ baseHost: 'https://archive.foo',
77
+ subPrefix: 'bar',
78
+ updated: () => {},
79
+ } as IntMenuProvider;
@@ -0,0 +1,32 @@
1
+ import { html, fixture, expect } from '@open-wc/testing';
2
+ import { IANoTheaterAvailable } from '../src/no-theater-available';
3
+ import '../src/no-theater-available';
4
+
5
+ describe('IANoTheaterAvailable', () => {
6
+ it('Fires `loadingStateUpdated` on identifier change', async () => {
7
+ const el = await fixture<IANoTheaterAvailable>(
8
+ html`<ia-no-theater-available
9
+ .identifier=${`foo`}
10
+ ></ia-no-theater-available>`
11
+ );
12
+ let eventFired = false;
13
+ el.addEventListener('loadingStateUpdated', () => {
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
+ eventFired = true;
16
+ });
17
+ expect(eventFired).to.be.false;
18
+
19
+ el.identifier = 'bar';
20
+ await el.updateComplete;
21
+ expect(eventFired).to.be.true;
22
+ });
23
+ it('Has link to item download page', async () => {
24
+ const el = await fixture<IANoTheaterAvailable>(
25
+ html`<ia-no-theater-available
26
+ .identifier=${`foo`}
27
+ ></ia-no-theater-available>`
28
+ );
29
+ expect(el.downloadUrl).to.equal('/download/foo');
30
+ expect(el?.shadowRoot?.querySelector('a')?.href).to.contain(el.downloadUrl);
31
+ });
32
+ });