Skip to content

Improve targeting devtools panel iframe created by an extension #4247

@antross

Description

@antross

Filing as the workaround listed in #3699 wasn't sufficient to target content inside the iframe created for a devtools extension panel. I was able to eventually get this working, but it required accessing private APIs (as did the workaround in #3699) so I'd like to see this scenario improved and officially supported.

Here's what it took:


✔ Good: Installing the extension and opening the devtools on a page of my choosing works well.

    const browser = await launch({
        args: [
            `--disable-extensions-except=${pathToExtension}`,
            `--load-extension=${pathToExtension}`
        ],
        defaultViewport: null,
        devtools: true,
        headless: false
    });

    const page = (await browser.pages())[0];

    await page.goto(url);

⚠ Issue 1: Getting a puppeteer Page pointing to the devtools requires some URL-matching and a hack as the Target type is other (this could be loaded in a separate browser tab as described in #3699, but that also requires accessing private data).

    const targets = await browser.targets();
    const devtoolsTarget = targets.filter((t) => {
        return t.type() === 'other' && t.url().startsWith('chrome-devtools://');
    })[0];

    // Hack to get a page pointing to the devtools
    devtoolsTarget._targetInfo.type = 'page';

    const devtoolsPage = await devtoolsTarget.page();

🙏 Proposal 1: Expose the devtools as a known target type that can return a Page.

    const targets = await browser.targets();
    const devtoolsTarget = targets.filter((t) => t.type() === 'devtools')[0];
    const devtoolsPage = await devtoolsTarget.page();

✔ Good: Activating the extension devtools tab so it's iframe gets created is awkward, but at least this uses public APIs. It takes advantage of keyboard shortcuts as suggested in #3699 - though I'm iterating just once in reverse as the extension is always the last tab.

    await devtoolsPage.keyboard.down('Control');
    await devtoolsPage.keyboard.press('[');
    await devtoolsPage.keyboard.up('Control');

⚠ Issue 2: At this point the example in #3699 shows how to get a reference to the tab element in the devtools, but that is outside of the extension panel's iframe and I want to debug the content inside the frame. Unfortunately devtoolsPage.frames() doesn't contain the extension panel frame, but I was able to work around this because the panel did appear in browser.targets().

    const targets = await browser.targets();
    const extensionPanelTarget = targets.filter((t) => {
        return t.type() === 'other' &&
            t.url().startsWith('chrome-extension://') &&
            t.url().endsWith('/panel.html');
    })[0];

    // Hack to get a page pointing to the devtools extension panel.
    extensionPanelTarget._targetInfo.type = 'page';

    // Most APIs on `Page` fail as `mainFrame()` is `undefined` (frame has a `parentId`).
    const extensionPanelPage = await extensionPanelTarget.page();

    // Getting the first frame and working with that instead provides something usable.
    const extensionPanelFrame = extensionPanelPage.frames()[0];

    // And now we can finally interact with our extension panel frame!
    extensionPanelFrame.click(selector);

🙏 Proposal 2: Fix returning the extension panel frame in devtoolsPage.frames():

    const extensionPanelFrame = devtoolsPage.frames().filter((frame) => {
        return frame.url().startsWith('chrome-extension://') &&
            frame.url().endsWith('/panel.html');
    })[0];

    extensionPanelFrame.click(selector);

Let me know if you'd prefer to have the proposals split into two separate issues. I wanted to present them together initially for context on what it took to interact with a devtools extension panel and to better help anyone else who may be trying to do the same.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions