chrome-devtools-frontend
Version:
Chrome DevTools UI
260 lines (238 loc) • 11.7 kB
text/typescript
// Copyright 2022 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';
const TARGET_ID = 'TARGET_ID' as Protocol.Target.TargetID;
const TITLE = 'TITLE';
let nextTargetId = 0;
function createTargetInfo(targetId?: string, type?: string, url?: string, title?: string) {
return {
targetId: (targetId ?? String(++nextTargetId)) as Protocol.Target.TargetID,
type: type ?? 'page',
title: title ?? '',
url: url ?? 'http://example.com',
attached: true,
canAccessOpener: true,
};
}
let nextSessionId = 0;
function createSessionId() {
return ('SESSION_ID' + ++nextSessionId) as Protocol.Target.SessionID;
}
describeWithMockConnection('ChildTargetManager', () => {
it('adds subtargets', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget(
{sessionId: createSessionId(), targetInfo: createTargetInfo(TARGET_ID), waitingForDebugger: false});
assert.lengthOf(childTargetManager.childTargets(), 1);
assert.strictEqual(childTargetManager.childTargets()[0].id(), TARGET_ID);
});
it('sets subtarget type', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
for (const [protocolType, sdkType] of [
['iframe', SDK.Target.Type.FRAME],
['webview', SDK.Target.Type.FRAME],
['page', SDK.Target.Type.FRAME],
['background_page', SDK.Target.Type.FRAME],
['app', SDK.Target.Type.FRAME],
['popup_page', SDK.Target.Type.FRAME],
['worker', SDK.Target.Type.Worker],
['shared_worker', SDK.Target.Type.SHARED_WORKER],
['service_worker', SDK.Target.Type.ServiceWorker],
['auction_worklet', SDK.Target.Type.AUCTION_WORKLET],
['browser', SDK.Target.Type.BROWSER],
]) {
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, protocolType),
waitingForDebugger: false,
});
const [subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), sdkType);
}
});
it('sets subtarget to frame for devtools scheme if type is other', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'other', 'devtools://foo/bar'),
waitingForDebugger: false,
});
let [subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.FRAME);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'worker', 'devtools://foo/bar'),
waitingForDebugger: false,
});
[subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.Worker);
});
it('sets subtarget to frame for chrome://print/ if type is other', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'other', 'chrome://print/'),
waitingForDebugger: false,
});
const [subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.FRAME);
});
it('sets subtarget to frame for chrome://file-manager/ if type is other', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'other', 'chrome://file-manager/?%7B%22allowedPaths%22:%22anyPathOrUrl'),
waitingForDebugger: false,
});
const [subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.FRAME);
});
it('sets subtarget to frame for sidebar URLs if type is other', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'other', 'chrome://read-later.top-chrome/'),
waitingForDebugger: false,
});
let [subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.FRAME);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'other', 'chrome://booksmarks-side-panel.top-chrome/'),
waitingForDebugger: false,
});
[subtarget] = childTargetManager.childTargets().slice(-1);
assert.strictEqual(subtarget.type(), SDK.Target.Type.FRAME);
});
it('sets worker target name to the target title', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'worker', 'http://example.com/worker.js', TITLE),
waitingForDebugger: false,
});
assert.strictEqual(childTargetManager.childTargets()[0].name(), TITLE);
});
it('sets non-frame target name to the last path component if present', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'service_worker', 'http://example.org/service_worker.html', TITLE),
waitingForDebugger: false,
});
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'worker', 'http://example.com/worker.js'),
waitingForDebugger: false,
});
assert.strictEqual(childTargetManager.childTargets()[0].name(), 'service_worker.html');
assert.strictEqual(childTargetManager.childTargets()[1].name(), 'worker.js');
});
it('sets non-frame target a numbered name if it cannot use URL path', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
assert.lengthOf(childTargetManager.childTargets(), 0);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'page', 'data:text/html,<!doctype html>'),
waitingForDebugger: false,
});
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'iframe', 'data:text/html,<!doctype html>'),
waitingForDebugger: false,
});
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'webview', 'data:text/html,<!doctype html>'),
waitingForDebugger: false,
});
// The targets above are frames and should not be given a numbered named
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo:
createTargetInfo(undefined, 'service_worker', 'data:application/javascript;console.log("Service Worker")'),
waitingForDebugger: false,
});
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo(undefined, 'worker', 'data:application/javascript;console.log("Worker")'),
waitingForDebugger: false,
});
assert.strictEqual(childTargetManager.childTargets()[3].name(), '#1');
assert.strictEqual(childTargetManager.childTargets()[4].name(), '#2');
});
it('calls attach callback', async () => {
const target = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(target);
const attachCallback = sinon.spy();
SDK.ChildTargetManager.ChildTargetManager.install(attachCallback);
await childTargetManager.attachedToTarget(
{sessionId: createSessionId(), targetInfo: createTargetInfo(TARGET_ID), waitingForDebugger: false});
assert.isTrue(attachCallback.calledOnce);
assert.strictEqual(attachCallback.firstCall.firstArg.target.id(), TARGET_ID);
assert.isFalse(attachCallback.firstCall.firstArg.waitingForDebugger);
const OTHER_TARGET_ID = 'OTHER_TARGET_ID' as Protocol.Target.TargetID;
await childTargetManager.attachedToTarget(
{sessionId: createSessionId(), targetInfo: createTargetInfo(OTHER_TARGET_ID), waitingForDebugger: true});
assert.isTrue(attachCallback.calledTwice);
assert.strictEqual(attachCallback.secondCall.firstArg.target.id(), OTHER_TARGET_ID);
assert.isTrue(attachCallback.secondCall.firstArg.waitingForDebugger);
});
it('marks the target as crashed when it crashes', async () => {
const parentTarget = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(parentTarget);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo('child-target-id'),
waitingForDebugger: false,
});
const target = childTargetManager.childTargets().at(0);
assert.isDefined(target);
assert.strictEqual(target.id(), 'child-target-id');
childTargetManager.targetCrashed(
{targetId: target.id() as Protocol.Target.TargetID, status: 'crashed', errorCode: 1});
assert.isTrue(target.hasCrashed());
});
it('"un-crashes" a target when the target info message is received', async () => {
const parentTarget = createTarget();
const childTargetManager = new SDK.ChildTargetManager.ChildTargetManager(parentTarget);
await childTargetManager.attachedToTarget({
sessionId: createSessionId(),
targetInfo: createTargetInfo('child-target-id'),
waitingForDebugger: false,
});
const target = childTargetManager.childTargets().at(0);
assert.isDefined(target);
assert.strictEqual(target.id(), 'child-target-id');
childTargetManager.targetCrashed(
{targetId: target.id() as Protocol.Target.TargetID, status: 'crashed', errorCode: 1});
assert.isTrue(target.hasCrashed());
childTargetManager.targetInfoChanged({targetInfo: createTargetInfo(target.id())});
assert.isFalse(target.hasCrashed());
});
});