Skip to content

Commit a406af3

Browse files
committed
v99: Fix vars on open in IDE
Also, actually test that the recorder works in IDE!!!
1 parent 52bca46 commit a406af3

File tree

13 files changed

+131
-43
lines changed

13 files changed

+131
-43
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
"pretest": "cd packages/webdriver-testkit && npm run download-drivers",
1616
"start": "cd packages/selenium-ide && npm start",
1717
"test:jest:core": "jest",
18-
"test": "npm run test:jest && npm run test:side-runner:ci",
18+
"test": "npm run test:jest && npm run test:side-runner:ci && npm run test:ide",
1919
"test:jest": "npm-run-bg -s 'http-server -p 8080 ./packages/side-testkit/fixtures/static::Available on::8080' 'npm run test:jest:core'",
2020
"lint": "pnpm run lint:scripts",
2121
"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/",
22-
"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'",
22+
"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'",
2323
"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'",
2424
"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'",
2525
"typecheck": "tsc --noEmit --composite false",

packages/selenium-ide/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "selenium-ide",
3-
"version": "4.0.1-alpha.98",
3+
"version": "4.0.1-alpha.99",
44
"private": false,
55
"description": "Selenium IDE electron app",
66
"author": "Todd <[email protected]>",

packages/selenium-ide/scripts/ide-runner.js

+89-25
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const args = process.argv
2-
31
const { spawn } = require('child_process')
42
const webdriver = require('selenium-webdriver')
53
const fs = require('fs')
@@ -8,8 +6,6 @@ const os = require('os')
86

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

