UNPKG

chrome-devtools-frontend

Version:
129 lines (112 loc) 5.26 kB
// Copyright 2024 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import type * as Protocol from '../../generated/protocol.js'; import {createTarget} from '../../testing/EnvironmentHelpers.js'; import {describeWithMockConnection} from '../../testing/MockConnection.js'; import * as SDK from './sdk.js'; describeWithMockConnection('SourceMapScopeRemoteObject', () => { let callFrame: sinon.SinonStubbedInstance<SDK.DebuggerModel.CallFrame>; beforeEach(() => { callFrame = sinon.createStubInstance(SDK.DebuggerModel.CallFrame); const target = createTarget(); callFrame.debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel)!; }); it('returns "value unavailable" for unavailable scope variables', async () => { const originalScope: SDK.SourceMapScopes.OriginalScope = { start: {line: 0, column: 0}, end: {line: 20, column: 0}, isStackFrame: false, kind: 'global', variables: ['variable1', 'variable2'], children: [], }; const entry = new SDK.SourceMapScopeChainEntry.SourceMapScopeChainEntry( callFrame, originalScope, undefined, false, undefined); const {properties} = await entry.object().getAllProperties(/* accessorPropertiesOnly */ false, /* generatePreview */ true); assert.isNotNull(properties); assert.lengthOf(properties, 2); assert.strictEqual(properties[0].name, 'variable1'); assert.isUndefined(properties[0].value); assert.strictEqual(properties[1].name, 'variable2'); assert.isUndefined(properties[1].value); }); it('resolves variable values using binding expressions and evaluateOnCallFrame', async () => { const originalScope: SDK.SourceMapScopes.OriginalScope = { start: {line: 0, column: 0}, end: {line: 20, column: 0}, isStackFrame: false, kind: 'global', variables: ['variable1'], children: [], }; const range: SDK.SourceMapScopes.GeneratedRange = { start: {line: 0, column: 0}, end: {line: 0, column: 200}, isStackFrame: false, isHidden: false, values: ['a'], children: [], }; callFrame.location.returns( new SDK.DebuggerModel.Location(callFrame.debuggerModel, '0' as Protocol.Runtime.ScriptId, 0, 50)); callFrame.evaluate.callsFake(({expression}) => { assert.strictEqual(expression, 'a'); return Promise.resolve({object: new SDK.RemoteObject.LocalJSONObject(42)}); }); const entry = new SDK.SourceMapScopeChainEntry.SourceMapScopeChainEntry(callFrame, originalScope, range, false, undefined); const {properties} = await entry.object().getAllProperties(/* accessorPropertiesOnly */ false, /* generatePreview */ true); assert.isNotNull(properties); assert.lengthOf(properties, 1); assert.strictEqual(properties[0].name, 'variable1'); assert.strictEqual(properties[0].value?.value, 42); }); it('uses the right binding expression when resolving variable values when ranges are split', async () => { const originalScope: SDK.SourceMapScopes.OriginalScope = { start: {line: 0, column: 0}, end: {line: 20, column: 0}, isStackFrame: false, kind: 'global', variables: ['variable1'], children: [], }; const range: SDK.SourceMapScopes.GeneratedRange = { start: {line: 0, column: 0}, end: {line: 0, column: 200}, isStackFrame: false, isHidden: false, values: [[ {from: {line: 0, column: 0}, to: {line: 0, column: 50}, value: 'a'}, // From 0..50 available as 'a'. {from: {line: 0, column: 50}, to: {line: 0, column: 150}}, // From 50..150 unavailable. {from: {line: 0, column: 150}, to: {line: 0, column: 200}, value: 'b'}, // From 150..200 available as 'b'. ]], children: [], }; // We simulate 3 pauses in the 3 sub-ranges. const pauseLocations = [ new SDK.DebuggerModel.Location(callFrame.debuggerModel, '0' as Protocol.Runtime.ScriptId, 0, 25), new SDK.DebuggerModel.Location(callFrame.debuggerModel, '0' as Protocol.Runtime.ScriptId, 0, 100), new SDK.DebuggerModel.Location(callFrame.debuggerModel, '0' as Protocol.Runtime.ScriptId, 0, 175), ]; const expectedExpressions = ['a', 'does not matter since it must not be called', 'b']; const values = [42, undefined, 21]; for (let i = 0; i < 3; ++i) { callFrame.location.returns(pauseLocations[i]); callFrame.evaluate.callsFake(({expression}) => { assert.strictEqual(expression, expectedExpressions[i]); return Promise.resolve({object: new SDK.RemoteObject.LocalJSONObject(values[i])}); }); const entry = new SDK.SourceMapScopeChainEntry.SourceMapScopeChainEntry(callFrame, originalScope, range, false, undefined); const {properties} = await entry.object().getAllProperties(/* accessorPropertiesOnly */ false, /* generatePreview */ true); assert.isNotNull(properties); assert.lengthOf(properties, 1); assert.strictEqual(properties[0].name, 'variable1'); assert.strictEqual(properties[0].value?.value, values[i]); } }); });