Skip to content

Commit

Permalink
making preload plugin scripts work again
Browse files Browse the repository at this point in the history
  • Loading branch information
toddtarsi committed Nov 26, 2023
1 parent d1bcee7 commit 81361e1
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 81 deletions.
2 changes: 1 addition & 1 deletion packages/selenium-ide/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
"@seleniumhq/code-export-ruby-rspec": "^4.0.0-alpha.1",
"side-code-export": "^4.0.0-alpha.11",
"@seleniumhq/get-driver": "^4.0.0-alpha.1",
"@seleniumhq/side-api": "^4.0.0-alpha.33",
"@seleniumhq/side-api": "^4.0.0-alpha.34",
"@seleniumhq/side-model": "^4.0.0-alpha.4",
"@seleniumhq/side-runtime": "^4.0.0-alpha.31",
"dnd-core": "^16.0.1",
Expand Down
1 change: 1 addition & 0 deletions packages/selenium-ide/src/browser/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const api: Api = processApi((path: string) => {
return Handler()(path)
})

export {BrowserApiMutators} from './mutator'
export { Api } from '@seleniumhq/side-api'

export default api
12 changes: 7 additions & 5 deletions packages/selenium-ide/src/browser/api/mutator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { processApi } from '@seleniumhq/side-api'
import { ApiHoist as Api } from '@seleniumhq/side-api'

type FunctionKeys<T extends Record<string, {mutator?: Function}>> = {
[K in keyof T as T[K]['mutator'] extends Function ? K : never]: T[K]['mutator'];
};

/**
* This Converts the chrome API type to something usable
* from the front end
*/
export type BrowserApiMutatorMapper = {
[Namespace in keyof Api]: {
[Handler in keyof Api[Namespace]]: Api[Namespace][Handler]['mutator']
}
export type BrowserApiMutators = {
[Namespace in keyof Api]: FunctionKeys<Api[Namespace]>
}

export default processApi<BrowserApiMutatorMapper>(
export default processApi<BrowserApiMutators>(
(_, handler) => handler.mutator
)
78 changes: 66 additions & 12 deletions packages/selenium-ide/src/browser/helpers/preload.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,67 @@
import { contextBridge } from 'electron'
import api from 'browser/api'
import apiMutators from 'browser/api/mutator'
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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.
import { PluginPreloadOutputShape } from '@seleniumhq/side-api'
import api, { Api, BrowserApiMutators } from 'browser/api'
import mutators from 'browser/api/mutator'
import { contextBridge, ipcRenderer } from 'electron'

/**
* Binds our API on initialization
*/
process.once('loaded', async () => {
/**
* Expose it in the main context
*/
contextBridge.exposeInMainWorld('sideAPI', { ...api, mutators: apiMutators })
})
export default (
apiSubset: Partial<Api> & { mutators: Partial<BrowserApiMutators> } = {
...api,
mutators,
}
) =>
new Promise<(PluginPreloadOutputShape | null)[]>((resolve) => {
const loadPluginFromPath = ([pluginPath, preloadPath]: [
string,
string
]): PluginPreloadOutputShape | null => {
try {
const pluginPreload = __non_webpack_require__(preloadPath)
const pluginHandler =
typeof pluginPreload === 'function'
? pluginPreload
: pluginPreload.default
return pluginHandler((...args: any[]) =>
ipcRenderer.send(`message-${pluginPath}`, ...args)
)
} catch (e) {
console.error(e)
return null
}
}

window.sideAPI = apiSubset as Api & { mutators: BrowserApiMutators }

/**
* Binds our API on initialization
*/
process.once('loaded', async () => {
/**
* Expose it in the main context
*/
contextBridge.exposeInMainWorld('sideAPI', window.sideAPI)
const pluginPaths = await api.plugins.list()
const preloadPaths = await api.plugins.listPreloadPaths()
const richPlugins: [string, string][] = pluginPaths.map((p, i) => [
p,
preloadPaths[i],
])
const plugins = richPlugins.map(loadPluginFromPath)
resolve(plugins)
})
})
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import '../../helpers/preload'
import preload from '../../helpers/preload'

preload()
4 changes: 3 additions & 1 deletion packages/selenium-ide/src/browser/windows/Logger/preload.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import '../../helpers/preload'
import preload from '../../helpers/preload'

preload()
64 changes: 23 additions & 41 deletions packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,34 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
import { PluginPreloadOutputShape } from '@seleniumhq/side-api'
import api from 'browser/api'
import apiMutators from 'browser/api/mutator'
import { contextBridge, ipcRenderer, webFrame } from 'electron'
import { identity } from 'lodash/fp'
import preload from 'browser/helpers/preload'
import { webFrame } from 'electron'
import Recorder from './preload/recorder'

const pluginFromPath = ([pluginPath, preloadPath]: [string, string]) => {
try {
const pluginPreload = __non_webpack_require__(preloadPath)
const pluginHandler =
typeof pluginPreload === 'function'
? pluginPreload
: pluginPreload.default
return pluginHandler((...args: any[]) =>
ipcRenderer.send(`message-${pluginPath}`, ...args)
)
} catch (e) {
console.error(e)
return null
}
}

/**
* Expose it in the main context
*/
window.addEventListener('DOMContentLoaded', async () => {
webFrame.executeJavaScript(`
Object.defineProperty(navigator, 'webdriver', {
get () {
return true
}
})
`)
window.sideAPI = {
(async () => {
const plugins = await preload({
recorder: api.recorder,
// @ts-expect-error
mutators: { recorder: apiMutators.recorder },
}
const pluginPaths = await api.plugins.list()
const preloadPaths = await api.plugins.listPreloadPaths()
const richPlugins: [string, string][] = pluginPaths.map((p, i) => [p, preloadPaths[i]])
const plugins = richPlugins.map(pluginFromPath).filter(identity)
})
window.addEventListener('DOMContentLoaded', async () => {
webFrame.executeJavaScript(`
Object.defineProperty(navigator, 'webdriver', {
get () {
return true
}
})
`)
setTimeout(async () => {
console.debug('Initializing the recorder')
new Recorder(window, plugins.filter(Boolean) as PluginPreloadOutputShape[])
}, 500)
})
})();

contextBridge.exposeInMainWorld('sideAPI', window.sideAPI)
setTimeout(async () => {
console.debug('Initializing the recorder')
new Recorder(window, plugins)
}, 500)
})
/**
* Expose it in the main context
*/
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import '../../helpers/preload'
import preload from '../../helpers/preload'

preload()
4 changes: 3 additions & 1 deletion packages/selenium-ide/src/browser/windows/Splash/preload.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import '../../helpers/preload'
import preload from '../../helpers/preload'

preload()
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const windowLoaderFactoryMap: WindowLoaderFactoryMap = Object.fromEntries(
devTools: !isAutomated,
...(windowConfig?.webPreferences ?? {}),
preload: hasPreload ? preloadPath : undefined,
sandbox: hasPreload ? false : undefined,
},
...options,
})
Expand Down Expand Up @@ -198,11 +199,19 @@ export default class WindowsController extends BaseController {
webPreferences: {
// This should be the default preload, which just adds the sideAPI to the window
preload: join(__dirname, `project-editor-preload-bundle.js`),
sandbox: false,
...(opts?.webPreferences ?? {}),
},
show: false,
})
this.windows[name] = window
await window.loadURL(`file://${filepath}`)
await this.useWindowState(
window,
'windowSize' + name,
'windowPosition' + name
)
window.show()
return true
}

