From 14d01a40962dd89cf154c7e696fb8c9aef70fa4d Mon Sep 17 00:00:00 2001 From: toddtarsi Date: Sat, 30 Dec 2023 19:15:44 -0600 Subject: [PATCH] adding back plugin comm channel capabiltiy --- packages/selenium-ide/package.json | 2 +- .../src/browser/api/classes/EventListener.ts | 8 +++- .../browser/windows/PlaybackWindow/preload.ts | 43 +++++++++++-------- .../components/Drawer/EditorToolbar.tsx | 30 +++++++++++-- .../tabs/Project/ProjectSettings.tsx | 17 ++++++++ .../Tests/CommandFields/CommandSelector.tsx | 8 +++- .../tabs/Tests/CommandFields/LocatorField.tsx | 4 ++ .../tabs/Tests/CommandFields/TextField.tsx | 4 +- .../tabs/Tests/TestCommandEditor.tsx | 1 + .../tabs/Tests/TestCommandList.tsx | 7 ++- .../tabs/Tests/TestCommandListItem.tsx | 3 ++ .../tabs/Tests/TestCommandRow.tsx | 5 ++- .../tabs/Tests/TestCommandTable.tsx | 4 ++ .../ProjectEditor/tabs/Tests/TestsTab.tsx | 8 +++- .../windows/ProjectEditor/tabs/Tests/types.ts | 1 + packages/selenium-ide/src/main/api/index.ts | 7 +-- .../session/controllers/Channels/index.ts | 13 ++++++ .../main/session/controllers/Driver/bidi.ts | 6 +-- .../session/controllers/Playback/index.ts | 9 +++- .../main/session/controllers/Plugins/index.ts | 29 ++++++------- .../selenium-ide/src/main/session/index.ts | 2 + packages/selenium-ide/src/main/types.ts | 2 + packages/side-api/package.json | 2 +- .../side-api/src/commands/channels/index.ts | 18 ++++++++ .../side-api/src/commands/channels/onSend.ts | 6 +++ .../side-api/src/commands/channels/send.ts | 4 ++ .../side-api/src/commands/plugins/index.ts | 4 -- .../src/commands/recorder/getWinHandleId.ts | 2 +- packages/side-api/src/index.ts | 3 ++ packages/side-api/src/types/api.ts | 2 + packages/side-example-suite/package.json | 2 +- .../src/plugins/custom-click/index.ts | 9 ++++ .../src/plugins/custom-click/preload/index.ts | 3 ++ pnpm-lock.yaml | 4 +- 34 files changed, 208 insertions(+), 64 deletions(-) create mode 100644 packages/selenium-ide/src/main/session/controllers/Channels/index.ts create mode 100644 packages/side-api/src/commands/channels/index.ts create mode 100644 packages/side-api/src/commands/channels/onSend.ts create mode 100644 packages/side-api/src/commands/channels/send.ts diff --git a/packages/selenium-ide/package.json b/packages/selenium-ide/package.json index 9aa29565b..3f4f87393 100644 --- a/packages/selenium-ide/package.json +++ b/packages/selenium-ide/package.json @@ -111,7 +111,7 @@ "@seleniumhq/code-export-python-pytest": "^4.0.0-alpha.4", "@seleniumhq/code-export-ruby-rspec": "^4.0.0-alpha.3", "@seleniumhq/get-driver": "^4.0.0-alpha.3", - "@seleniumhq/side-api": "^4.0.0-alpha.40", + "@seleniumhq/side-api": "^4.0.0-alpha.41", "@seleniumhq/side-model": "^4.0.0-alpha.5", "@seleniumhq/side-runtime": "^4.0.0-alpha.33", "dnd-core": "^16.0.1", diff --git a/packages/selenium-ide/src/browser/api/classes/EventListener.ts b/packages/selenium-ide/src/browser/api/classes/EventListener.ts index 358d745c4..44f68e493 100644 --- a/packages/selenium-ide/src/browser/api/classes/EventListener.ts +++ b/packages/selenium-ide/src/browser/api/classes/EventListener.ts @@ -3,7 +3,7 @@ import { BaseListener, VariadicArgs } from '@seleniumhq/side-api' const baseListener = ( path: string -): BaseListener => { +): BaseListener & { emitEvent: (...args: ARGS) => void } => { const listeners: any[] = [] return { addListener(listener) { @@ -15,7 +15,11 @@ const baseListener = ( console.debug(path, 'dispatching event') const results = listeners.map((fn) => fn(...args)) ipcRenderer.send(`${path}.response`, results) - return results; + return results + }, + emitEvent(...args) { + console.debug(path, 'emitting event') + ipcRenderer.send(`${path}.emit`, ...args) }, hasListener(listener) { return listeners.includes(listener) diff --git a/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts b/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts index 91e345acb..e1a7f61c8 100644 --- a/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts +++ b/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts @@ -18,17 +18,23 @@ import { RecorderPreprocessor } from '@seleniumhq/side-api' import api from 'browser/api' import apiMutators from 'browser/api/mutator' import preload from 'browser/helpers/preload' -import {cb as ElectronCallback} from 'browser/helpers/preload-electron' +import { cb as ElectronCallback } from 'browser/helpers/preload-electron' import { webFrame } from 'electron' import Recorder from './preload/recorder' const recorderProcessors: RecorderPreprocessor[] = [] async function main() { - const preloads = await api.plugins.getPreloads() - for (const preload of preloads) { - eval(preload) - } window.addEventListener('DOMContentLoaded', async () => { + const preloads = await api.plugins.getPreloads() + for (const preload of preloads) { + try { + console.debug(`Loading preload: ${preload}`) + eval(preload) + console.debug(`Loaded preload!`) + } catch (e) { + console.error(`Error loading preload: ${preload}`, e) + } + } webFrame.executeJavaScript(` Object.defineProperty(navigator, 'webdriver', { get () { @@ -44,17 +50,20 @@ async function main() { }) } -preload(api, ElectronCallback, main)( - { - plugins: { - addRecorderPreprocessor: (fn) => { - recorderProcessors.push(fn) - }, - }, - recorder: api.recorder, - mutators: { - plugins: {}, - recorder: apiMutators.recorder, +preload( + api, + ElectronCallback, + main +)({ + channels: api.channels, + plugins: { + addRecorderPreprocessor: (fn) => { + recorderProcessors.push(fn) }, }, -) + recorder: api.recorder, + mutators: { + plugins: {}, + recorder: apiMutators.recorder, + }, +}) diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/components/Drawer/EditorToolbar.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/components/Drawer/EditorToolbar.tsx index 5d2af4036..10b304671 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/components/Drawer/EditorToolbar.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/components/Drawer/EditorToolbar.tsx @@ -8,6 +8,7 @@ import ListSubheader, { ListSubheaderProps } from '@mui/material/ListSubheader' import React, { FC } from 'react' interface EditorToolbarProps extends ListSubheaderProps { + disabled?: boolean onAdd?: () => void onEdit?: () => void onRemove?: () => void @@ -24,6 +25,7 @@ const standardIconProps = { const EditorToolbar: FC = ({ children, className = 'lh-36', + disabled = false, onAdd, onEdit, onRemove, @@ -41,7 +43,12 @@ const EditorToolbar: FC = ({ {onAdd ? ( - + @@ -50,7 +57,12 @@ const EditorToolbar: FC = ({ {onRemove ? ( - + @@ -59,7 +71,12 @@ const EditorToolbar: FC = ({ {onEdit ? ( - + @@ -68,7 +85,12 @@ const EditorToolbar: FC = ({ {onView ? ( - + diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Project/ProjectSettings.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Project/ProjectSettings.tsx index 6208787da..21e8f8ec8 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Project/ProjectSettings.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Project/ProjectSettings.tsx @@ -55,6 +55,23 @@ const ProjectSettings: FC = ({ value={project.url} /> + + { + update({ + delay: Math.max(parseInt(e.target.value || '0'), 0), + }) + }} + size="small" + value={project.delay || 0} + /> + = ({ command, commands, + disabled, isDisabled, testID, }) => { @@ -40,6 +41,7 @@ const CommandSelector: FC = ({ option.label} options={commandOptions} @@ -65,7 +67,10 @@ const CommandSelector: FC = ({ } a new window`} placement="top-end" > - setOpensWindow(!command.opensWindow)}> + setOpensWindow(!command.opensWindow)} + > @@ -75,6 +80,7 @@ const CommandSelector: FC = ({ placement="top-end" > setCommand(isDisabled ? command.command : `//${command.command}`) } diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/LocatorField.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/LocatorField.tsx index 74ec6eb81..5dadaed6d 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/LocatorField.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/LocatorField.tsx @@ -16,6 +16,7 @@ type PluralField = 'targets' | 'values' const CommandLocatorField: FC = ({ command, commands, + disabled, fieldName, testID, }) => { @@ -44,6 +45,7 @@ const CommandLocatorField: FC = ({ = ({ /> window.sideAPI.recorder.requestHighlightElement(fieldName) } @@ -88,6 +91,7 @@ const CommandLocatorField: FC = ({ window.sideAPI.recorder.requestSelectElement(true, fieldName) } diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/TextField.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/TextField.tsx index d5e824651..76c2667b8 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/TextField.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/CommandFields/TextField.tsx @@ -9,8 +9,9 @@ import Tooltip from '@mui/material/Tooltip' import { LocatorFields } from '@seleniumhq/side-api' const CommandTextField: FC = ({ - commands, command, + commands, + disabled, fieldName, note, testID, @@ -27,6 +28,7 @@ const CommandTextField: FC = ({ = ({ bottomOffset, commandStates, commands, + disabled = false, selectedCommandIndexes, }) => { const [preview, reorderPreview, resetPreview] = useReorderPreview( @@ -34,9 +36,10 @@ const CommandList: FC = ({ window.sideAPI.tests.addSteps( activeTest, @@ -52,6 +55,7 @@ const CommandList: FC = ({ ) : undefined } + sx={{ top: '48px', zIndex: 100 }} > Commands @@ -67,6 +71,7 @@ const CommandList: FC = ({ activeTest={activeTest} command={command} commandState={commandStates[id]} + disabled={disabled} key={id} index={index} reorderPreview={reorderPreview} diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandListItem.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandListItem.tsx index b8b724e65..e9d49bc6e 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandListItem.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandListItem.tsx @@ -31,6 +31,7 @@ interface CommandRowProps { activeTest: string commandState: PlaybackEventShapes['COMMAND_STATE_CHANGED'] command: CommandShape + disabled?: boolean index: number reorderPreview: ReorderPreview resetPreview: () => void @@ -54,6 +55,7 @@ const CommandRow: React.FC = ({ activeTest, commandState = defaultCommandState, command: { command, id, isBreakpoint, opensWindow, target, value }, + disabled = false, index, reorderPreview, resetPreview, @@ -93,6 +95,7 @@ const CommandRow: React.FC = ({ secondaryAction={ diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandRow.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandRow.tsx index ab78bd277..3c97bf342 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandRow.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandRow.tsx @@ -61,6 +61,7 @@ interface CommandRowProps { activeTest: string commandState: PlaybackEventShapes['COMMAND_STATE_CHANGED'] command: CommandShape + disabled?: boolean index: number reorderPreview: ReorderPreview resetPreview: () => void @@ -81,6 +82,7 @@ const CommandRow: React.FC = ({ activeTest, commandState = {}, command: { command, comment, id, isBreakpoint, target, value }, + disabled = false, index, reorderPreview, resetPreview, @@ -133,6 +135,7 @@ const CommandRow: React.FC = ({ secondaryAction={ @@ -191,7 +194,7 @@ const CommandRow: React.FC = ({ {value} - {commandState.message && ( + {'message' in commandState && ( {commandState.message} diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandTable.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandTable.tsx index c7fc41868..60d9ece8e 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandTable.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestCommandTable.tsx @@ -13,6 +13,7 @@ export interface CommandListProps { bottomOffset: number commands: CommandShape[] commandStates: CommandsStateShape + disabled?: boolean selectedCommandIndexes: number[] } @@ -23,6 +24,7 @@ const CommandList: FC = ({ bottomOffset, commandStates, commands, + disabled, selectedCommandIndexes, }) => { const [preview, reorderPreview, resetPreview] = useReorderPreview( @@ -33,6 +35,7 @@ const CommandList: FC = ({ useKeyboundNav(commands, selectedCommandIndexes) return ( = ({ activeTest={activeTest} command={command} commandState={commandStates[id]} + disabled={disabled} key={id} index={index} reorderPreview={reorderPreview} diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestsTab.tsx b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestsTab.tsx index 2a52456cb..e88a94252 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestsTab.tsx +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/TestsTab.tsx @@ -1,5 +1,8 @@ import Paper from '@mui/material/Paper' -import { getActiveCommand, getActiveTest } from '@seleniumhq/side-api/dist/helpers/getActiveData' +import { + getActiveCommand, + getActiveTest, +} from '@seleniumhq/side-api/dist/helpers/getActiveData' import { useHeightFromElement } from 'browser/helpers/useHeightFromElement' import React from 'react' import CommandEditor from './TestCommandEditor' @@ -42,6 +45,7 @@ const TestsTab: React.FC<{ const activeTest = getActiveTest(session) const activeCommand = getActiveCommand(session) + const disabled = ['playing', 'recording'].includes(session.state.status) return ( <> @@ -50,6 +54,7 @@ const TestsTab: React.FC<{ bottomOffset={bottomOffset} commands={activeTest.commands} commandStates={playback.commands} + disabled={disabled} selectedCommandIndexes={selectedCommandIndexes} /> diff --git a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/types.ts b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/types.ts index 6576f2e84..c387ded33 100644 --- a/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/types.ts +++ b/packages/selenium-ide/src/browser/windows/ProjectEditor/tabs/Tests/types.ts @@ -4,6 +4,7 @@ import { CoreSessionData, LocatorFields } from '@seleniumhq/side-api' export interface CommandEditorProps { command: CommandShape commands: CoreSessionData['state']['commands'] + disabled?: boolean testID: string } diff --git a/packages/selenium-ide/src/main/api/index.ts b/packages/selenium-ide/src/main/api/index.ts index a0450323a..d13c53b5a 100644 --- a/packages/selenium-ide/src/main/api/index.ts +++ b/packages/selenium-ide/src/main/api/index.ts @@ -17,12 +17,7 @@ export type MainApi = { ? MainListener : Api[NS][K] } -} & { - recorder: { - getWinHandleId: Session['recorder']['getWinHandleId'] - getFrameLocation: Session['recorder']['getFrameLocation'] - } -} +} & typeof overrides export default (session: Session): MainApi => ({ ...processApi((path, handler) => { diff --git a/packages/selenium-ide/src/main/session/controllers/Channels/index.ts b/packages/selenium-ide/src/main/session/controllers/Channels/index.ts new file mode 100644 index 000000000..ad0e21e67 --- /dev/null +++ b/packages/selenium-ide/src/main/session/controllers/Channels/index.ts @@ -0,0 +1,13 @@ +import BaseController from '../Base' + +/** + * This holds on to all commands currently in the command map. + * It's primarily instrumented by loading plugins + */ +export default class ChannelsController extends BaseController { + async send(channel: string, ...args: any[]) { + await this.session.api.channels.onSend.dispatchEvent(channel, ...args) + } + // This needs to build after plugins + priority = 5 +} diff --git a/packages/selenium-ide/src/main/session/controllers/Driver/bidi.ts b/packages/selenium-ide/src/main/session/controllers/Driver/bidi.ts index 3c8b87476..9168e3045 100644 --- a/packages/selenium-ide/src/main/session/controllers/Driver/bidi.ts +++ b/packages/selenium-ide/src/main/session/controllers/Driver/bidi.ts @@ -36,10 +36,10 @@ export const createBidiAPIBindings = async ( [], false ) - const pluginPreloads = await session.plugins.listPreloadPaths() - pluginPreloads.forEach(async (preloadPath) => { + const pluginPreloads = await session.plugins.getPreloads() + pluginPreloads.forEach(async (preload) => { await scriptManager.addPreloadScript( - (await readFile(preloadPath, 'utf-8')) as any, + (await readFile(preload, 'utf-8')) as any, [], null ) diff --git a/packages/selenium-ide/src/main/session/controllers/Playback/index.ts b/packages/selenium-ide/src/main/session/controllers/Playback/index.ts index 07be84cec..81ab4033d 100644 --- a/packages/selenium-ide/src/main/session/controllers/Playback/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Playback/index.ts @@ -174,7 +174,14 @@ export default class PlaybackController extends BaseController { } } else { playback = this.playbacks[0] - await this.claimPlaybackWindow(playback) + try { + await this.claimPlaybackWindow(playback) + } catch (e) { + // playback has become invalid + this.playbacks.splice(this.playbacks.indexOf(playback), 1) + await playback.cleanup() + playback = await this.getPlayback(testID) + } } return playback } diff --git a/packages/selenium-ide/src/main/session/controllers/Plugins/index.ts b/packages/selenium-ide/src/main/session/controllers/Plugins/index.ts index 3ceab0819..f4d9b6c8d 100644 --- a/packages/selenium-ide/src/main/session/controllers/Plugins/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Plugins/index.ts @@ -25,7 +25,18 @@ export default class PluginsController extends BaseController { } async getPreloads() { - const preloadPaths = (await this.listPreloadPaths()) + const plugins = await this.list() + const preloadPaths = plugins.map((pluginPath) => { + const actualPluginPath = __non_webpack_require__.resolve(pluginPath) + const preloadPath = path.join( + actualPluginPath, + '..', + 'preload', + 'index.js' + ) + return preloadPath + }) + const correctedPreloadPaths = preloadPaths .map((preloadPath) => { try { const path = __non_webpack_require__.resolve(preloadPath) as string @@ -37,24 +48,10 @@ export default class PluginsController extends BaseController { .filter(Boolean) as string[] return Promise.all( - preloadPaths.map((preloadPath) => readFile(preloadPath, 'utf-8')) + correctedPreloadPaths.map((preloadPath) => readFile(preloadPath, 'utf-8')) ) } - async listPreloadPaths() { - const list = await this.list() - return list.map((pluginPath) => { - const actualPluginPath = __non_webpack_require__.resolve(pluginPath) - const preloadPath = path.join( - actualPluginPath, - '..', - 'preload', - 'index.js' - ) - return preloadPath - }) - } - async onProjectLoaded() { const pluginPaths = await this.list() const plugins = await loadPlugins(pluginPaths, __non_webpack_require__) diff --git a/packages/selenium-ide/src/main/session/index.ts b/packages/selenium-ide/src/main/session/index.ts index ad3d92669..730ccb8b3 100644 --- a/packages/selenium-ide/src/main/session/index.ts +++ b/packages/selenium-ide/src/main/session/index.ts @@ -1,5 +1,6 @@ import { App } from 'electron' import ArgTypesController from './controllers/ArgTypes' +import ChannelsController from './controllers/Channels' import CommandsController from './controllers/Commands' import DialogsController from './controllers/Dialogs' import DriverController from './controllers/Driver' @@ -26,6 +27,7 @@ export default async function createSession( app, store: await Store(), } + partialSession.channels = new ChannelsController(partialSession as Session) partialSession.dialogs = new DialogsController(partialSession as Session) partialSession.argTypes = new ArgTypesController(partialSession as Session) partialSession.commands = new CommandsController(partialSession as Session) diff --git a/packages/selenium-ide/src/main/types.ts b/packages/selenium-ide/src/main/types.ts index 490ac6ae7..888b52fdb 100644 --- a/packages/selenium-ide/src/main/types.ts +++ b/packages/selenium-ide/src/main/types.ts @@ -4,6 +4,7 @@ import { App } from 'electron' import Store from 'electron-store' import config from './store/config' import ArgTypesController from './session/controllers/ArgTypes' +import ChannelsController from './session/controllers/Channels' import CommandsController from './session/controllers/Commands' import DialogsController from './session/controllers/Dialogs' import DriverController from './session/controllers/Driver' @@ -40,6 +41,7 @@ export interface Session { api: MainApi app: App argTypes: ArgTypesController + channels: ChannelsController commands: CommandsController dialogs: DialogsController driver: DriverController diff --git a/packages/side-api/package.json b/packages/side-api/package.json index 61112d509..9ed264f5e 100644 --- a/packages/side-api/package.json +++ b/packages/side-api/package.json @@ -1,6 +1,6 @@ { "name": "@seleniumhq/side-api", - "version": "4.0.0-alpha.40", + "version": "4.0.0-alpha.41", "private": false, "description": "Selenium IDE API command shapes and such", "author": "Todd Tarsi ", diff --git a/packages/side-api/src/commands/channels/index.ts b/packages/side-api/src/commands/channels/index.ts new file mode 100644 index 000000000..41547c8c3 --- /dev/null +++ b/packages/side-api/src/commands/channels/index.ts @@ -0,0 +1,18 @@ +import type { Shape as OnSend } from './onSend' +import type { Shape as Send } from './send' + +import * as onSend from './onSend' +import * as send from './send' + +export const commands = { + onSend, + send, +} + +/** + * Manages the establishing of bidirectional communication channels + */ +export type Shape = { + onSend: OnSend + send: Send +} diff --git a/packages/side-api/src/commands/channels/onSend.ts b/packages/side-api/src/commands/channels/onSend.ts new file mode 100644 index 000000000..d6eeec7e9 --- /dev/null +++ b/packages/side-api/src/commands/channels/onSend.ts @@ -0,0 +1,6 @@ +import { BaseListener } from '../../types/base' + +/** + * Contains a channel UUID and variadic arguments + */ +export type Shape = BaseListener<[string, ...any[]]> diff --git a/packages/side-api/src/commands/channels/send.ts b/packages/side-api/src/commands/channels/send.ts new file mode 100644 index 000000000..16c7efb06 --- /dev/null +++ b/packages/side-api/src/commands/channels/send.ts @@ -0,0 +1,4 @@ +/** + * Emit messages along a channel + */ +export type Shape = (channel: string, ...args: any[]) => Promise diff --git a/packages/side-api/src/commands/plugins/index.ts b/packages/side-api/src/commands/plugins/index.ts index cef026cc8..8eff926a3 100644 --- a/packages/side-api/src/commands/plugins/index.ts +++ b/packages/side-api/src/commands/plugins/index.ts @@ -2,7 +2,6 @@ import type { Shape as AddPreloadScript } from './addPreloadScript' import type { Shape as AddRecorderPreprocessor } from './addRecorderPreprocessor' import type { Shape as GetPreloads } from './getPreloads' import type { Shape as List } from './list' -import type { Shape as ListPreloadPaths } from './listPreloadPaths' import type { Shape as ProjectCreate } from './projectCreate' import type { Shape as ProjectDelete } from './projectDelete' import type { Shape as ProjectEdit } from './projectEdit' @@ -11,7 +10,6 @@ import * as addPreloadScript from './addPreloadScript' import * as addRecorderPreprocessor from './addRecorderPreprocessor' import * as getPreloads from './getPreloads' import * as list from './list' -import * as listPreloadPaths from './listPreloadPaths' import * as projectCreate from './projectCreate' import * as projectDelete from './projectDelete' import * as projectEdit from './projectEdit' @@ -21,7 +19,6 @@ export const commands = { addRecorderPreprocessor, getPreloads, list, - listPreloadPaths, projectCreate, projectDelete, projectEdit, @@ -34,7 +31,6 @@ export type Shape = { addRecorderPreprocessor: AddRecorderPreprocessor getPreloads: GetPreloads list: List - listPreloadPaths: ListPreloadPaths projectCreate: ProjectCreate projectDelete: ProjectDelete projectEdit: ProjectEdit diff --git a/packages/side-api/src/commands/recorder/getWinHandleId.ts b/packages/side-api/src/commands/recorder/getWinHandleId.ts index 0818df1b7..e191042a2 100644 --- a/packages/side-api/src/commands/recorder/getWinHandleId.ts +++ b/packages/side-api/src/commands/recorder/getWinHandleId.ts @@ -1 +1 @@ -export type Shape = () => Promise \ No newline at end of file +export type Shape = () => Promise diff --git a/packages/side-api/src/index.ts b/packages/side-api/src/index.ts index 0af429411..3feef4d30 100644 --- a/packages/side-api/src/index.ts +++ b/packages/side-api/src/index.ts @@ -1,4 +1,5 @@ import { BaseApi } from './types/base' +import { commands as channels } from './commands/channels' import { commands as dialogs } from './commands/dialogs' import { commands as driver } from './commands/driver' import { commands as menus } from './commands/menus' @@ -13,6 +14,7 @@ import { commands as tests } from './commands/tests' import { commands as windows } from './commands/windows' export interface ApiHoist extends BaseApi { + channels: typeof channels dialogs: typeof dialogs driver: typeof driver menus: typeof menus @@ -28,6 +30,7 @@ export interface ApiHoist extends BaseApi { } export const api: ApiHoist = { + channels, dialogs, driver, menus, diff --git a/packages/side-api/src/types/api.ts b/packages/side-api/src/types/api.ts index 02823a40b..f53f3254a 100644 --- a/packages/side-api/src/types/api.ts +++ b/packages/side-api/src/types/api.ts @@ -1,3 +1,4 @@ +import { type Shape as Channels } from '../commands/channels' import { type Shape as Dialogs } from '../commands/dialogs' import { type Shape as Driver } from '../commands/driver' import { type Shape as Menus } from '../commands/menus' @@ -15,6 +16,7 @@ import { type Shape as Windows } from '../commands/windows' * The full API usable by Selenium IDE */ export type Api = { + channels: Channels dialogs: Dialogs driver: Driver menus: Menus diff --git a/packages/side-example-suite/package.json b/packages/side-example-suite/package.json index 441958716..d107814dc 100644 --- a/packages/side-example-suite/package.json +++ b/packages/side-example-suite/package.json @@ -21,7 +21,7 @@ "@seleniumhq/code-export-python-pytest": "4.0.0-alpha.3" }, "devDependencies": { - "@seleniumhq/side-api": "^4.0.0-alpha.40" + "@seleniumhq/side-api": "^4.0.0-alpha.41" }, "repository": { "type": "git", diff --git a/packages/side-example-suite/src/plugins/custom-click/index.ts b/packages/side-example-suite/src/plugins/custom-click/index.ts index 8064a0cf5..c274641e9 100644 --- a/packages/side-example-suite/src/plugins/custom-click/index.ts +++ b/packages/side-example-suite/src/plugins/custom-click/index.ts @@ -28,6 +28,15 @@ const plugin: PluginShape = { onBeforeCommand: (input) => { console.log('Before command', input) }, + async onLoad(api) { + console.log('Loading example plugin!') + api.channels.onSend.addListener((channel, command) => { + if (channel === 'example-plugin') { + console.log('Message received', channel, command) + } + }) + console.log('Loaded example plugin!') + }, }, } diff --git a/packages/side-example-suite/src/plugins/custom-click/preload/index.ts b/packages/side-example-suite/src/plugins/custom-click/preload/index.ts index ad6b8a2fc..9c2b1d165 100644 --- a/packages/side-example-suite/src/plugins/custom-click/preload/index.ts +++ b/packages/side-example-suite/src/plugins/custom-click/preload/index.ts @@ -5,6 +5,7 @@ const api = window.sideAPI as Api api.plugins.addRecorderPreprocessor((command, event) => { console.debug('Recorded command', command, event) if (command.command !== 'click') return + api.channels.send('example-plugin', command) return { action: 'update', command: { @@ -13,3 +14,5 @@ api.plugins.addRecorderPreprocessor((command, event) => { }, } }) + +export = true diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bfc75e67..c6bce31ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -270,7 +270,7 @@ importers: specifier: ^4.0.0-alpha.3 version: link:../get-driver '@seleniumhq/side-api': - specifier: ^4.0.0-alpha.40 + specifier: ^4.0.0-alpha.41 version: link:../side-api '@seleniumhq/side-model': specifier: ^4.0.0-alpha.5 @@ -483,7 +483,7 @@ importers: version: link:../side-code-export devDependencies: '@seleniumhq/side-api': - specifier: ^4.0.0-alpha.40 + specifier: ^4.0.0-alpha.41 version: link:../side-api packages/side-migrate: