From 106e6fdb035462d987e0a549830d38adc698dbad Mon Sep 17 00:00:00 2001 From: toddtarsi Date: Sat, 23 Dec 2023 15:01:24 -0700 Subject: [PATCH] all tests passing, legacy preload works --- .../browser/windows/PlaybackWindow/preload.ts | 4 + packages/selenium-ide/src/main/index.ts | 7 +- .../main/session/controllers/Driver/index.ts | 4 + .../session/controllers/Playback/index.ts | 107 ++++++++++++------ .../session/controllers/Recorder/index.ts | 25 ++-- .../main/session/controllers/Windows/index.ts | 1 - .../src/__tests__/playback.spec.ts | 1 + packages/side-runtime/src/webdriver.ts | 2 +- 8 files changed, 90 insertions(+), 61 deletions(-) diff --git a/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts b/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts index df2d0b9373..8c08a502aa 100644 --- a/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts +++ b/packages/selenium-ide/src/browser/windows/PlaybackWindow/preload.ts @@ -35,6 +35,10 @@ preload({ }, }) window.addEventListener('DOMContentLoaded', async () => { + const plugins = await api.plugins.listPreloadPaths() + for (const plugin of plugins) { + __non_webpack_require__(plugin) + } webFrame.executeJavaScript(` Object.defineProperty(navigator, 'webdriver', { get () { diff --git a/packages/selenium-ide/src/main/index.ts b/packages/selenium-ide/src/main/index.ts index c7d92f3076..d9b8556a1b 100644 --- a/packages/selenium-ide/src/main/index.ts +++ b/packages/selenium-ide/src/main/index.ts @@ -32,12 +32,7 @@ app.on('ready', async () => { connectSessionLogging(session) await session.system.startup() - process.on('SIGINT', async () => { - await session.system.shutdown() - if (session.system.isDown) { - await session.system.quit() - } - }) + process.on('SIGINT', () => app.quit()) app.on('open-file', async (_e, path) => { // Instantiate the session await session.projects.load(path) diff --git a/packages/selenium-ide/src/main/session/controllers/Driver/index.ts b/packages/selenium-ide/src/main/session/controllers/Driver/index.ts index 94cc25e20a..97e58b2d2d 100644 --- a/packages/selenium-ide/src/main/session/controllers/Driver/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Driver/index.ts @@ -186,6 +186,10 @@ export default class DriverController extends BaseController { } async stopProcess(): Promise { + await this.session.recorder.stop() + await Promise.all( + this.session.playback.playbacks.map((playback) => playback.cleanup()) + ) await this.session.windows.closeAllPlaybackWindows() await this.session.driver.executor?.cleanup() if (this.driverProcess) { 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 c8b3aab905..854322817b 100644 --- a/packages/selenium-ide/src/main/session/controllers/Playback/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Playback/index.ts @@ -47,11 +47,19 @@ export default class PlaybackController extends BaseController { if (useBidi) { const handles = await driver.getAllWindowHandles() if (!handles.length) { - const playbackPos = await this.session.store.get('windowPositionPlayback') + const playbackPos = await this.session.store.get( + 'windowPositionPlayback' + ) const playbackSize = await this.session.store.get('windowSizePlayback') await driver.switchTo().newWindow('tab') - await driver.manage().window().setPosition(...playbackPos) - await driver.manage().window().setSize(...playbackSize) + await driver + .manage() + .window() + .setPosition(...playbackPos) + await driver + .manage() + .window() + .setSize(...playbackSize) const windowDimensionCache = setInterval(async () => { const handles = await driver.getAllWindowHandles() if (!handles.length) { @@ -59,9 +67,12 @@ export default class PlaybackController extends BaseController { } const pos = await driver.manage().window().getPosition() const size = await driver.manage().window().getSize() - await this.session.store.set('windowPositionPlayback', [pos.x, pos.y]) - await this.session.store.set('windowSizePlayback', [size.width, size.height]) - }, 1000); + await this.session.store.set('windowPositionPlayback', [pos.x, pos.y]) + await this.session.store.set('windowSizePlayback', [ + size.width, + size.height, + ]) + }, 1000) } return } @@ -151,37 +162,48 @@ export default class PlaybackController extends BaseController { } } + async getPlayback(testID?: string) { + const browserInfo = this.session.store.get('browserInfo') + const allowMultiplePlaybacks = + (await this.isParallel()) && this.testQueue.length + const makeNewPlayback = allowMultiplePlaybacks || !this.playbacks.length + if (makeNewPlayback) { + const playback = new Playback({ + baseUrl: this.session.projects.project.url, + executor: await this.session.driver.build({ + browser: browserInfo.browser, + }), + getTestByName: (name: string) => this.session.tests.getByName(name), + logger: console, + variables: new Variables(), + options: { + delay: this.session.projects.project.delay || 0, + }, + }) + await playback.init() + const EE = playback['event-emitter'] + EE.addListener( + PlaybackEvents.PLAYBACK_STATE_CHANGED, + this.handlePlaybackStateChanged( + playback, + allowMultiplePlaybacks ? testID : null + ) + ) + EE.addListener( + PlaybackEvents.COMMAND_STATE_CHANGED, + this.handleCommandStateChanged + ) + this.playbacks.push(playback) + return playback + } + return this.playbacks[0] + } + async play(testID: string, playRange = PlaybackController.defaultPlayRange) { this.playingTest = testID this.playRange = playRange this.isPlaying = true - /** - * Create playback if none exists - */ - const browserInfo = this.session.store.get('browserInfo') - const playback = new Playback({ - baseUrl: this.session.projects.project.url, - executor: await this.session.driver.build({ - browser: browserInfo.browser, - }), - getTestByName: (name: string) => this.session.tests.getByName(name), - logger: console, - variables: new Variables(), - options: { - delay: this.session.projects.project.delay || 0, - }, - }) - await playback.init() - const EE = playback['event-emitter'] - EE.addListener( - PlaybackEvents.PLAYBACK_STATE_CHANGED, - this.handlePlaybackStateChanged(playback, testID) - ) - EE.addListener( - PlaybackEvents.COMMAND_STATE_CHANGED, - this.handleCommandStateChanged - ) - this.playbacks.push(playback) + const playback = await this.getPlayback(testID) /** * If not ending at end of test, use playTo command * or playSingleCommand if just one command specified. @@ -190,7 +212,7 @@ export default class PlaybackController extends BaseController { if (playRange[1] !== -1) { const test = this.session.tests.getByID(testID) if (playRange[0] === playRange[1]) { - await playback.playSingleCommand(test.commands[playRange[0]]) + await playback.playSingleCommand(test.commands[playRange[0]]) } else { await playback.playTo(test, playRange[1], playRange[0]) } @@ -201,6 +223,17 @@ export default class PlaybackController extends BaseController { } } + async isParallel() { + const { + project: { suites }, + state: { activeSuiteID }, + } = await this.session.state.get() + this.playingSuite = activeSuiteID + const suite = suites.find(hasID(activeSuiteID)) + this.testQueue = suite?.tests ?? [] + return suite?.parallel ?? false + } + async playSuite() { const { project: { suites }, @@ -248,9 +281,11 @@ export default class PlaybackController extends BaseController { } handlePlaybackStateChanged = - (playback: Playback, testID: string) => + (playback: Playback, testID: string | null = null) => async (e: PlaybackEventShapes['PLAYBACK_STATE_CHANGED']) => { - const testName = this.session.tests.getByID(testID)?.name + const testName = this.session.tests.getByID( + testID || this.session.state.state.activeTestID + )?.name console.debug( `Playing state changed ${e.state} for test ${testName}`, this.playingSuite diff --git a/packages/selenium-ide/src/main/session/controllers/Recorder/index.ts b/packages/selenium-ide/src/main/session/controllers/Recorder/index.ts index 3798c6ee27..2fe3663c90 100644 --- a/packages/selenium-ide/src/main/session/controllers/Recorder/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Recorder/index.ts @@ -8,11 +8,10 @@ import { LocatorFields, RecordNewCommandInput, } from '@seleniumhq/side-api' -import { randomInt, randomUUID } from 'crypto' +import { randomUUID } from 'crypto' import { relative } from 'node:path' import BaseController from '../Base' import { BrowserWindow } from 'electron' -import { WebDriverExecutor } from '@seleniumhq/side-runtime' const uninitializedWindows = ['data:,', 'about:blank'] @@ -54,7 +53,6 @@ const getFrameTraversalCommands = ( } export default class RecorderController extends BaseController { - driver!: WebDriverExecutor windowIDs: number[] = [] async recordNewCommand( @@ -65,6 +63,7 @@ export default class RecorderController extends BaseController { return null } const activeWindowHandleID = getActiveWindowHandleID(session) || 'root' + console.log(activeWindowHandleID, session.project.tests[0].commands) const commands = [] if (activeWindowHandleID != cmd.winHandleId) { const selectWindowCommand: CommandShape = { @@ -102,16 +101,6 @@ export default class RecorderController extends BaseController { ) } - async handleNewWindow() { - const session = await this.session.state.get() - if (session.state.status !== 'recording') return - const newWindowID = `win${randomInt(1, 9999)}` - this.session.api.recorder.onNewWindow.dispatchEvent( - newWindowID, - randomUUID() - ) - } - async requestSelectElement(activate: boolean, fieldName: LocatorFields) { this.session.windows.getLastPlaybackWindow().focus() this.session.api.recorder.onRequestSelectElement.dispatchEvent( @@ -159,15 +148,17 @@ export default class RecorderController extends BaseController { newStepID: string windowHandle: string | null } | null> { + const playback = await this.session.playback.getPlayback() + const executor = playback.executor + const driver = executor.driver const useBidi = this.session.store.get('browserInfo.useBidi') const newStepID = randomUUID() - this.driver = await this.session.driver.build() if (useBidi) { - const firstWindowURL = await this.driver.driver.getCurrentUrl() + const firstWindowURL = await driver.getCurrentUrl() if (uninitializedWindows.includes(firstWindowURL)) { - await this.driver.doOpen(this.session.projects.project.url) + await executor.doOpen(this.session.projects.project.url) } - const windowHandle = await this.driver.driver.getWindowHandle() + const windowHandle = await driver.getWindowHandle() return { newStepID, windowHandle } } diff --git a/packages/selenium-ide/src/main/session/controllers/Windows/index.ts b/packages/selenium-ide/src/main/session/controllers/Windows/index.ts index ea249871cf..b1770af4b8 100644 --- a/packages/selenium-ide/src/main/session/controllers/Windows/index.ts +++ b/packages/selenium-ide/src/main/session/controllers/Windows/index.ts @@ -251,7 +251,6 @@ export default class WindowsController extends BaseController { this.playbackWindows.push(window) window.webContents.insertCSS(playbackCSS) window.webContents.setWindowOpenHandler(() => { - this.session.recorder.handleNewWindow() return { action: 'allow', overrideBrowserWindowOptions: playbackWindowOptions, diff --git a/packages/side-runtime/src/__tests__/playback.spec.ts b/packages/side-runtime/src/__tests__/playback.spec.ts index 423a676a92..24024e090b 100644 --- a/packages/side-runtime/src/__tests__/playback.spec.ts +++ b/packages/side-runtime/src/__tests__/playback.spec.ts @@ -421,6 +421,7 @@ describe('Playback', () => { value: '', }) await playback.resume() + await psetTimeout(10) expect(executor.doOpen).toHaveBeenCalledTimes(4) }) diff --git a/packages/side-runtime/src/webdriver.ts b/packages/side-runtime/src/webdriver.ts index 052955ee02..ae655caf7c 100644 --- a/packages/side-runtime/src/webdriver.ts +++ b/packages/side-runtime/src/webdriver.ts @@ -191,7 +191,7 @@ export default class WebDriverExecutor { } async cleanup() { - if (this.initialized) { + if (this.driver) { await this.driver.quit() // @ts-expect-error this.driver = undefined