feat: just enough //extensions to load a simple devtools extension (#19515)
This commit is contained in:
parent
9c1310dadc
commit
55368e4d97
14 changed files with 250 additions and 14 deletions
|
@ -1034,6 +1034,13 @@ void AtomBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
|
||||||
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
|
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
|
||||||
api::Protocol* protocol = api::Protocol::FromWrappedClass(
|
api::Protocol* protocol = api::Protocol::FromWrappedClass(
|
||||||
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
|
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
factories->emplace(
|
||||||
|
extensions::kExtensionScheme,
|
||||||
|
extensions::CreateExtensionNavigationURLLoaderFactory(
|
||||||
|
web_contents->GetBrowserContext(),
|
||||||
|
false /* we don't support extensions::WebViewGuest */));
|
||||||
|
#endif
|
||||||
if (protocol)
|
if (protocol)
|
||||||
protocol->RegisterURLLoaderFactories(factories);
|
protocol->RegisterURLLoaderFactories(factories);
|
||||||
}
|
}
|
||||||
|
@ -1042,6 +1049,13 @@ void AtomBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
||||||
int render_process_id,
|
int render_process_id,
|
||||||
int render_frame_id,
|
int render_frame_id,
|
||||||
NonNetworkURLLoaderFactoryMap* factories) {
|
NonNetworkURLLoaderFactoryMap* factories) {
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
|
||||||
|
render_frame_id);
|
||||||
|
if (factory)
|
||||||
|
factories->emplace(extensions::kExtensionScheme, std::move(factory));
|
||||||
|
#endif
|
||||||
|
|
||||||
// Chromium may call this even when NetworkService is not enabled.
|
// Chromium may call this even when NetworkService is not enabled.
|
||||||
content::RenderFrameHost* frame_host =
|
content::RenderFrameHost* frame_host =
|
||||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||||
|
|
|
@ -226,9 +226,6 @@ AtomBrowserMainParts::AtomBrowserMainParts(
|
||||||
electron_bindings_(new ElectronBindings(uv_default_loop())) {
|
electron_bindings_(new ElectronBindings(uv_default_loop())) {
|
||||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||||
self_ = this;
|
self_ = this;
|
||||||
// Register extension scheme as web safe scheme.
|
|
||||||
content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
|
|
||||||
"chrome-extension");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
|
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
|
||||||
#include "components/proxy_config/proxy_config_dictionary.h"
|
#include "components/proxy_config/proxy_config_dictionary.h"
|
||||||
#include "components/proxy_config/proxy_config_pref_names.h"
|
#include "components/proxy_config/proxy_config_pref_names.h"
|
||||||
|
#include "content/public/browser/child_process_security_policy.h"
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
|
#include "extensions/common/constants.h"
|
||||||
#include "net/proxy_resolution/proxy_config.h"
|
#include "net/proxy_resolution/proxy_config.h"
|
||||||
#include "net/proxy_resolution/proxy_config_service.h"
|
#include "net/proxy_resolution/proxy_config_service.h"
|
||||||
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
||||||
|
@ -89,6 +91,10 @@ void BrowserProcessImpl::PostEarlyInitialization() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BrowserProcessImpl::PreCreateThreads() {
|
void BrowserProcessImpl::PreCreateThreads() {
|
||||||
|
// chrome-extension:// URLs are safe to request anywhere, but may only
|
||||||
|
// commit (including in iframes) in extension processes.
|
||||||
|
content::ChildProcessSecurityPolicy::GetInstance()
|
||||||
|
->RegisterWebSafeIsolatedScheme(extensions::kExtensionScheme, true);
|
||||||
// Must be created before the IOThread.
|
// Must be created before the IOThread.
|
||||||
// Once IOThread class is no longer needed,
|
// Once IOThread class is no longer needed,
|
||||||
// this can be created on first use.
|
// this can be created on first use.
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
#include "extensions/browser/updater/null_extension_cache.h"
|
#include "extensions/browser/updater/null_extension_cache.h"
|
||||||
#include "extensions/browser/url_request_util.h"
|
#include "extensions/browser/url_request_util.h"
|
||||||
#include "extensions/common/features/feature_channel.h"
|
#include "extensions/common/features/feature_channel.h"
|
||||||
|
#include "extensions/common/manifest_constants.h"
|
||||||
|
#include "extensions/common/manifest_url_handlers.h"
|
||||||
|
#include "services/network/public/mojom/url_loader.mojom.h"
|
||||||
#include "shell/browser/atom_browser_client.h"
|
#include "shell/browser/atom_browser_client.h"
|
||||||
#include "shell/browser/atom_browser_context.h"
|
#include "shell/browser/atom_browser_context.h"
|
||||||
#include "shell/browser/browser.h"
|
#include "shell/browser/browser.h"
|
||||||
|
@ -31,9 +34,6 @@
|
||||||
#include "shell/browser/extensions/atom_extension_host_delegate.h"
|
#include "shell/browser/extensions/atom_extension_host_delegate.h"
|
||||||
#include "shell/browser/extensions/atom_extension_system_factory.h"
|
#include "shell/browser/extensions/atom_extension_system_factory.h"
|
||||||
#include "shell/browser/extensions/atom_extension_web_contents_observer.h"
|
#include "shell/browser/extensions/atom_extension_web_contents_observer.h"
|
||||||
// #include "shell/browser/extensions/atom_extensions_api_client.h"
|
|
||||||
// #include "shell/browser/extensions/atom_extensions_browser_api_provider.h"
|
|
||||||
#include "services/network/public/mojom/url_loader.mojom.h"
|
|
||||||
#include "shell/browser/extensions/atom_navigation_ui_data.h"
|
#include "shell/browser/extensions/atom_navigation_ui_data.h"
|
||||||
#include "shell/browser/extensions/electron_extensions_api_client.h"
|
#include "shell/browser/extensions/electron_extensions_api_client.h"
|
||||||
#include "shell/browser/extensions/electron_process_manager_delegate.h"
|
#include "shell/browser/extensions/electron_process_manager_delegate.h"
|
||||||
|
@ -139,6 +139,37 @@ void AtomExtensionsBrowserClient::LoadResourceFromResourceBundle(
|
||||||
NOTREACHED() << "Load resources from bundles not supported.";
|
NOTREACHED() << "Load resources from bundles not supported.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool AllowCrossRendererResourceLoad(const GURL& url,
|
||||||
|
content::ResourceType resource_type,
|
||||||
|
ui::PageTransition page_transition,
|
||||||
|
int child_id,
|
||||||
|
bool is_incognito,
|
||||||
|
const extensions::Extension* extension,
|
||||||
|
const extensions::ExtensionSet& extensions,
|
||||||
|
const extensions::ProcessMap& process_map,
|
||||||
|
bool* allowed) {
|
||||||
|
if (extensions::url_request_util::AllowCrossRendererResourceLoad(
|
||||||
|
url, resource_type, page_transition, child_id, is_incognito,
|
||||||
|
extension, extensions, process_map, allowed)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there aren't any explicitly marked web accessible resources, the
|
||||||
|
// load should be allowed only if it is by DevTools. A close approximation is
|
||||||
|
// checking if the extension contains a DevTools page.
|
||||||
|
if (extension && !extensions::ManifestURL::Get(
|
||||||
|
extension, extensions::manifest_keys::kDevToolsPage)
|
||||||
|
.is_empty()) {
|
||||||
|
*allowed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't determine if the resource is allowed or not.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
bool AtomExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
bool AtomExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
content::ResourceType resource_type,
|
content::ResourceType resource_type,
|
||||||
|
@ -149,7 +180,7 @@ bool AtomExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
||||||
const extensions::ExtensionSet& extensions,
|
const extensions::ExtensionSet& extensions,
|
||||||
const extensions::ProcessMap& process_map) {
|
const extensions::ProcessMap& process_map) {
|
||||||
bool allowed = false;
|
bool allowed = false;
|
||||||
if (extensions::url_request_util::AllowCrossRendererResourceLoad(
|
if (::electron::AllowCrossRendererResourceLoad(
|
||||||
url, resource_type, page_transition, child_id, is_incognito,
|
url, resource_type, page_transition, child_id, is_incognito,
|
||||||
extension, extensions, process_map, &allowed)) {
|
extension, extensions, process_map, &allowed)) {
|
||||||
return allowed;
|
return allowed;
|
||||||
|
|
|
@ -48,6 +48,16 @@
|
||||||
#include "ui/display/display.h"
|
#include "ui/display/display.h"
|
||||||
#include "ui/display/screen.h"
|
#include "ui/display/screen.h"
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
#include "content/public/browser/child_process_security_policy.h"
|
||||||
|
#include "content/public/browser/render_process_host.h"
|
||||||
|
#include "extensions/browser/extension_registry.h"
|
||||||
|
#include "extensions/common/manifest_constants.h"
|
||||||
|
#include "extensions/common/manifest_url_handlers.h"
|
||||||
|
#include "extensions/common/permissions/permissions_data.h"
|
||||||
|
#include "shell/browser/atom_browser_context.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -571,10 +581,51 @@ void InspectableWebContentsImpl::LoadCompleted() {
|
||||||
javascript, base::NullCallback());
|
javascript, base::NullCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
AddDevToolsExtensionsToClient();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (view_->GetDelegate())
|
if (view_->GetDelegate())
|
||||||
view_->GetDelegate()->DevToolsOpened();
|
view_->GetDelegate()->DevToolsOpened();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
void InspectableWebContentsImpl::AddDevToolsExtensionsToClient() {
|
||||||
|
// get main browser context
|
||||||
|
auto* browser_context = web_contents_->GetBrowserContext();
|
||||||
|
const extensions::ExtensionRegistry* registry =
|
||||||
|
extensions::ExtensionRegistry::Get(browser_context);
|
||||||
|
if (!registry)
|
||||||
|
return;
|
||||||
|
|
||||||
|
base::ListValue results;
|
||||||
|
for (auto& extension : registry->enabled_extensions()) {
|
||||||
|
auto devtools_page_url = extensions::ManifestURL::Get(
|
||||||
|
extension.get(), extensions::manifest_keys::kDevToolsPage);
|
||||||
|
if (devtools_page_url.is_empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Each devtools extension will need to be able to run in the devtools
|
||||||
|
// process. Grant the devtools process the ability to request URLs from the
|
||||||
|
// extension.
|
||||||
|
content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestOrigin(
|
||||||
|
web_contents_->GetMainFrame()->GetProcess()->GetID(),
|
||||||
|
url::Origin::Create(extension->url()));
|
||||||
|
|
||||||
|
std::unique_ptr<base::DictionaryValue> extension_info(
|
||||||
|
new base::DictionaryValue());
|
||||||
|
extension_info->SetString("startPage", devtools_page_url.spec());
|
||||||
|
extension_info->SetString("name", extension->name());
|
||||||
|
extension_info->SetBoolean("exposeExperimentalAPIs",
|
||||||
|
extension->permissions_data()->HasAPIPermission(
|
||||||
|
extensions::APIPermission::kExperimental));
|
||||||
|
results.Append(std::move(extension_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
CallClientFunction("DevToolsAPI.addExtensions", &results, NULL, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) {
|
void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) {
|
||||||
DevToolsContentsResizingStrategy strategy(rect);
|
DevToolsContentsResizingStrategy strategy(rect);
|
||||||
if (contents_resizing_strategy_.Equals(strategy))
|
if (contents_resizing_strategy_.Equals(strategy))
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "content/public/browser/devtools_frontend_host.h"
|
#include "content/public/browser/devtools_frontend_host.h"
|
||||||
#include "content/public/browser/web_contents_delegate.h"
|
#include "content/public/browser/web_contents_delegate.h"
|
||||||
#include "content/public/browser/web_contents_observer.h"
|
#include "content/public/browser/web_contents_observer.h"
|
||||||
|
#include "electron/buildflags/buildflags.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||||
#include "ui/gfx/geometry/rect.h"
|
#include "ui/gfx/geometry/rect.h"
|
||||||
|
|
||||||
|
@ -193,6 +194,10 @@ class InspectableWebContentsImpl
|
||||||
|
|
||||||
void SendMessageAck(int request_id, const base::Value* arg1);
|
void SendMessageAck(int request_id, const base::Value* arg1);
|
||||||
|
|
||||||
|
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||||
|
void AddDevToolsExtensionsToClient();
|
||||||
|
#endif
|
||||||
|
|
||||||
bool frontend_loaded_;
|
bool frontend_loaded_;
|
||||||
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
||||||
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
|
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
{
|
{
|
||||||
"content_scripts": {
|
"content_scripts": {
|
||||||
"channel": "stable",
|
"channel": "stable",
|
||||||
"extension_types": ["extension", "legacy_packaged_app"]
|
"extension_types": ["extension"]
|
||||||
|
},
|
||||||
|
"devtools_page": {
|
||||||
|
"channel": "stable",
|
||||||
|
"extension_types": ["extension"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,69 @@
|
||||||
|
|
||||||
#include "shell/common/extensions/atom_extensions_api_provider.h"
|
#include "shell/common/extensions/atom_extensions_api_provider.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "base/containers/span.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
|
#include "extensions/common/alias.h"
|
||||||
#include "extensions/common/features/json_feature_provider_source.h"
|
#include "extensions/common/features/json_feature_provider_source.h"
|
||||||
|
#include "extensions/common/manifest_constants.h"
|
||||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
#include "extensions/common/manifest_handler.h"
|
||||||
|
#include "extensions/common/manifest_handlers/permissions_parser.h"
|
||||||
|
#include "extensions/common/manifest_url_handlers.h"
|
||||||
|
#include "extensions/common/permissions/permissions_info.h"
|
||||||
#include "shell/common/extensions/api/manifest_features.h"
|
#include "shell/common/extensions/api/manifest_features.h"
|
||||||
#endif
|
|
||||||
|
namespace extensions {
|
||||||
|
|
||||||
|
namespace keys = manifest_keys;
|
||||||
|
namespace errors = manifest_errors;
|
||||||
|
|
||||||
|
// Parses the "devtools_page" manifest key.
|
||||||
|
class DevToolsPageHandler : public ManifestHandler {
|
||||||
|
public:
|
||||||
|
DevToolsPageHandler() = default;
|
||||||
|
~DevToolsPageHandler() override = default;
|
||||||
|
|
||||||
|
bool Parse(Extension* extension, base::string16* error) override {
|
||||||
|
std::unique_ptr<ManifestURL> manifest_url(new ManifestURL);
|
||||||
|
std::string devtools_str;
|
||||||
|
if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
|
||||||
|
*error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
manifest_url->url_ = extension->GetResourceURL(devtools_str);
|
||||||
|
extension->SetManifestData(keys::kDevToolsPage, std::move(manifest_url));
|
||||||
|
PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
base::span<const char* const> Keys() const override {
|
||||||
|
static constexpr const char* kKeys[] = {keys::kDevToolsPage};
|
||||||
|
return kKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(DevToolsPageHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
|
||||||
|
{APIPermission::kDevtools, "devtools",
|
||||||
|
APIPermissionInfo::kFlagImpliesFullURLAccess |
|
||||||
|
APIPermissionInfo::kFlagCannotBeOptional |
|
||||||
|
APIPermissionInfo::kFlagInternal},
|
||||||
|
};
|
||||||
|
base::span<const APIPermissionInfo::InitInfo> GetPermissionInfos() {
|
||||||
|
return base::make_span(permissions_to_register);
|
||||||
|
}
|
||||||
|
base::span<const Alias> GetPermissionAliases() {
|
||||||
|
return base::span<const Alias>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace extensions
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
@ -60,8 +115,16 @@ base::StringPiece AtomExtensionsAPIProvider::GetAPISchema(
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomExtensionsAPIProvider::RegisterPermissions(
|
void AtomExtensionsAPIProvider::RegisterPermissions(
|
||||||
extensions::PermissionsInfo* permissions_info) {}
|
extensions::PermissionsInfo* permissions_info) {
|
||||||
|
permissions_info->RegisterPermissions(extensions::GetPermissionInfos(),
|
||||||
|
extensions::GetPermissionAliases());
|
||||||
|
}
|
||||||
|
|
||||||
void AtomExtensionsAPIProvider::RegisterManifestHandlers() {}
|
void AtomExtensionsAPIProvider::RegisterManifestHandlers() {
|
||||||
|
extensions::ManifestHandlerRegistry* registry =
|
||||||
|
extensions::ManifestHandlerRegistry::Get();
|
||||||
|
registry->RegisterHandler(
|
||||||
|
std::make_unique<extensions::DevToolsPageHandler>());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { session, BrowserWindow, ipcMain } from 'electron'
|
import { session, BrowserWindow, ipcMain, WebContents } from 'electron'
|
||||||
import { closeAllWindows, closeWindow } from './window-helpers'
|
import { closeAllWindows, closeWindow } from './window-helpers'
|
||||||
import * as http from 'http'
|
import * as http from 'http'
|
||||||
import { AddressInfo } from 'net'
|
import { AddressInfo } from 'net'
|
||||||
|
@ -138,6 +138,45 @@ ifdescribe(process.electronBinding('features').isExtensionsEnabled())('chrome ex
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('devtools extensions', () => {
|
||||||
|
let showPanelTimeoutId: any = null
|
||||||
|
afterEach(() => {
|
||||||
|
if (showPanelTimeoutId) clearTimeout(showPanelTimeoutId)
|
||||||
|
})
|
||||||
|
const showLastDevToolsPanel = (w: BrowserWindow) => {
|
||||||
|
w.webContents.once('devtools-opened', () => {
|
||||||
|
const show = () => {
|
||||||
|
if (w == null || w.isDestroyed()) return
|
||||||
|
const { devToolsWebContents } = w as unknown as { devToolsWebContents: WebContents | undefined }
|
||||||
|
if (devToolsWebContents == null || devToolsWebContents.isDestroyed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const showLastPanel = () => {
|
||||||
|
// this is executed in the devtools context, where UI is a global
|
||||||
|
const { UI } = (window as any)
|
||||||
|
const lastPanelId = UI.inspectorView._tabbedPane._tabs.peekLast().id
|
||||||
|
UI.inspectorView.showPanel(lastPanelId)
|
||||||
|
}
|
||||||
|
devToolsWebContents.executeJavaScript(`(${showLastPanel})()`, false).then(() => {
|
||||||
|
showPanelTimeoutId = setTimeout(show, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
showPanelTimeoutId = setTimeout(show, 100)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it('loads a devtools extension', async () => {
|
||||||
|
const customSession = session.fromPartition(`persist:${require('uuid').v4()}`);
|
||||||
|
(customSession as any).loadExtension(path.join(fixtures, 'extensions', 'devtools-extension'))
|
||||||
|
const w = new BrowserWindow({ show: true, webPreferences: { session: customSession, nodeIntegration: true } })
|
||||||
|
await w.loadURL('data:text/html,hello')
|
||||||
|
w.webContents.openDevTools()
|
||||||
|
showLastDevToolsPanel(w)
|
||||||
|
await emittedOnce(ipcMain, 'winning')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
ifdescribe(!process.electronBinding('features').isExtensionsEnabled())('chrome extensions', () => {
|
ifdescribe(!process.electronBinding('features').isExtensionsEnabled())('chrome extensions', () => {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>foo</title>
|
||||||
|
<!-- can't be inline, because of CSP -->
|
||||||
|
<script src="foo.js"></script>
|
||||||
|
</head>
|
||||||
|
</html>
|
2
spec-main/fixtures/extensions/devtools-extension/foo.js
Normal file
2
spec-main/fixtures/extensions/devtools-extension/foo.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// eslint-disable-next-line
|
||||||
|
chrome.devtools.panels.create('Foo', 'icon.png', 'index.html')
|
|
@ -0,0 +1,5 @@
|
||||||
|
<!doctype html>
|
||||||
|
<body>
|
||||||
|
a custom devtools extension
|
||||||
|
<!-- can't be inline because of CSP -->
|
||||||
|
<script src="index.js"></script>
|
|
@ -0,0 +1,4 @@
|
||||||
|
// eslint-disable-next-line
|
||||||
|
chrome.devtools.inspectedWindow.eval(`require("electron").ipcRenderer.send("winning")`, (result, exc) => {
|
||||||
|
console.log(result, exc)
|
||||||
|
})
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "foo",
|
||||||
|
"version": "1.0",
|
||||||
|
"devtools_page": "foo.html",
|
||||||
|
"manifest_version": 2
|
||||||
|
}
|
Loading…
Reference in a new issue