|
| 1 | +import { errorLibraryNotInitialized } from '../../src/internal/constants'; |
| 2 | +import { GlobalVars } from '../../src/internal/globalVars'; |
| 3 | +import { ApiName } from '../../src/internal/telemetry'; |
| 4 | +import * as app from '../../src/public/app/app'; |
| 5 | +import { errorNotSupportedOnPlatform, FrameContexts } from '../../src/public/constants'; |
| 6 | +import * as mouseRelay from '../../src/public/mouseRelay'; |
| 7 | +import { latestRuntimeApiVersion } from '../../src/public/runtime'; |
| 8 | +import { Utils } from '../utils'; |
| 9 | + |
| 10 | +const BACK_BUTTON = 3; // X1 |
| 11 | +const FORWARD_BUTTON = 4; // X2 |
| 12 | + |
| 13 | +describe('mouseRelay capability', () => { |
| 14 | + describe('frameless', () => { |
| 15 | + let utils: Utils = new Utils(); |
| 16 | + beforeEach(() => { |
| 17 | + utils = new Utils(); |
| 18 | + utils.mockWindow.parent = undefined; |
| 19 | + utils.messages = []; |
| 20 | + GlobalVars.isFramelessWindow = false; |
| 21 | + }); |
| 22 | + afterEach(() => { |
| 23 | + app._uninitialize?.(); |
| 24 | + }); |
| 25 | + |
| 26 | + describe('isSupported()', () => { |
| 27 | + it('returns false when runtime says it is not supported', async () => { |
| 28 | + await utils.initializeWithContext(FrameContexts.content); |
| 29 | + utils.setRuntimeConfig({ apiVersion: 1, supports: {} }); |
| 30 | + expect(mouseRelay.isSupported()).toBeFalsy(); |
| 31 | + }); |
| 32 | + |
| 33 | + it('returns true when runtime says it is supported', async () => { |
| 34 | + await utils.initializeWithContext(FrameContexts.content); |
| 35 | + utils.setRuntimeConfig({ apiVersion: 1, supports: { mouseRelay: {} } }); |
| 36 | + expect(mouseRelay.isSupported()).toBeTruthy(); |
| 37 | + }); |
| 38 | + |
| 39 | + it('throws before initialization', () => { |
| 40 | + utils.uninitializeRuntimeConfig(); |
| 41 | + expect(() => mouseRelay.isSupported()).toThrowError(new Error(errorLibraryNotInitialized)); |
| 42 | + }); |
| 43 | + }); |
| 44 | + |
| 45 | + describe('enableMouseRelayCapability()', () => { |
| 46 | + it('should reject before initialization', async () => { |
| 47 | + await expect(mouseRelay.enableMouseRelayCapability()).rejects.toThrowError( |
| 48 | + new Error(errorLibraryNotInitialized), |
| 49 | + ); |
| 50 | + }); |
| 51 | + |
| 52 | + it('should reject when capability not supported in runtime', async () => { |
| 53 | + await utils.initializeWithContext(FrameContexts.content); |
| 54 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: {} }); |
| 55 | + |
| 56 | + await expect(mouseRelay.enableMouseRelayCapability()).rejects.toEqual(errorNotSupportedOnPlatform); |
| 57 | + }); |
| 58 | + |
| 59 | + it('forwards { direction: back } to host on the back (X1) button mouseup', async () => { |
| 60 | + await utils.initializeWithContext(FrameContexts.content); |
| 61 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: { mouseRelay: {} } }); |
| 62 | + |
| 63 | + await mouseRelay.enableMouseRelayCapability(); |
| 64 | + |
| 65 | + document.body.dispatchEvent( |
| 66 | + new MouseEvent('mouseup', { button: BACK_BUTTON, bubbles: true, cancelable: true }), |
| 67 | + ); |
| 68 | + |
| 69 | + const fwd = utils.findMessageByFunc(ApiName.MouseRelay_ForwardNavigation); |
| 70 | + expect(fwd).not.toBeNull(); |
| 71 | + expect(fwd?.args?.[0]).toEqual({ direction: 'back' }); |
| 72 | + }); |
| 73 | + |
| 74 | + it('forwards { direction: forward } to host on the forward (X2) button mouseup', async () => { |
| 75 | + await utils.initializeWithContext(FrameContexts.content); |
| 76 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: { mouseRelay: {} } }); |
| 77 | + |
| 78 | + await mouseRelay.enableMouseRelayCapability(); |
| 79 | + |
| 80 | + document.body.dispatchEvent( |
| 81 | + new MouseEvent('mouseup', { button: FORWARD_BUTTON, bubbles: true, cancelable: true }), |
| 82 | + ); |
| 83 | + |
| 84 | + const fwd = utils.findMessageByFunc(ApiName.MouseRelay_ForwardNavigation); |
| 85 | + expect(fwd?.args?.[0]).toEqual({ direction: 'forward' }); |
| 86 | + }); |
| 87 | + |
| 88 | + it('suppresses native nav on mousedown but forwards only on release (mouseup)', async () => { |
| 89 | + await utils.initializeWithContext(FrameContexts.content); |
| 90 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: { mouseRelay: {} } }); |
| 91 | + |
| 92 | + await mouseRelay.enableMouseRelayCapability(); |
| 93 | + |
| 94 | + const down = new MouseEvent('mousedown', { button: BACK_BUTTON, bubbles: true, cancelable: true }); |
| 95 | + document.body.dispatchEvent(down); |
| 96 | + |
| 97 | + expect(down.defaultPrevented).toBe(true); // suppressed early |
| 98 | + expect(utils.findMessageByFunc(ApiName.MouseRelay_ForwardNavigation)).toBeNull(); // not yet |
| 99 | + }); |
| 100 | + |
| 101 | + it('ignores non-navigation mouse buttons', async () => { |
| 102 | + await utils.initializeWithContext(FrameContexts.content); |
| 103 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: { mouseRelay: {} } }); |
| 104 | + |
| 105 | + await mouseRelay.enableMouseRelayCapability(); |
| 106 | + |
| 107 | + const evt = new MouseEvent('mouseup', { button: 0, bubbles: true, cancelable: true }); |
| 108 | + document.body.dispatchEvent(evt); |
| 109 | + |
| 110 | + expect(utils.findMessageByFunc(ApiName.MouseRelay_ForwardNavigation)).toBeNull(); |
| 111 | + expect(evt.defaultPrevented).toBe(false); |
| 112 | + }); |
| 113 | + }); |
| 114 | + |
| 115 | + describe('resetIsMouseRelayCapabilityEnabled()', () => { |
| 116 | + it('detaches the listeners so events stop forwarding', async () => { |
| 117 | + await utils.initializeWithContext(FrameContexts.content); |
| 118 | + utils.setRuntimeConfig({ apiVersion: latestRuntimeApiVersion, supports: { mouseRelay: {} } }); |
| 119 | + |
| 120 | + await mouseRelay.enableMouseRelayCapability(); |
| 121 | + mouseRelay.resetIsMouseRelayCapabilityEnabled(); |
| 122 | + utils.messages = []; |
| 123 | + |
| 124 | + document.body.dispatchEvent( |
| 125 | + new MouseEvent('mouseup', { button: BACK_BUTTON, bubbles: true, cancelable: true }), |
| 126 | + ); |
| 127 | + |
| 128 | + expect(utils.findMessageByFunc(ApiName.MouseRelay_ForwardNavigation)).toBeNull(); |
| 129 | + }); |
| 130 | + }); |
| 131 | + }); |
| 132 | +}); |
0 commit comments