| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as Common from '../../core/common/common.js'; |
| import * as Host from '../../core/host/host.js'; |
| import {expectCalled} from '../../testing/ExpectStubCall.js'; |
| import {getVeId} from '../../testing/VisualLoggingHelpers.js'; |
| |
| import * as VisualLogging from './visual_logging-testing.js'; |
| |
| describe('LoggingEvents', () => { |
| let parent: Element; |
| let element: Element; |
| let veid: number; |
| let throttler: Common.Throttler.Throttler; |
| |
| beforeEach(() => { |
| parent = document.createElement('div'); |
| element = document.createElement('div'); |
| VisualLogging.LoggingState.getOrCreateLoggingState(parent, {ve: 1}); |
| VisualLogging.LoggingState.getOrCreateLoggingState(element, {ve: 1, context: '42'}, parent); |
| veid = getVeId(element); |
| throttler = new Common.Throttler.Throttler(1000000); |
| }); |
| |
| afterEach(async () => { |
| await throttler.schedule(async () => {}, Common.Throttler.Scheduling.AS_SOON_AS_POSSIBLE); |
| }); |
| |
| async function assertThrottled(stub: sinon.SinonStub) { |
| await new Promise(resolve => setTimeout(resolve, 0)); |
| sinon.assert.notCalled(stub); |
| await throttler.process?.(); |
| sinon.assert.calledOnce(stub); |
| } |
| |
| it('calls UI binding to log an impression', async () => { |
| const recordImpression = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordImpression', |
| ); |
| await VisualLogging.LoggingEvents.logImpressions([element, parent]); |
| sinon.assert.calledOnce(recordImpression); |
| assert.sameDeepMembers(recordImpression.firstCall.firstArg.impressions, [ |
| {id: veid, type: 1, context: 42, parent: getVeId(parent), height: 0, width: 0}, |
| {id: getVeId(parent), type: 1, height: 0, width: 0}, |
| ]); |
| }); |
| |
| it('calls UI binding to log a click', async () => { |
| const recordClick = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordClick', |
| ); |
| // @ts-expect-error |
| const event = new MouseEvent('click', {button: 0, sourceCapabilities: new InputDeviceCapabilities()}); |
| VisualLogging.LoggingEvents.logClick(throttler)(element, event); |
| await assertThrottled(recordClick); |
| assert.deepEqual(recordClick.firstCall.firstArg, {veid, mouseButton: 0, doubleClick: false}); |
| }); |
| |
| it('does not set mouse button for synthetic clicks', async () => { |
| const recordClick = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordClick', |
| ); |
| const event = new MouseEvent('click', {button: 0}); |
| VisualLogging.LoggingEvents.logClick(throttler)(element, event); |
| await assertThrottled(recordClick); |
| assert.deepEqual(recordClick.firstCall.firstArg, {veid, doubleClick: false}); |
| }); |
| |
| it('calls UI binding to log a double click', async () => { |
| const recordClick = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordClick', |
| ); |
| const event = new MouseEvent('dblclick', {button: 1}); |
| VisualLogging.LoggingEvents.logClick(throttler)(element, event, {doubleClick: true}); |
| await assertThrottled(recordClick); |
| assert.deepEqual(recordClick.firstCall.firstArg, {veid, doubleClick: true}); |
| }); |
| |
| it('calls UI binding to log a change', async () => { |
| const recordChange = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordChange', |
| ); |
| await VisualLogging.LoggingEvents.logChange(element); |
| sinon.assert.calledOnce(recordChange); |
| assert.deepEqual(recordChange.firstCall.firstArg, {veid}); |
| }); |
| |
| it('calls UI binding to log a change of specific type', async () => { |
| const recordChange = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordChange', |
| ); |
| VisualLogging.LoggingState.getLoggingState(element)!.pendingChangeContext = 'instertText'; |
| await VisualLogging.LoggingEvents.logChange(element); |
| sinon.assert.calledOnce(recordChange); |
| assert.deepEqual(recordChange.firstCall.firstArg, {veid, context: 296063892}); |
| }); |
| |
| it('calls UI binding to log a keydown with any code', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown'); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| await assertThrottled(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid}); |
| }); |
| |
| it('calls UI binding to log a keydown with a matching code', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Enter', key: 'Enter'}); |
| VisualLogging.LoggingState.getLoggingState(element)!.config.track = {keydown: 'Enter|Escape'}; |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| await assertThrottled(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid, context: 513111094}); |
| }); |
| |
| it('calls UI binding to log a keydown with a matching key', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Period', key: '>'}); |
| VisualLogging.LoggingState.getLoggingState(element)!.config.track = {keydown: '>'}; |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| await assertThrottled(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid: getVeId(element), context: -1098575095}); |
| }); |
| |
| it('calls UI binding to log a keydown with an provided context', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Enter'}); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event, '21'); |
| await assertThrottled(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid, context: 21}); |
| }); |
| |
| it('throttles subsequent keydowns', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Enter'}); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| await assertThrottled(recordKeyDown); |
| }); |
| |
| it('does not drop keydowns with a specific context', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Enter'}); |
| sinon.stub(event, 'currentTarget').value(element); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event, '1'); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event, '2'); |
| await new Promise(resolve => setTimeout(resolve, 0)); |
| sinon.assert.calledOnce(recordKeyDown); |
| await throttler.process?.(); |
| sinon.assert.calledTwice(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid, context: 1}); |
| assert.deepEqual(recordKeyDown.secondCall.firstArg, {veid, context: 2}); |
| }); |
| |
| it('throttles subsequent keydowns with the same context', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'Enter'}); |
| sinon.stub(event, 'currentTarget').value(element); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event, '1'); |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event, '1'); |
| await assertThrottled(recordKeyDown); |
| assert.deepEqual(recordKeyDown.firstCall.firstArg, {veid, context: 1}); |
| }); |
| |
| it('does not call UI binding to log a keydown with a non-matching code', async () => { |
| const recordKeyDown = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordKeyDown', |
| ); |
| const event = new KeyboardEvent('keydown', {code: 'KeyQ'}); |
| VisualLogging.LoggingState.getLoggingState(element)!.config.track = {keydown: 'Enter|Escape'}; |
| void VisualLogging.LoggingEvents.logKeyDown(throttler)(element, event); |
| sinon.assert.notCalled(recordKeyDown); |
| }); |
| |
| it('calls UI binding to log a hover event', async () => { |
| const recordHover = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordHover', |
| ); |
| const event = new MouseEvent('click', {button: 1}); |
| sinon.stub(event, 'currentTarget').value(element); |
| void VisualLogging.LoggingEvents.logHover(new Common.Throttler.Throttler(0))(event); |
| await expectCalled(recordHover); |
| assert.deepEqual(recordHover.firstCall.firstArg, {veid}); |
| }); |
| |
| it('calls UI binding to log a drag event', async () => { |
| const recordDrag = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordDrag', |
| ); |
| const event = new MouseEvent('click', {button: 1}); |
| sinon.stub(event, 'currentTarget').value(element); |
| void VisualLogging.LoggingEvents.logDrag(throttler)(event); |
| await assertThrottled(recordDrag); |
| assert.deepEqual(recordDrag.firstCall.firstArg, {veid}); |
| }); |
| |
| it('calls UI binding to log a resize event', async () => { |
| const recordResize = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordResize', |
| ); |
| VisualLogging.LoggingEvents.logResize(element, new DOMRect(0, 0, 100, 50)); |
| assert.deepEqual(recordResize.firstCall.firstArg, {veid, width: 100, height: 50}); |
| }); |
| |
| it('throttles calls UI binding to log a resize event', async () => { |
| const recordResize = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordResize', |
| ); |
| VisualLogging.LoggingEvents.logResize(element, new DOMRect(0, 0, 100, 50)); |
| assert.deepEqual(recordResize.firstCall.firstArg, {veid, width: 100, height: 50}); |
| }); |
| |
| it('calls UI binding to log a setting access event', async () => { |
| const recordSettingAccess = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordSettingAccess', |
| ); |
| await VisualLogging.LoggingEvents.logSettingAccess('test-setting', 'test-value'); |
| assert.deepEqual( |
| recordSettingAccess.lastCall.firstArg, {name: -1361026584, numeric_value: undefined, string_value: 856719891}); |
| |
| await VisualLogging.LoggingEvents.logSettingAccess('test-setting', 123); |
| assert.deepEqual( |
| recordSettingAccess.lastCall.firstArg, {name: -1361026584, numeric_value: 123, string_value: undefined}); |
| }); |
| |
| it('calls UI binding to log a function call event', async () => { |
| const recordFunctionCall = sinon.stub( |
| Host.InspectorFrontendHost.InspectorFrontendHostInstance, |
| 'recordFunctionCall', |
| ); |
| await VisualLogging.LoggingEvents.logFunctionCall('test-function', 'test-context'); |
| assert.deepEqual(recordFunctionCall.lastCall.firstArg, {name: -1470917656, context: 617717214}); |
| |
| await VisualLogging.LoggingEvents.logFunctionCall('test-function'); |
| assert.deepEqual(recordFunctionCall.lastCall.firstArg, {name: -1470917656, context: undefined}); |
| }); |
| }); |