blob: f5733b2cae7e3c94d632a14298dd82e26ef8fef0 [file] [log] [blame]
// Copyright 2026 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 Platform from '../../core/platform/platform.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as Protocol from '../../generated/protocol.js';
import * as Bindings from '../../models/bindings/bindings.js';
import * as Workspace from '../../models/workspace/workspace.js';
import {dispatchClickEvent, renderElementIntoDOM} from '../../testing/DOMHelpers.js';
import {
createTarget,
describeWithEnvironment,
} from '../../testing/EnvironmentHelpers.js';
import {debuggerCallFrame, protocolCallFrame} from '../../testing/StackTraceHelpers.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as Sources from './sources.js';
function getPausedDetails() {
const target = createTarget();
const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
assert.exists(debuggerModel);
const scriptId = 'scriptId' as Protocol.Runtime.ScriptId;
const url = Platform.DevToolsPath.urlString`http://example.com/script.js`;
const script = debuggerModel.parsedScriptSource(
scriptId, url, 0, 0, 0, 0, 0, '', undefined, false, undefined, false, false, 0, null, null, null, null, null,
null, null);
const syncCallFrame = debuggerCallFrame(`${url}:${scriptId}:testFunction:0:0`);
const asyncCallFrame = protocolCallFrame(`${url}:${scriptId}:asyncParent:5:2`);
const details = new SDK.DebuggerModel.DebuggerPausedDetails(
debuggerModel, [syncCallFrame], Protocol.Debugger.PausedEventReason.Other, {}, [],
{description: 'setTimeout', callFrames: [asyncCallFrame]});
return {details, debuggerModel, script};
}
describeWithEnvironment('CallStackSidebarPane', () => {
beforeEach(() => {
const workspace = Workspace.Workspace.WorkspaceImpl.instance();
const targetManager = SDK.TargetManager.TargetManager.instance();
const resourceMapping = new Bindings.ResourceMapping.ResourceMapping(targetManager, workspace);
const ignoreListManager = Workspace.IgnoreListManager.IgnoreListManager.instance({forceNew: true});
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
forceNew: true,
resourceMapping,
targetManager,
ignoreListManager,
workspace,
});
});
it('updates call stack sidebar pane and activates item when SourceMapAttached event fires and SourcesPanel is active',
async () => {
const {details, debuggerModel, script} = getPausedDetails();
const callStackSidebarPane = Sources.CallStackSidebarPane.CallStackSidebarPane.instance({forceNew: true});
await callStackSidebarPane.flavorChanged(details);
const setSelectedCallFrameSpy = sinon.spy(debuggerModel, 'setSelectedCallFrame');
UI.Context.Context.instance().setFlavor(
Sources.SourcesPanel.SourcesPanel, sinon.createStubInstance(Sources.SourcesPanel.SourcesPanel));
UI.Context.Context.instance().setFlavor(Sources.SourcesPanel.QuickSourceView, null);
const mockSourceMap = sinon.createStubInstance(SDK.SourceMap.SourceMap);
mockSourceMap.sourceURLs.returns([]);
debuggerModel.sourceMapManager().dispatchEventToListeners(SDK.SourceMapManager.Events.SourceMapAttached, {
client: script,
sourceMap: mockSourceMap,
});
await callStackSidebarPane.updateComplete;
sinon.assert.called(setSelectedCallFrameSpy);
});
it('updates call stack sidebar pane and activates item when SourceMapAttached event fires and QuickSourceView is active',
async () => {
const {details, debuggerModel, script} = getPausedDetails();
const callStackSidebarPane = Sources.CallStackSidebarPane.CallStackSidebarPane.instance({forceNew: true});
await callStackSidebarPane.flavorChanged(details);
const setSelectedCallFrameSpy = sinon.spy(debuggerModel, 'setSelectedCallFrame');
UI.Context.Context.instance().setFlavor(Sources.SourcesPanel.SourcesPanel, null);
UI.Context.Context.instance().setFlavor(
Sources.SourcesPanel.QuickSourceView, sinon.createStubInstance(Sources.SourcesPanel.QuickSourceView));
const mockSourceMap = sinon.createStubInstance(SDK.SourceMap.SourceMap);
mockSourceMap.sourceURLs.returns([]);
debuggerModel.sourceMapManager().dispatchEventToListeners(SDK.SourceMapManager.Events.SourceMapAttached, {
client: script,
sourceMap: mockSourceMap,
});
await callStackSidebarPane.updateComplete;
sinon.assert.called(setSelectedCallFrameSpy);
});
it('does not activate item when SourceMapAttached event fires and no view is active', async () => {
const {details, debuggerModel, script} = getPausedDetails();
const callStackSidebarPane = Sources.CallStackSidebarPane.CallStackSidebarPane.instance({forceNew: true});
await callStackSidebarPane.flavorChanged(details);
const setSelectedCallFrameSpy = sinon.spy(debuggerModel, 'setSelectedCallFrame');
UI.Context.Context.instance().setFlavor(Sources.SourcesPanel.SourcesPanel, null);
UI.Context.Context.instance().setFlavor(Sources.SourcesPanel.QuickSourceView, null);
const mockSourceMap = sinon.createStubInstance(SDK.SourceMap.SourceMap);
mockSourceMap.sourceURLs.returns([]);
debuggerModel.sourceMapManager().dispatchEventToListeners(SDK.SourceMapManager.Events.SourceMapAttached, {
client: script,
sourceMap: mockSourceMap,
});
await callStackSidebarPane.updateComplete;
sinon.assert.notCalled(setSelectedCallFrameSpy);
});
it('reveals UILocation for frames in async fragments', async () => {
const {details} = getPausedDetails();
const callStackSidebarPane = Sources.CallStackSidebarPane.CallStackSidebarPane.instance({forceNew: true});
renderElementIntoDOM(callStackSidebarPane);
await callStackSidebarPane.flavorChanged(details);
await callStackSidebarPane.updateComplete;
const items = callStackSidebarPane.contentElement.querySelectorAll('.call-frame-item');
assert.lengthOf(items, 3); // sync frame, async description, async frame
const revealSpy = sinon.spy(Common.Revealer.RevealerRegistry.instance(), 'reveal');
dispatchClickEvent(items[2], {bubbles: true});
sinon.assert.calledOnceWithMatch(revealSpy, (location: unknown) => {
return location instanceof Workspace.UISourceCode.UILocation && location.lineNumber === 5 &&
location.columnNumber === 2;
});
callStackSidebarPane.detach();
});
});