chrome-devtools-frontend
Version:
Chrome DevTools UI
229 lines (194 loc) • 9.83 kB
text/typescript
// Copyright 2023 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 * as Platform from '../../core/platform/platform.js';
import * as SDK from '../../core/sdk/sdk.js';
import type * as Protocol from '../../generated/protocol.js';
import {createTarget} from '../../testing/EnvironmentHelpers.js';
import {
describeWithMockConnection,
} from '../../testing/MockConnection.js';
import {MockProtocolBackend} from '../../testing/MockScopeChain.js';
import {createFileSystemFileForPersistenceTests} from '../../testing/PersistenceHelpers.js';
import {
createContentProviderUISourceCode,
createFileSystemUISourceCode,
} from '../../testing/UISourceCodeHelpers.js';
import * as Bindings from '../bindings/bindings.js';
import * as Breakpoints from '../breakpoints/breakpoints.js';
import * as Persistence from '../persistence/persistence.js';
import * as Workspace from '../workspace/workspace.js';
const {urlString} = Platform.DevToolsPath;
describeWithMockConnection('PersistenceImpl', () => {
const FILE_SYSTEM_BREAK_ID = 'BREAK_ID' as Protocol.Debugger.BreakpointId;
const FILE_SYSTEM_SCRIPT_ID = 'FILE_SYSTEM_SCRIPT' as Protocol.Runtime.ScriptId;
const NETWORK_BREAKPOINT_ID = 'BREAKPOINT_ID';
let backend: MockProtocolBackend;
let target: SDK.Target.Target;
let breakpointManager: Breakpoints.BreakpointManager.BreakpointManager;
const DEFAULT_BREAKPOINT:
[Breakpoints.BreakpointManager.UserCondition, boolean, boolean, Breakpoints.BreakpointManager.BreakpointOrigin] =
[
Breakpoints.BreakpointManager.EMPTY_BREAKPOINT_CONDITION,
true, // enabled
false, // isLogpoint
Breakpoints.BreakpointManager.BreakpointOrigin.OTHER,
];
const SCRIPT_DESCRIPTION = {
url: urlString`http://www.google.com/script.js`,
content: 'console.log(1);\nconsole.log(2);\n',
startLine: 0,
startColumn: 0,
hasSourceURL: false,
};
beforeEach(() => {
backend = new MockProtocolBackend();
target = createTarget();
const workspace = Workspace.Workspace.WorkspaceImpl.instance();
const targetManager = SDK.TargetManager.TargetManager.instance();
const resourceMapping = new Bindings.ResourceMapping.ResourceMapping(targetManager, workspace);
const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
forceNew: true,
resourceMapping,
targetManager,
});
Bindings.IgnoreListManager.IgnoreListManager.instance({forceNew: true, debuggerWorkspaceBinding});
breakpointManager = Breakpoints.BreakpointManager.BreakpointManager.instance(
{forceNew: true, targetManager, workspace, debuggerWorkspaceBinding});
Persistence.Persistence.PersistenceImpl.instance({forceNew: true, workspace, breakpointManager});
});
async function setBreakpointOnFileSystem(
fileSystemUiSourceCode: Workspace.UISourceCode.UISourceCode, breakpointLine: number) {
const fileSystemBreakpointResponse =
backend.responderToBreakpointByUrlRequest(fileSystemUiSourceCode.url(), breakpointLine)({
breakpointId: FILE_SYSTEM_BREAK_ID,
locations: [
{
scriptId: FILE_SYSTEM_SCRIPT_ID,
lineNumber: breakpointLine,
columnNumber: 0,
},
],
});
// Set the breakpoint on the file system uiSourceCode.
await breakpointManager.setBreakpoint(fileSystemUiSourceCode, breakpointLine, 0, ...DEFAULT_BREAKPOINT);
await fileSystemBreakpointResponse;
}
async function attachNetworkScript(breakpointLine: number) {
const script = await backend.addScript(target, SCRIPT_DESCRIPTION, null);
const uiSourceCode =
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().uiSourceCodeForScript(script);
assert.exists(uiSourceCode);
// Set the breakpoint response for our upcoming request to set the breakpoint on the network file.
await backend.responderToBreakpointByUrlRequest(script.sourceURL, breakpointLine)({
breakpointId: NETWORK_BREAKPOINT_ID as Protocol.Debugger.BreakpointId,
locations: [
{
scriptId: script.scriptId,
lineNumber: breakpointLine,
columnNumber: 0,
},
],
});
return uiSourceCode;
}
function assertBreakLocationUiSourceCodes(uiSourceCodes: Workspace.UISourceCode.UISourceCode[]) {
const locations = breakpointManager.allBreakpointLocations();
assert.deepEqual(locations.map(loc => loc.uiLocation.uiSourceCode), uiSourceCodes);
}
it('moves breakpoint from file system uiSourceCode to the network uiSourceCode when binding is created', async () => {
const fileSystemPath = urlString`file://path/to/filesystem`;
const fileSystemFileUrl = urlString`${fileSystemPath + '/script.js'}`;
const {uiSourceCode: fileSystemUiSourceCode, project} = createFileSystemFileForPersistenceTests(
{
fileSystemPath,
fileSystemFileUrl,
type: Persistence.PlatformFileSystem.PlatformFileSystemType.WORKSPACE_PROJECT
},
SCRIPT_DESCRIPTION.url, SCRIPT_DESCRIPTION.content, target);
const breakpointLine = 0;
// Set the breakpoint response for our upcoming request.
await setBreakpointOnFileSystem(fileSystemUiSourceCode, breakpointLine);
// We should only have one breakpoint location: the one on the file system.
assertBreakLocationUiSourceCodes([fileSystemUiSourceCode]);
// Add the script.
const networkUiSourceCode = await attachNetworkScript(breakpointLine);
// We should only have one breakpoint location: the one on the network.
assertBreakLocationUiSourceCodes([networkUiSourceCode]);
project.dispose();
assertBreakLocationUiSourceCodes([networkUiSourceCode]);
});
it('copies breakpoint from network uiSourceCode to the file system uiSourceCode when binding is removed ',
async () => {
const fileSystemPath = urlString`file://path/to/filesystem`;
const fileSystemFileUrl = urlString`${fileSystemPath + '/script.js'}`;
const {uiSourceCode: fileSystemUiSourceCode, project} = createFileSystemFileForPersistenceTests(
{
fileSystemPath,
fileSystemFileUrl,
type: Persistence.PlatformFileSystem.PlatformFileSystemType.WORKSPACE_PROJECT
},
SCRIPT_DESCRIPTION.url, SCRIPT_DESCRIPTION.content, target);
const breakpointLine = 0;
// Set the breakpoint response for our upcoming request.
await setBreakpointOnFileSystem(fileSystemUiSourceCode, breakpointLine);
// We should only have one breakpoint location: the one on the file system.
assertBreakLocationUiSourceCodes([fileSystemUiSourceCode]);
// Add the script.
const networkUiSourceCode = await attachNetworkScript(breakpointLine);
// We should only have one breakpoint location: the one on the network.
assertBreakLocationUiSourceCodes([networkUiSourceCode]);
// Prepare to remove the binding. This will cause the breakpoint from the network to be copied
// over to the file system uiSourceCode.
const persistence = Persistence.Persistence.PersistenceImpl.instance();
const binding = persistence.binding(fileSystemUiSourceCode);
assert.exists(binding);
// Set the breakpoint response for our upcoming request on the file system.
const moveResponse = backend.responderToBreakpointByUrlRequest(fileSystemUiSourceCode.url(), breakpointLine)({
breakpointId: FILE_SYSTEM_BREAK_ID,
locations: [
{
scriptId: FILE_SYSTEM_SCRIPT_ID,
lineNumber: breakpointLine,
columnNumber: 0,
},
],
});
await persistence.removeBinding(binding);
await moveResponse;
assertBreakLocationUiSourceCodes([networkUiSourceCode, fileSystemUiSourceCode]);
project.dispose();
});
// Replaces web test: http/tests/devtools/persistence/automapping-bind-committed-network-sourcecode.js
it('it marks the filesystem UISourceCode dirty when the network UISourceCode was committed before the binding was established',
async () => {
const url = urlString`https://example.com/script.js`;
const origContent = 'window.foo = () => "foo";\n';
const {uiSourceCode: networkUISourceCode} = createContentProviderUISourceCode({
url,
content: origContent,
mimeType: 'text/javascript',
projectType: Workspace.Workspace.projectTypes.Network,
metadata: new Workspace.UISourceCode.UISourceCodeMetadata(null, origContent.length),
});
// Modify the content of the network UISourceCode.
const content = origContent.replace(/foo/g, 'bar');
networkUISourceCode.addRevision(content);
// Add a filesystem version of 'script.js' with the original content.
const mappingPromise =
Persistence.Persistence.PersistenceImpl.instance().once(Persistence.Persistence.Events.BindingCreated);
const localUrl = urlString`file:///var/www/script.js`;
const {uiSourceCode} = createFileSystemUISourceCode({
url: localUrl,
mimeType: 'text/javascript',
content: origContent,
autoMapping: true,
metadata: new Workspace.UISourceCode.UISourceCodeMetadata(null, origContent.length),
});
const {network, fileSystem} = await mappingPromise;
assert.strictEqual(network, networkUISourceCode);
assert.strictEqual(fileSystem, uiSourceCode);
assert.isTrue(fileSystem.isDirty());
assert.strictEqual(fileSystem.workingCopy(), content);
});
});