Expand Down Expand Up @@ -290,7 +299,11 @@ export default class WindowsController extends BaseController {
if (isMac) {
window.setWindowButtonVisibility(false)
}
await this.useWindowState(window, 'windowSizePlayback', 'windowPositionPlayback')
await this.useWindowState(
window,
'windowSizePlayback',
'windowPositionPlayback'
)
window.show()
}

Expand All @@ -305,14 +318,14 @@ export default class WindowsController extends BaseController {
) {
const size = storage.get(sizeKey) as number[]
const position = storage.get(positionKey) as number[]
if (size.length) window.setSize(size[0], size[1], true)
if (size?.length) window.setSize(size[0], size[1], true)

const screenElectron = electron.screen.getPrimaryDisplay()

const sWidth = screenElectron.bounds.width
const sHeight = screenElectron.bounds.height

if (position.length) {
if (position?.length) {
const adjustedX = position[0] < 0 ? 50 : position[0]
const adjustedY = position[1] < 0 ? 50 : position[1]
window.setPosition(adjustedX, adjustedY)
Expand Down Expand Up @@ -347,7 +360,7 @@ export default class WindowsController extends BaseController {
await this.initializePlaybackWindow()
await this.close('splash')

await this.open(projectEditorWindowName, {show: false})
await this.open(projectEditorWindowName, { show: false })
const projectWindow = await this.get(projectEditorWindowName)
this.useWindowState(projectWindow, 'windowSize', 'windowPosition')

Expand Down
2 changes: 1 addition & 1 deletion packages/side-api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@seleniumhq/side-api",
"version": "4.0.0-alpha.33",
"version": "4.0.0-alpha.34",
"private": false,
"description": "Selenium IDE API command shapes and such",
"author": "Todd Tarsi <[email protected]>",
Expand Down
3 changes: 0 additions & 3 deletions packages/side-api/src/commands/state/closeTestEditor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { EditorStateShape } from '../../models/state'
import { Mutator } from '../../types/base'

/**
* Removes selected command indexes. Called when test editor closes.
*/
export type Shape = () => Promise<void>
export type EditorUpdates = Pick<EditorStateShape, 'selectedCommandIndexes'>
export type StateUpdates = { editor: EditorUpdates }

export const mutator: Mutator = (session) => session
3 changes: 0 additions & 3 deletions packages/side-api/src/commands/state/openTestEditor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { EditorStateShape } from '../../models/state'
import { Mutator } from '../../types/base'

export type Shape = () => Promise<void>
/**
* Called whenever test editor opens. Assigns command indexes
*/
export type EditorUpdates = Pick<EditorStateShape, 'selectedCommandIndexes'>
export type StateUpdates = { editor: EditorUpdates }

export const mutator: Mutator = (session) => session
5 changes: 2 additions & 3 deletions packages/side-example-suite/src/plugins/custom-click/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ const plugin: PluginShape = {
name: 'locator',
description: 'The target of the original recorded click',
},
execute: async (command, driver) => {
await driver.doClick(command.target as string, command.value || '')
},
execute: (command, driver) =>
driver.doClick(command.target as string, command.value || ''),
},
},
hooks: {
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 81361e1

Please sign in to comment.