|
2 | 2 | // Use of this source code is governed by a BSD-style license that can be |
3 | 3 | // found in the LICENSE file. |
4 | 4 |
|
5 | | -import {dispatchClickEvent, dispatchKeyDownEvent, renderElementIntoDOM} from '../../../testing/DOMHelpers.js'; |
6 | 5 | import { |
7 | 6 | describeWithEnvironment, |
8 | 7 | setupActionRegistry, |
9 | 8 | } from '../../../testing/EnvironmentHelpers.js'; |
10 | | -import * as RenderCoordinator from '../../../ui/components/render_coordinator/render_coordinator.js'; |
| 9 | +import { |
| 10 | + createViewFunctionStub, |
| 11 | + type ViewFunctionStub, |
| 12 | +} from '../../../testing/ViewFunctionHelpers.js'; |
11 | 13 |
|
12 | 14 | import * as Components from './components.js'; |
13 | 15 |
|
14 | 16 | describeWithEnvironment('RecordingListView', () => { |
15 | 17 | setupActionRegistry(); |
16 | 18 |
|
17 | | - it('should open a recording on Enter', async () => { |
18 | | - const view = new Components.RecordingListView.RecordingListView(); |
19 | | - renderElementIntoDOM(view); |
20 | | - view.recordings = [{storageName: 'storage-test', name: 'test'}]; |
21 | | - await RenderCoordinator.done(); |
22 | | - const recording = view.shadowRoot?.querySelector('.row') as HTMLDivElement; |
23 | | - assert.isOk(recording); |
24 | | - const eventSent = new Promise<Components.RecordingListView.OpenRecordingEvent>( |
25 | | - resolve => { |
26 | | - view.addEventListener('openrecording', resolve, {once: true}); |
27 | | - }, |
28 | | - ); |
29 | | - dispatchKeyDownEvent(recording, {key: 'Enter'}); |
30 | | - const event = await eventSent; |
31 | | - assert.strictEqual(event.storageName, 'storage-test'); |
| 19 | + const views: Components.RecordingListView.RecordingListView[] = []; |
| 20 | + |
| 21 | + afterEach(() => { |
| 22 | + // Unregister global listeners in willHide to prevent leaks. |
| 23 | + for (const view of views) { |
| 24 | + view.willHide(); |
| 25 | + } |
32 | 26 | }); |
33 | 27 |
|
34 | | - it('should delete a recording', async () => { |
35 | | - const view = new Components.RecordingListView.RecordingListView(); |
36 | | - renderElementIntoDOM(view); |
37 | | - view.recordings = [{storageName: 'storage-test', name: 'test'}]; |
38 | | - await RenderCoordinator.done(); |
39 | | - const deleteButton = view.shadowRoot?.querySelector( |
40 | | - '.delete-recording-button', |
41 | | - ) as HTMLButtonElement; |
42 | | - assert.isOk(deleteButton); |
43 | | - const eventSent = new Promise<Components.RecordingListView.DeleteRecordingEvent>( |
44 | | - resolve => { |
45 | | - view.addEventListener('deleterecording', resolve, {once: true}); |
46 | | - }, |
47 | | - ); |
48 | | - dispatchClickEvent(deleteButton); |
49 | | - const event = await eventSent; |
50 | | - assert.strictEqual(event.storageName, 'storage-test'); |
| 28 | + async function createView(output?: Components.RecordingListView.ViewOutput): Promise<[ |
| 29 | + ViewFunctionStub<typeof Components.RecordingListView.RecordingListView>, |
| 30 | + Components.RecordingListView.RecordingListView |
| 31 | + ]> { |
| 32 | + const view = createViewFunctionStub(Components.RecordingListView.RecordingListView, output); |
| 33 | + const component = new Components.RecordingListView.RecordingListView(undefined, view); |
| 34 | + component.recordings = [{storageName: 'storage-test', name: 'test'}]; |
| 35 | + component.replayAllowed = true; |
| 36 | + component.wasShown(); |
| 37 | + views.push(component); |
| 38 | + return [view, component]; |
| 39 | + } |
| 40 | + |
| 41 | + it('should open a recording on Enter', async () => { |
| 42 | + const [view, component] = await createView(); |
| 43 | + const dispatchEventSpy = sinon.spy(component.contentElement, 'dispatchEvent'); |
| 44 | + |
| 45 | + view.input.onKeyDown('storage-test', new KeyboardEvent('keydown', {key: 'Enter'})); |
| 46 | + |
| 47 | + sinon.assert.calledOnce(dispatchEventSpy); |
| 48 | + const event = dispatchEventSpy.firstCall.args[0]; |
| 49 | + assert.instanceOf(event, Components.RecordingListView.OpenRecordingEvent); |
| 50 | + assert.strictEqual((event as Components.RecordingListView.OpenRecordingEvent).storageName, 'storage-test'); |
51 | 51 | }); |
52 | 52 |
|
53 | | - it('should not open a recording on Enter on the delete button', async () => { |
54 | | - const view = new Components.RecordingListView.RecordingListView(); |
55 | | - renderElementIntoDOM(view); |
56 | | - view.recordings = [{storageName: 'storage-test', name: 'test'}]; |
57 | | - await RenderCoordinator.done(); |
58 | | - const deleteButton = view.shadowRoot?.querySelector( |
59 | | - '.delete-recording-button', |
60 | | - ) as HTMLDivElement; |
61 | | - assert.isOk(deleteButton); |
62 | | - const {resolve: forceResolve, promise: eventSent} = |
63 | | - Promise.withResolvers<Components.RecordingListView.OpenRecordingEvent|void>(); |
| 53 | + it('should delete a recording', async () => { |
| 54 | + const [view, component] = await createView(); |
| 55 | + const dispatchEventSpy = sinon.spy(component.contentElement, 'dispatchEvent'); |
64 | 56 |
|
65 | | - view.addEventListener('openrecording', forceResolve, {once: true}); |
| 57 | + view.input.onDeleteClick('storage-test', new MouseEvent('click')); |
66 | 58 |
|
67 | | - dispatchKeyDownEvent(deleteButton, {key: 'Enter', bubbles: true}); |
68 | | - const maybeEvent = await Promise.race([ |
69 | | - eventSent, |
70 | | - new Promise(resolve => queueMicrotask(() => resolve('timeout'))), |
71 | | - ]); |
72 | | - assert.strictEqual(maybeEvent, 'timeout'); |
73 | | - forceResolve(); |
| 59 | + sinon.assert.calledOnce(dispatchEventSpy); |
| 60 | + const event = dispatchEventSpy.firstCall.args[0]; |
| 61 | + assert.instanceOf(event, Components.RecordingListView.DeleteRecordingEvent); |
| 62 | + assert.strictEqual((event as Components.RecordingListView.DeleteRecordingEvent).storageName, 'storage-test'); |
74 | 63 | }); |
75 | 64 | }); |
0 commit comments