Skip to content

Commit

Permalink
v99: Fix vars on open in IDE
Browse files Browse the repository at this point in the history
Also, actually test that the recorder works in IDE!!!
  • Loading branch information
toddtarsi committed Feb 25, 2024
1 parent 52bca46 commit a406af3
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 43 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
"pretest": "cd packages/webdriver-testkit && npm run download-drivers",
"start": "cd packages/selenium-ide && npm start",
"test:jest:core": "jest",
"test": "npm run test:jest && npm run test:side-runner:ci",
"test": "npm run test:jest && npm run test:side-runner:ci && npm run test:ide",
"test:jest": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'npm run test:jest:core'",
"lint": "pnpm run lint:scripts",
"lint:scripts": "eslint --ignore-pattern node_modules --ignore-pattern third-party --ignore-pattern dist --ignore-pattern build --ignore-pattern json --ext .ts,.tsx --ext .js packages/",
"test:ide": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'node ./packages/selenium-ide/scripts/ide-runner.js -t 15000 ./tests/examples/*.side'",
"test:ide": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'node ./packages/selenium-ide/scripts/ide-runner.js'",
"test:side-runner": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'node ./packages/side-runner/dist/bin.js -t 15000 ./tests/examples/*.side'",
"test:side-runner:ci": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'node ./packages/side-runner/dist/bin.js -c \"goog:chromeOptions.args=[headless,no-sandbox] browserName=chrome\" -t 15000 ./tests/examples/*.side'",
"typecheck": "tsc --noEmit --composite false",
Expand Down
2 changes: 1 addition & 1 deletion packages/selenium-ide/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "selenium-ide",
"version": "4.0.1-alpha.98",
"version": "4.0.1-alpha.99",
"private": false,
"description": "Selenium IDE electron app",
"author": "Todd <[email protected]>",
Expand Down
114 changes: 89 additions & 25 deletions packages/selenium-ide/scripts/ide-runner.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const args = process.argv

const { spawn } = require('child_process')
const webdriver = require('selenium-webdriver')
const fs = require('fs')
Expand All @@ -8,8 +6,6 @@ const os = require('os')

const WebdriverDebugLog = console.log // debuglog('webdriver')

const appName = 'Electron'