11-
const appName = 'Electron'
12-
139
const driverPath = path.join(
1410
__dirname,
1511
'..',
@@ -19,16 +15,25 @@ const driverPath = path.join(
1915
'chromedriver' + (os.platform() === 'win32' ? '.exe' : '')
2016
)
2117

22-
const electronBinaryPath = path.join(
23-
require.resolve('electron'),
24-
'..',
25-
'dist',
26-
appName + '.app',
27-
'Contents',
28-
'MacOS',
29-
appName
30-
)
18+
const getElectronPath = () => {
19+
const basePath = path.join(require.resolve('electron'), '..', 'dist')
20+
switch (os.platform()) {
21+
case 'darwin':
22+
return path.join(
23+
basePath,
24+
'Electron.app',
25+
'Contents',
26+
'MacOS',
27+
'Electron'
28+
)
29+
case 'win32':
30+
return path.join(basePath, 'electron.exe')
31+
default:
32+
return path.join(basePath, 'electron')
33+
}
34+
}
3135

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

3439
const port = 9518
@@ -40,28 +45,87 @@ async function main() {
4045
if (!success) {
4146
console.error('Failed to start webdriver backend')
4247
console.error(proc.error)
43-
return
48+
throw proc.error
4449
}
45-
const sideFiles = args.filter((arg) => arg.endsWith('.side'))
46-
for (const sideFile of [sideFiles[0]]) {
47-
console.log('Starting driver for sidefile', sideFile)
48-
const driver = await new webdriver.Builder()
50+
let driver
51+
try {
52+
driver = await new webdriver.Builder()
4953
.usingServer(`http://localhost:${port}`)
5054
.withCapabilities({
5155
'goog:chromeOptions': {
5256
// Here is the path to your Electron binary.
5357
binary: electronBinaryPath,
54-
args: ['app=' + pathToSeleniumIDE, `side-file=${sideFile}`],
58+
args: ['app=' + pathToSeleniumIDE, 'enable-automation'],
5559
excludeSwitches: ['enable-logging'],
5660
},
5761
})
58-
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
62+
.forBrowser('chrome')
5963
.build()
60-
await driver.sleep(10000)
64+
const newProject = await driver.wait(
65+
webdriver.until.elementLocated(webdriver.By.css('[data-new-project]')),
66+
5000
67+
)
68+
const firstHandle = await driver.getWindowHandle()
69+
await newProject.click()
70+
let handles = await driver.getAllWindowHandles()
71+
while (handles.length < 1 || handles[0] === firstHandle) {
72+
await driver.sleep(100)
73+
try {
74+
handles = await driver.getAllWindowHandles()
75+
} catch (e) {}
76+
}
77+
await driver.switchTo().window(handles[0])
78+
const url = await driver.wait(
79+
webdriver.until.elementLocated(webdriver.By.css('[data-url]')),
80+
5000
81+
)
82+
await url.click()
83+
while ((await url.getAttribute('value')) !== '') {
84+
await url.sendKeys(webdriver.Key.BACK_SPACE)
85+
}
86+
const host = 'http://localhost:8080'
87+
for (const index in host) {
88+
await url.sendKeys(host[index])
89+
await driver.sleep(10)
90+
}
91+
const record = await driver.wait(
92+
webdriver.until.elementLocated(webdriver.By.css('[data-record]')),
93+
1000
94+
)
95+
await record.click()
96+
let handles2 = await driver.getAllWindowHandles()
97+
while (handles2.length < 2) {
98+
await driver.sleep(100)
99+
handles2 = await driver.getAllWindowHandles()
100+
}
101+
await driver.switchTo().window(handles2[1])
102+
await driver.sleep(1000)
103+
const link = await driver.wait(
104+
webdriver.until.elementLocated(webdriver.By.linkText('windows.html')),
105+
3000
106+
)
107+
await link.click()
108+
await driver.switchTo().window(handles2[0])
109+
const command = await driver.wait(
110+
webdriver.until.elementLocated(
111+
webdriver.By.css('[data-command-id]:nth-child(2)')
112+
),
113+
1000
114+
)
115+
const text = (await command.getText()).replace(/\s+/g, ' ')
116+
if (text !== 'Click linkText=windows.html') {
117+
throw new Error('Unexpected command text: ' + text)
118+
}
119+
console.log('IDE is correctly recording commands!')
61120
await driver.quit()
62-
return
121+
proc.kill()
122+
} catch (e) {
123+
if (driver) {
124+
await driver.quit()
125+
}
126+
proc.kill()
127+
throw e
63128
}
64-
proc.kill()
65129
}
66130

67131
function startWebdriverBackend() {
@@ -76,7 +140,7 @@ function startWebdriverBackend() {
76140
})
77141
proc.stdout.on('data', (out) => {
78142
const outStr = `${out}`
79-
WebdriverDebugLog(outStr)
143+
// WebdriverDebugLog(outStr)
80144
const fullyStarted = outStr.includes(successMessage)
81145
if (fullyStarted) {
82146
initialized = true
@@ -86,7 +150,7 @@ function startWebdriverBackend() {
86150
})
87151
proc.stderr.on('data', (err) => {
88152
const errStr = `${err}`
89-
WebdriverDebugLog(errStr)
153+
// WebdriverDebugLog(errStr)
90154
if (!initialized) {
91155
resolve({ success: false, error: errStr })
92156
}

packages/selenium-ide/src/browser/components/Controls/PauseButton.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const PauseButton: FC = () => (
88
<Tooltip title="Pause" aria-label="pause">
99
<IconButton
1010
{...baseControlProps}
11+
data-pause
1112
onClick={() => window.sideAPI.playback.pause()}
1213
>
1314
<PauseIcon />

packages/selenium-ide/src/browser/components/Controls/PlayButton.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const PlayButton: FC<PlayButtonProps> = ({ state }) => (
1414
<Tooltip title="Play" aria-label="play">
1515
<IconButton
1616
{...baseControlProps}
17+
data-play
1718
onClick={() => {
1819
state.playback.currentIndex === badIndex
1920
? window.sideAPI.playback.play(state.activeTestID)

packages/selenium-ide/src/browser/components/Controls/PlayListButton.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const PlayListButton: FC<PlayListButtonProps> = () => (
1313
<Tooltip title="Play Suite" aria-label="play-suite">
1414
<IconButton
1515
{...baseControlProps}
16+
data-play-suite
1617
onClick={() => window.sideAPI.playback.playSuite()}
1718
>
1819
<PlaylistPlayIcon />

packages/selenium-ide/src/browser/components/Controls/PlayNextStepButton.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const PlayNextStepButton: FC<PlayNextStepButtonProps> = ({ state, test }) => {
3535
<Tooltip title="Play Next Step" aria-label="play-next-step">
3636
<IconButton
3737
{...baseControlProps}
38+
data-play-next-step
3839
disabled={disabled}
3940
onClick={() => {
4041
window.sideAPI.playback.play(state.activeTestID, [

packages/selenium-ide/src/browser/components/Controls/RecordButton.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const RecordButton: FC = () => (
88
<Tooltip title="Record" aria-label="record">
99
<IconButton
1010
{...baseControlProps}
11+
data-record
1112
onClick={() => window.sideAPI.recorder.start()}
1213
>
1314
<RecordIcon color="error" />

packages/selenium-ide/src/browser/components/URLBar/index.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const URLBar: React.FC<Pick<SIDEMainProps, 'session'>> = ({ session }) => {
1717
<Box className="flex-1 px-3 py-2">
1818
<TextField
1919
className="width-100"
20+
inputProps={{
21+
['data-url']: true,
22+
}}
2023
onChange={(e: any) => {
2124
update({
2225
url: e.target.value,

packages/selenium-ide/src/browser/windows/Splash/renderer.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ const ProjectEditor = () => {
3838
</Typography>
3939
</Grid>
4040
<Grid item xs={6}>
41-
<Button onClick={loadProject} variant="contained">
41+
<Button data-load-project onClick={loadProject} variant="contained">
4242
Load Project
4343
</Button>
4444
</Grid>
4545
<Grid item xs={6}>
46-
<Button onClick={newProject} variant="outlined">
46+
<Button data-new-project onClick={newProject} variant="outlined">
4747
New Project
4848
</Button>
4949
</Grid>

packages/selenium-ide/src/main/session/controllers/Driver/index.ts

+25-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
import { Chrome } from '@seleniumhq/browser-info'
2+
import { retry } from '@seleniumhq/side-commons'
3+
import { CommandShape } from '@seleniumhq/side-model'
24
import { PluginRuntimeShape, WebDriverExecutor } from '@seleniumhq/side-runtime'
5+
import { absolutifyUrl } from '@seleniumhq/side-runtime/dist/utils'
6+
import { interpolateString } from '@seleniumhq/side-runtime/dist/preprocessors'
37
import { ChildProcess } from 'child_process'
48
import { BrowserInfo, Session } from 'main/types'
5-
import getScriptManager from 'selenium-webdriver/bidi/scriptManager'
9+
import { join } from 'path'
610
import { Builder } from 'selenium-webdriver'
11+
import getScriptManager from 'selenium-webdriver/bidi/scriptManager'
712

813
import downloadDriver from './download'
914
import startDriver, { port, WebdriverDebugLog } from './start'
1015
import BaseController from '../Base'
1116
import { createBidiAPIBindings } from './bidi'
12-
import { CommandShape } from '@seleniumhq/side-model'
13-
import { absolutifyUrl } from '@seleniumhq/side-runtime/src/utils'
14-
import { retry } from '@seleniumhq/side-commons'
17+
18+
const turtlesMode = Boolean(process.env.TURTLES)
19+
const pathToSeleniumIDE = join(__dirname, '..', 'build', 'main-bundle.js')
20+
const ideCapabilities = {
21+
'goog:chromeOptions': {
22+
// Here is the path to your Electron binary.
23+
binary: process.execPath,
24+
args: ['app=' + pathToSeleniumIDE],
25+
excludeSwitches: ['enable-logging'],
26+
},
27+
}
1528

1629
// Escape hatch to avoid dealing with rootDir complexities in TS
1730
// https://stackoverflow.com/questions/50822310/how-to-import-package-json-in-typescript
@@ -163,7 +176,13 @@ const electronPolyfills = (
163176
throw new Error('Failed to find playback window')
164177
}
165178
await retry(
166-
() => window.loadURL(absolutifyUrl(url!, session.projects.project.url)),
179+
() =>
180+
window.loadURL(
181+
absolutifyUrl(
182+
interpolateString(url!, executor.variables),
183+
session.projects.project.url
184+
)
185+
),
167186
5,
168187
100
169188
)
@@ -234,6 +253,7 @@ export default class DriverController extends BaseController {
234253
browserName,
235254
...capabilities,
236255
...(capabilities.webSocketUrl === false ? electronCapabilities : {}),
256+
...(turtlesMode ? ideCapabilities : {}),
237257
})
238258
.usingServer(server)
239259
.forBrowser(browserName)

packages/selenium-ide/src/main/session/controllers/Driver/start.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as fs from 'fs-extra'
55
import { BrowserInfo, Session } from 'main/types'
66
import * as path from 'node:path'
77
import * as os from 'os'
8-
import { COLOR_MAGENTA, COLOR_YELLOW, vdebuglog } from 'main/util'
8+
import { COLOR_MAGENTA, COLOR_YELLOW, isAutomated, vdebuglog } from 'main/util'
99

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

23-
export const port = app.isPackaged ? 9516 : 9515
23+
export const port = isAutomated ? 9518 : app.isPackaged ? 9516 : 9515
2424

2525
/**
2626
* This module is just an async function that does the following:
@@ -61,9 +61,6 @@ const startDriver: StartDriver = (session: Session) => (info) =>
6161
let initialized = false
6262
const args = ['--verbose', `--port=${port}`]
6363
const driverPath = getDriver(info)
64-
switch (info.browser) {
65-
case 'electron':
66-
}
6764
console.log(
6865
'Starting driver',
6966
info.browser,

packages/selenium-ide/src/main/session/controllers/Windows/index.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import electron, {
1010
import { existsSync, readFileSync } from 'fs'
1111
import kebabCase from 'lodash/fp/kebabCase'
1212
import { Session } from 'main/types'
13-
import { isAutomated } from 'main/util'
1413
import { join } from 'node:path'
1514
import BaseController from '../Base'
1615
import { window as playbackWindowOpts } from 'browser/windows/PlaybackWindow/controller'
@@ -21,7 +20,7 @@ const playbackCSS = readFileSync(join(__dirname, 'highlight.css'), 'utf-8')
2120
const playbackWindowOptions = {
2221
...playbackWindowOpts(),
2322
webPreferences: {
24-
devTools: !isAutomated,
23+
devTools: true,
2524
preload: join(__dirname, `playback-window-preload-bundle.js`),
2625
},
2726
}
@@ -56,7 +55,7 @@ const windowLoaderFactoryMap: WindowLoaderFactoryMap = Object.fromEntries(
5655
...windowConfig,
5756
..._options,
5857
webPreferences: {
59-
devTools: !isAutomated,
58+
devTools: true,
6059
...(windowConfig?.webPreferences ?? {}),
6160
preload: hasPreload ? preloadPath : undefined,
6261
sandbox: true,

0 commit comments

Comments
 (0)