diff --git a/packages/main/src/development-menu-builder.spec.ts b/packages/main/src/development-menu-builder.spec.ts new file mode 100644 index 0000000000000..e34ad0ecf2885 --- /dev/null +++ b/packages/main/src/development-menu-builder.spec.ts @@ -0,0 +1,69 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import { beforeEach } from 'node:test'; + +import type { BrowserWindow, ContextMenuParams, MenuItem } from 'electron'; +import { describe, expect, test, vi } from 'vitest'; + +import { buildDevelopmentMenu } from './development-menu-builder.js'; + +const browserWindow = { + webContents: { + send: vi.fn(), + }, +} as unknown as BrowserWindow; + +describe('Open DevTools Menu builder creates menu item for', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + test('/contribs/extension navigation', async () => { + const parameters: ContextMenuParams = { + linkURL: '/contribs/ExtensionId', + } as unknown as ContextMenuParams; + const menuItems = buildDevelopmentMenu(parameters, browserWindow, true); + expect(menuItems).toHaveLength(1); + expect(menuItems[0]).toHaveProperty('label'); + expect(menuItems[0]?.label).toBe('Open DevTools of ExtensionId Extension'); + expect(menuItems[0]?.click).toBeDefined(); + menuItems[0]!.click!(undefined as unknown as MenuItem, undefined, undefined as unknown as Electron.KeyboardEvent); + expect(browserWindow.webContents.send).toBeCalledWith('dev-tools:open-extension', 'ExtensionId'); + }); + + test('/webviews/WebviewId navigation', () => { + const parameters: ContextMenuParams = { + linkURL: '/webviews/WebviewId', + } as unknown as ContextMenuParams; + const menuItems = buildDevelopmentMenu(parameters, browserWindow, true); + expect(menuItems).toHaveLength(1); + expect(menuItems[0]).toHaveProperty('label'); + expect(menuItems[0]?.label).toBe(`Open DevTools of the webview`); + expect(menuItems[0]?.click).toBeDefined(); + menuItems[0]!.click!(undefined as unknown as MenuItem, undefined, undefined as unknown as Electron.KeyboardEvent); + expect(browserWindow.webContents.send).toBeCalledWith('dev-tools:open-webview', 'WebviewId'); + }); + + test('no menu created on other navigation items', () => { + const parameters: ContextMenuParams = { + linkURL: '/images', + } as unknown as ContextMenuParams; + const menuItems = buildDevelopmentMenu(parameters, browserWindow, true); + expect(menuItems).toHaveLength(0); + }); +}); diff --git a/packages/main/src/development-menu-builder.ts b/packages/main/src/development-menu-builder.ts new file mode 100644 index 0000000000000..3cf4838aa43d9 --- /dev/null +++ b/packages/main/src/development-menu-builder.ts @@ -0,0 +1,58 @@ +/********************************************************************** + * Copyright (C) 2024 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import type { BrowserWindow, ContextMenuParams, MenuItemConstructorOptions } from 'electron'; + +export function buildDevelopmentMenu( + parameters: ContextMenuParams, + browserWindow: BrowserWindow, + devMode: boolean, +): MenuItemConstructorOptions[] { + // In development mode, show the "Open DevTools of Extension and Webviews" menu item + if (devMode) { + let extensionId = ''; + if (parameters?.linkURL?.includes('/contribs')) { + const extensionIdVal = parameters.linkURL.split('/contribs/')[1]; + if (extensionIdVal) { + extensionId = extensionIdVal; + return [ + { + label: `Open DevTools of ${decodeURI(extensionId)} Extension`, + // make it visible when link contains contribs and we're inside the extension + visible: parameters.linkURL.includes('/contribs/'), + click: (): void => { + browserWindow.webContents.send('dev-tools:open-extension', extensionId.replaceAll('%20', '-')); + }, + }, + ]; + } + } else if (parameters?.linkURL?.includes('/webviews/')) { + const webviewId = parameters.linkURL.split('/webviews/')[1]; + return [ + { + label: `Open DevTools of the webview`, + visible: parameters.linkURL.includes('/webviews/'), + click: (): void => { + browserWindow.webContents.send('dev-tools:open-webview', webviewId); + }, + }, + ]; + } + } + return []; +} diff --git a/packages/main/src/mainWindow.ts b/packages/main/src/mainWindow.ts index 9c855cb29a62a..8f955b558e306 100644 --- a/packages/main/src/mainWindow.ts +++ b/packages/main/src/mainWindow.ts @@ -23,6 +23,7 @@ import type { BrowserWindowConstructorOptions, Rectangle } from 'electron'; import { app, autoUpdater, BrowserWindow, ipcMain, nativeTheme, screen } from 'electron'; import contextMenu from 'electron-context-menu'; +import { buildDevelopmentMenu } from './development-menu-builder.js'; import { NavigationItemsMenuBuilder } from './navigation-items-menu-builder.js'; import { OpenDevTools } from './open-dev-tools.js'; import type { ConfigurationRegistry } from './plugin/configuration-registry.js'; @@ -187,45 +188,7 @@ async function createWindow(): Promise { showInspectElement: import.meta.env.DEV, showServices: false, prepend: (_defaultActions, parameters) => { - // In development mode, show the "Open DevTools of Extension and Webviews" menu item - if (import.meta.env.DEV) { - let extensionId = ''; - if (parameters?.linkURL?.includes('/contribs')) { - const extensionIdVal = parameters.linkURL.split('/contribs/')[1]; - if (extensionIdVal) { - extensionId = extensionIdVal; - return [ - { - label: `Open DevTools of ${decodeURI(extensionId)} Extension`, - // make it visible when link contains contribs and we're inside the extension - visible: - parameters.linkURL.includes('/contribs/') && parameters.pageURL.includes(`/contribs/${extensionId}`), - click: (): void => { - browserWindow.webContents.send('dev-tools:open-extension', extensionId.replaceAll('%20', '-')); - }, - }, - ]; - } else { - return []; - } - } else if (parameters?.linkURL?.includes('/webviews/')) { - const webviewId = parameters.linkURL.split('/webviews/')[1]; - return [ - { - label: `Open DevTools of the webview`, - visible: - parameters.linkURL.includes('/webviews/') && parameters.pageURL.includes(`/webviews/${webviewId}`), - click: (): void => { - browserWindow.webContents.send('dev-tools:open-webview', webviewId); - }, - }, - ]; - } else { - return []; - } - } else { - return []; - } + return buildDevelopmentMenu(parameters, browserWindow, import.meta.env.DEV); }, append: (_defaultActions, parameters) => { return navigationItemsMenuBuilder?.buildNavigationMenu(parameters) ?? [];