const driverPath = path.join(
__dirname,
'..',
Expand All @@ -19,16 +15,25 @@ const driverPath = path.join(
'chromedriver' + (os.platform() === 'win32' ? '.exe' : '')
)

const electronBinaryPath = path.join(
require.resolve('electron'),
'..',
'dist',
appName + '.app',
'Contents',
'MacOS',
appName
)
const getElectronPath = () => {
const basePath = path.join(require.resolve('electron'), '..', 'dist')
switch (os.platform()) {
case 'darwin':
return path.join(
basePath,
'Electron.app',
'Contents',
'MacOS',
'Electron'
)
case 'win32':
return path.join(basePath, 'electron.exe')
default:
return path.join(basePath, 'electron')
}
}

const electronBinaryPath = getElectronPath()
const pathToSeleniumIDE = path.join(__dirname, '..', 'build', 'main-bundle.js')

const port = 9518
Expand All @@ -40,28 +45,87 @@ async function main() {
if (!success) {
console.error('Failed to start webdriver backend')
console.error(proc.error)
return
throw proc.error
}
const sideFiles = args.filter((arg) => arg.endsWith('.side'))
for (const sideFile of [sideFiles[0]]) {
console.log('Starting driver for sidefile', sideFile)
const driver = await new webdriver.Builder()
let driver
try {
driver = await new webdriver.Builder()
.usingServer(`http://localhost:${port}`)
.withCapabilities({
'goog:chromeOptions': {
// Here is the path to your Electron binary.
binary: electronBinaryPath,
args: ['app=' + pathToSeleniumIDE, `side-file=${sideFile}`],
args: ['app=' + pathToSeleniumIDE, 'enable-automation'],
excludeSwitches: ['enable-logging'],
},
})
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
.forBrowser('chrome')
.build()
await driver.sleep(10000)
const newProject = await driver.wait(
webdriver.until.elementLocated(webdriver.By.css('[data-new-project]')),
5000
)
const firstHandle = await driver.getWindowHandle()
await newProject.click()
let handles = await driver.getAllWindowHandles()
while (handles.length < 1 || handles[0] === firstHandle) {
await driver.sleep(100)
try {
handles = await driver.getAllWindowHandles()
} catch (e) {}
}
await driver.switchTo().window(handles[0])
const url = await driver.wait(
webdriver.until.elementLocated(webdriver.By.css('[data-url]')),
5000
)
await url.click()
while ((await url.getAttribute('value')) !== '') {
await url.sendKeys(webdriver.Key.BACK_SPACE)
}
const host = 'http://localhost:8080'
for (const index in host) {
await url.sendKeys(host[index])
await driver.sleep(10)
}
const record = await driver.wait(
webdriver.until.elementLocated(webdriver.By.css('[data-record]')),
1000
)
await record.click()
let handles2 = await driver.getAllWindowHandles()
while (handles2.length < 2) {
await driver.sleep(100)
handles2 = await driver.getAllWindowHandles()
}
await driver.switchTo().window(handles2[1])
await driver.sleep(1000)
const link = await driver.wait(
webdriver.until.elementLocated(webdriver.By.linkText('windows.html')),
3000
)
await link.click()
await driver.switchTo().window(handles2[0])
const command = await driver.wait(
webdriver.until.elementLocated(
webdriver.By.css('[data-command-id]:nth-child(2)')
),
1000
)
const text = (await command.getText()).replace(/\s+/g, ' ')
if (text !== 'Click linkText=windows.html') {
throw new Error('Unexpected command text: ' + text)
}
console.log('IDE is correctly recording commands!')
await driver.quit()
return
proc.kill()
} catch (e) {
if (driver) {
await driver.quit()
}
proc.kill()
throw e
}
proc.kill()
}

function startWebdriverBackend() {
Expand All @@ -76,7 +140,7 @@ function startWebdriverBackend() {
})
proc.stdout.on('data', (out) => {
const outStr = `${out}`
WebdriverDebugLog(outStr)
// WebdriverDebugLog(outStr)
const fullyStarted = outStr.includes(successMessage)
if (fullyStarted) {
initialized = true
Expand All @@ -86,7 +150,7 @@ function startWebdriverBackend() {
})
proc.stderr.on('data', (err) => {
const errStr = `${err}`
WebdriverDebugLog(errStr)
// WebdriverDebugLog(errStr)
if (!initialized) {
resolve({ success: false, error: errStr })
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const PauseButton: FC = () => (
<Tooltip title="Pause" aria-label="pause">
<IconButton
{...baseControlProps}
data-pause
onClick={() => window.sideAPI.playback.pause()}
>
<PauseIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const PlayButton: FC<PlayButtonProps> = ({ state }) => (
<Tooltip title="Play" aria-label="play">
<IconButton
{...baseControlProps}
data-play
onClick={() => {
state.playback.currentIndex === badIndex
? window.sideAPI.playback.play(state.activeTestID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const PlayListButton: FC<PlayListButtonProps> = () => (
<Tooltip title="Play Suite" aria-label="play-suite">
<IconButton
{...baseControlProps}
data-play-suite
onClick={() => window.sideAPI.playback.playSuite()}
>
<PlaylistPlayIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const PlayNextStepButton: FC<PlayNextStepButtonProps> = ({ state, test }) => {
<Tooltip title="Play Next Step" aria-label="play-next-step">
<IconButton
{...baseControlProps}
data-play-next-step
disabled={disabled}
onClick={() => {
window.sideAPI.playback.play(state.activeTestID, [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const RecordButton: FC = () => (
<Tooltip title="Record" aria-label="record">
<IconButton
{...baseControlProps}
data-record
onClick={() => window.sideAPI.recorder.start()}
>
<RecordIcon color="error" />
Expand Down
3 changes: 3 additions & 0 deletions packages/selenium-ide/src/browser/components/URLBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const URLBar: React.FC<Pick<SIDEMainProps, 'session'>> = ({ session }) => {
<Box className="flex-1 px-3 py-2">
<TextField
className="width-100"
inputProps={{
['data-url']: true,
}}
onChange={(e: any) => {
update({
url: e.target.value,
Expand Down
4 changes: 2 additions & 2 deletions packages/selenium-ide/src/browser/windows/Splash/renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ const ProjectEditor = () => {
</Typography>
</Grid>
<Grid item xs={6}>
<Button onClick={loadProject} variant="contained">
<Button data-load-project onClick={loadProject} variant="contained">
Load Project
</Button>
</Grid>
<Grid item xs={6}>
<Button onClick={newProject} variant="outlined">
<Button data-new-project onClick={newProject} variant="outlined">
New Project
</Button>
</Grid>
Expand Down
30 changes: 25 additions & 5 deletions packages/selenium-ide/src/main/session/controllers/Driver/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import { Chrome } from '@seleniumhq/browser-info'
import { retry } from '@seleniumhq/side-commons'
import { CommandShape } from '@seleniumhq/side-model'
import { PluginRuntimeShape, WebDriverExecutor } from '@seleniumhq/side-runtime'
import { absolutifyUrl } from '@seleniumhq/side-runtime/dist/utils'
import { interpolateString } from '@seleniumhq/side-runtime/dist/preprocessors'
import { ChildProcess } from 'child_process'
import { BrowserInfo, Session } from 'main/types'
import getScriptManager from 'selenium-webdriver/bidi/scriptManager'
import { join } from 'path'
import { Builder } from 'selenium-webdriver'
import getScriptManager from 'selenium-webdriver/bidi/scriptManager'

import downloadDriver from './download'
import startDriver, { port, WebdriverDebugLog } from './start'
import BaseController from '../Base'
import { createBidiAPIBindings } from './bidi'
import { CommandShape } from '@seleniumhq/side-model'
import { absolutifyUrl } from '@seleniumhq/side-runtime/src/utils'
import { retry } from '@seleniumhq/side-commons'

const turtlesMode = Boolean(process.env.TURTLES)
const pathToSeleniumIDE = join(__dirname, '..', 'build', 'main-bundle.js')
const ideCapabilities = {
'goog:chromeOptions': {
// Here is the path to your Electron binary.
binary: process.execPath,
args: ['app=' + pathToSeleniumIDE],
excludeSwitches: ['enable-logging'],
},
}

// Escape hatch to avoid dealing with rootDir complexities in TS
// https://stackoverflow.com/questions/50822310/how-to-import-package-json-in-typescript
Expand Down Expand Up @@ -163,7 +176,13 @@ const electronPolyfills = (
throw new Error('Failed to find playback window')
}
await retry(
() => window.loadURL(absolutifyUrl(url!, session.projects.project.url)),
() =>
window.loadURL(
absolutifyUrl(
interpolateString(url!, executor.variables),
session.projects.project.url
)
),
5,
100
)
Expand Down Expand Up @@ -234,6 +253,7 @@ export default class DriverController extends BaseController {
browserName,
...capabilities,
...(capabilities.webSocketUrl === false ? electronCapabilities : {}),
...(turtlesMode ? ideCapabilities : {}),
})
.usingServer(server)
.forBrowser(browserName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as fs from 'fs-extra'
import { BrowserInfo, Session } from 'main/types'
import * as path from 'node:path'
import * as os from 'os'
import { COLOR_MAGENTA, COLOR_YELLOW, vdebuglog } from 'main/util'
import { COLOR_MAGENTA, COLOR_YELLOW, isAutomated, vdebuglog } from 'main/util'

const successMessage = 'was started successfully.'
export interface DriverStartSuccess {
Expand All @@ -20,7 +20,7 @@ export interface DriverStartFailure {
export const WebdriverDebugLog = vdebuglog('webdriver', COLOR_MAGENTA)
export const WebdriverDebugLogErr = vdebuglog('webdriver-error', COLOR_YELLOW)

export const port = app.isPackaged ? 9516 : 9515
export const port = isAutomated ? 9518 : app.isPackaged ? 9516 : 9515

/**
* This module is just an async function that does the following:
Expand Down Expand Up @@ -61,9 +61,6 @@ const startDriver: StartDriver = (session: Session) => (info) =>
let initialized = false
const args = ['--verbose', `--port=${port}`]
const driverPath = getDriver(info)
switch (info.browser) {
case 'electron':
}
console.log(
'Starting driver',
info.browser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import electron, {
import { existsSync, readFileSync } from 'fs'
import kebabCase from 'lodash/fp/kebabCase'
import { Session } from 'main/types'
import { isAutomated } from 'main/util'
import { join } from 'node:path'
import BaseController from '../Base'
import { window as playbackWindowOpts } from 'browser/windows/PlaybackWindow/controller'
Expand All @@ -21,7 +20,7 @@ const playbackCSS = readFileSync(join(__dirname, 'highlight.css'), 'utf-8')
const playbackWindowOptions = {
...playbackWindowOpts(),
webPreferences: {
devTools: !isAutomated,
devTools: true,
preload: join(__dirname, `playback-window-preload-bundle.js`),
},
}
Expand Down Expand Up @@ -56,7 +55,7 @@ const windowLoaderFactoryMap: WindowLoaderFactoryMap = Object.fromEntries(
...windowConfig,
..._options,
webPreferences: {
devTools: !isAutomated,
devTools: true,
...(windowConfig?.webPreferences ?? {}),
preload: hasPreload ? preloadPath : undefined,
sandbox: true,
Expand Down

0 comments on commit a406af3

Please sign in to comment.