Skip to content

Commit 8e05ce1

Browse files
committed
using webdriver to test the ide pt 1
1 parent 4a2f71a commit 8e05ce1

File tree

12 files changed

+180
-48
lines changed

12 files changed

+180
-48
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"license": "Apache-2.0",
55
"private": true,
66
"scripts": {
7-
"start": "cd packages/selenium-ide && pnpm run start",
87
"start:test-site": "http-server -p 8080 ./tests/static",
98
"build": "run-s build:ts build:ide",
109
"build:electron": "pnpm run --stream --filter @seleniumhq/selenium-ide build:electron",
@@ -18,7 +17,7 @@
1817
"test:e2e": "jest --testMatch \"**/packages/**/__tests__/**/*.e2e.js\"",
1918
"lint": "pnpm run lint:scripts",
2019
"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/",
21-
"test:ide": "npm-run-bg -s 'http-server -p 8080 ./tests/static::Available on::8080' 'node ./scripts/ide-runner.js -t 15000 ./tests/examples/*.side'",
20+
"test:ide": "npm-run-bg -s 'http-server -p 8080 ./tests/static::Available on::8080' 'node ./packages/selenium-ide/scripts/ide-runner.js -t 15000 ./tests/examples/*.side'",
2221
"test:side-runner": "npm-run-bg -s 'http-server -p 8080 ./tests/static::Available on::8080' 'node ./packages/side-runner/dist/bin.js -t 15000 ./tests/examples/*.side'",
2322
"test:side-runner:ci": "npm-run-bg -s 'http-server -p 8080 ./tests/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'",
2423
"typecheck": "tsc --noEmit --composite false",

packages/selenium-ide/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
"@seleniumhq/code-export-ruby-rspec": "^4.0.0-alpha.1",
107107
"side-code-export": "^4.0.0-alpha.11",
108108
"@seleniumhq/get-driver": "^4.0.0-alpha.1",
109-
"@seleniumhq/side-api": "^4.0.0-alpha.27",
109+
"@seleniumhq/side-api": "^4.0.0-alpha.29",
110110
"@seleniumhq/side-model": "^4.0.0-alpha.4",
111111
"@seleniumhq/side-runtime": "^4.0.0-alpha.27",
112112
"dnd-core": "^16.0.1",
@@ -143,6 +143,7 @@
143143
"npm-run-all": "^4.1.5",
144144
"run-script-os": "^1.1.6",
145145
"scroll-into-view-if-needed": "^3.0.10",
146+
"selenium-webdriver": "^4.11.1",
146147
"source-map-loader": "^4.0.1",
147148
"source-map-support": "^0.5.21",
148149
"style-loader": "^3.3.3",
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
const args = process.argv
2+
3+
const { spawn } = require('child_process')
4+
const webdriver = require('selenium-webdriver')
5+
const fs = require('fs')
6+
const path = require('path')
7+
const os = require('os')
8+
9+
const WebdriverDebugLog = console.log // debuglog('webdriver')
10+
11+
const appName = 'Electron'
12+
13+
const driverPath = path.join(
14+
__dirname,
15+
'..',
16+
'node_modules',
17+
'electron-chromedriver',
18+
'bin',
19+
'chromedriver' + (os.platform() === 'win32' ? '.exe' : '')
20+
)
21+
22+
const electronBinaryPath = path.join(
23+
require.resolve('electron'),
24+
'..',
25+
'dist',
26+
appName + '.app',
27+
'Contents',
28+
'MacOS',
29+
appName
30+
)
31+
32+
const pathToSeleniumIDE = path.join(__dirname, '..', 'build', 'main-bundle.js')
33+
34+
const port = 9518
35+
main()
36+
37+
async function main() {
38+
console.log('Starting webdriver backend')
39+
await startWebdriverBackend({ driver: 'chrome' })
40+
const sideFiles = args.filter((arg) => arg.endsWith('.side'))
41+
for (const sideFile of sideFiles) {
42+
console.log('Starting driver for sidefile', sideFile)
43+
const driver = await new webdriver.Builder()
44+
.usingServer(`http://localhost:${port}`)
45+
.withCapabilities({
46+
'goog:chromeOptions': {
47+
// Here is the path to your Electron binary.
48+
binary: electronBinaryPath,
49+
args: [
50+
'app=' + pathToSeleniumIDE,
51+
`side-file=./../../${sideFile.replace('./', '')}`,
52+
],
53+
},
54+
})
55+
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
56+
.build()
57+
await driver.sleep(10000)
58+
await driver.quit()
59+
return
60+
}
61+
}
62+
63+
function startWebdriverBackend() {
64+
const successMessage = 'was started successfully.'
65+
return new Promise((resolve) => {
66+
let initialized = false
67+
const args = ['--verbose', `--port=${port}`]
68+
if (fs.existsSync(driverPath)) {
69+
const driver = spawn(driverPath.replace(/\s/g, ' '), args, {
70+
env: {},
71+
shell: false,
72+
})
73+
process.on('exit', () => {
74+
driver.kill()
75+
})
76+
driver.stdout.on('data', (out) => {
77+
const outStr = `${out}`
78+
WebdriverDebugLog(outStr)
79+
const fullyStarted = outStr.includes(successMessage)
80+
if (fullyStarted) {
81+
initialized = true
82+
WebdriverDebugLog('Driver has initialized!')
83+
resolve({ success: true, driver: driver })
84+
}
85+
})
86+
driver.stderr.on('data', (err) => {
87+
const errStr = `${err}`
88+
WebdriverDebugLog(errStr)
89+
if (!initialized) {
90+
resolve({ success: false, error: errStr })
91+
}
92+
})
93+
driver.on('close', (code) => {
94+
if (code) {
95+
WebdriverDebugLog(`driver has exited with code ${code}`)
96+
if (!initialized) {
97+
resolve({
98+
success: false,
99+
error: 'Process has exited before starting with code ' + code,
100+
})
101+
}
102+
}
103+
})
104+
} else {
105+
resolve({
106+
success: false,
107+
error: `Missing executable at path ${driverPath}`,
108+
})
109+
}
110+
})
111+
}

packages/selenium-ide/src/main/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { configureLogging, connectSessionLogging } from './log'
55
import store from './store'
66
import createSession from './session'
77
import installReactDevtools from './install-react-devtools'
8+
import { isAutomated } from './util'
89

910
// Configure logging
1011
configureLogging();
1112

12-
// Enable debugging - required for electron-chromedriv\
13+
// Enable debugging - required for electron-chromedriver
1314
app.commandLine.appendSwitch('remote-debugging-port', '8315')
1415

1516
// Capture and show unhandled exceptions
@@ -34,7 +35,9 @@ app.on('open-file', async (_e, path) => {
3435

3536
// Start and stop hooks
3637
app.on('ready', async () => {
37-
!app.isPackaged && installReactDevtools()
38+
if (!app.isPackaged && !isAutomated) {
39+
installReactDevtools()
40+
}
3841
await session.system.startup()
3942

4043
process.on('SIGINT', async () => {

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

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Session } from 'main/types'
88
import { randomUUID } from 'crypto'
99
import RecentProjects from './Recent'
1010
import BaseController from '../Base'
11+
import { isAutomated } from 'main/util'
1112

1213
export default class ProjectsController {
1314
constructor(session: Session) {
@@ -116,27 +117,29 @@ export default class ProjectsController {
116117
return starterProject
117118
}
118119

119-
async load(filepath: string): Promise<CoreSessionData | null > {
120-
const fileExists = await fs.stat(filepath)
121-
.then(() => true)
122-
.catch(() => false);
123-
if(fileExists){
124-
const loadedProject = await this.load_v3(filepath)
125-
if (loadedProject) {
126-
if (this.loaded) {
127-
const confirm = await this.onProjectUnloaded()
128-
if (!confirm) {
129-
return null
120+
async load(filepath: string): Promise<CoreSessionData | null> {
121+
const fileExists = await fs
122+
.stat(filepath)
123+
.then(() => true)
124+
.catch(() => false)
125+
console.log('fileExists', filepath, process.cwd(), __dirname);
126+
if (fileExists) {
127+
const loadedProject = await this.load_v3(filepath)
128+
if (loadedProject) {
129+
if (this.loaded) {
130+
const confirm = await this.onProjectUnloaded()
131+
if (!confirm) {
132+
return null
133+
}
130134
}
135+
await this.onProjectLoaded(loadedProject, filepath)
136+
return await this.session.state.get()
131137
}
132-
await this.onProjectLoaded(loadedProject, filepath)
133-
return await this.session.state.get()
134-
}
135-
return null
136-
}else{
137-
this.doShowWarning()
138-
this.recentProjects.remove(filepath)
139-
return null
138+
return null
139+
} else {
140+
this.doShowWarning()
141+
this.recentProjects.remove(filepath)
142+
return null
140143
}
141144
}
142145

@@ -146,19 +149,15 @@ export default class ProjectsController {
146149

147150
async select(useArgs = false): Promise<void> {
148151
// When we're opened with a side file in the path
149-
let argsFilepath = process.argv[1]
150-
if (!this.session.app.isPackaged) {
151-
const mainArgIndex = process.argv.findIndex((arg) =>
152-
arg.endsWith('main-bundle.js')
153-
)
154-
if (mainArgIndex === -1) {
155-
argsFilepath = ''
156-
} else argsFilepath = process.argv[mainArgIndex + 1]
157-
}
152+
let argsFilepath = process.argv.find((arg) => arg.startsWith('--side-file=')) || ''
158153
if (this.filepath) {
159154
await this.load(this.filepath)
160155
} else if (useArgs && argsFilepath) {
161-
await this.load(argsFilepath)
156+
try {
157+
await this.load(argsFilepath.replace('--side-file=', ''))
158+
} catch (e) {
159+
console.warn(`Unable to load file from args: ${argsFilepath}`)
160+
}
162161
} else {
163162
await this.session.windows.open('splash')
164163
}
@@ -224,11 +223,11 @@ export default class ProjectsController {
224223
}
225224

226225
async doShowWarning(): Promise<boolean> {
227-
if (await this.projectHasChanged()) {
228-
await this.session.dialogs.showMessageBox(
229-
'The Project your trying to load is not found , Please create new Project',
230-
[ 'Ok']
231-
)
226+
if (!isAutomated && (await this.projectHasChanged())) {
227+
await this.session.dialogs.showMessageBox(
228+
"The project you're trying to load is not found , Please create a new project",
229+
['Ok']
230+
)
232231
}
233232
return true
234233
}

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { dialog } from 'electron'
22
import BaseController from '../Base'
3+
import { isAutomated } from 'main/util'
34

45
let firstTime = true
56
export default class SystemController extends BaseController {
@@ -11,16 +12,22 @@ export default class SystemController extends BaseController {
1112
}
1213
async startup() {
1314
if (this.isDown) {
14-
const startupError = await this.session.driver.startProcess()
15-
if (startupError) {
16-
await this.crash(`Unable to startup due to chromedriver error: ${startupError}`);
15+
await this.session.windows.open('logger')
16+
// If automated, assume we already have a chromedriver process running
17+
if (!isAutomated) {
18+
const startupError = await this.session.driver.startProcess()
19+
if (startupError) {
20+
await this.crash(
21+
`Unable to startup due to chromedriver error: ${startupError}`
22+
)
23+
}
1724
}
1825
await this.session.projects.select(firstTime)
19-
await this.session.windows.open('logger')
2026
this.isDown = false
2127
firstTime = false
2228
}
2329
}
30+
2431
async shutdown() {
2532
if (!this.isDown) {
2633
if (!this.shuttingDown) {
@@ -34,6 +41,7 @@ export default class SystemController extends BaseController {
3441
}
3542
}
3643
}
44+
3745
async crash(error: string) {
3846
await dialog.showMessageBox({
3947
message: error,
@@ -42,6 +50,7 @@ export default class SystemController extends BaseController {
4250
await this.shutdown()
4351
await this.quit()
4452
}
53+
4554
async quit() {
4655
await this.shutdown()
4756
if (this.isDown) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import { Session } from 'main/types'
1313
import storage from 'main/store'
1414
import { join } from 'path'
1515
import BaseController from '../Base'
16+
import { isAutomated } from 'main/util'
1617

1718
const playbackWindowName = 'playback-window'
1819
const playbackCSS = readFileSync(join(__dirname, 'highlight.css'), 'utf-8')
1920
const playbackWindowOptions = {
2021
webPreferences: {
22+
devTools: !isAutomated,
2123
nodeIntegration: false,
2224
nodeIntegrationInSubFrames: true,
2325
preload: join(__dirname, `playback-window-preload-bundle.js`),
@@ -53,6 +55,7 @@ const windowLoaderFactoryMap: WindowLoaderFactoryMap = Object.fromEntries(
5355
const win = new BrowserWindow({
5456
...windowConfig,
5557
webPreferences: {
58+
devTools: !isAutomated,
5659
...(windowConfig?.webPreferences ?? {}),
5760
preload: hasPreload ? preloadPath : undefined,
5861
},

packages/selenium-ide/src/main/util.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export const COLOR_MAGENTA = '\x1b[35m'
1010
export const COLOR_CYAN = '\x1b[36m'
1111
export const COLOR_WHITE = '\x1b[37m'
1212

13+
export const isAutomated = process.argv.includes('--enable-automation')
14+
1315
export const vdebuglog = (namespace: string, color: string) => {
1416
const isBin = app.isPackaged
1517
const prefix = isBin ? `${namespace}: ` : color

packages/side-api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@seleniumhq/side-api",
3-
"version": "4.0.0-alpha.28",
3+
"version": "4.0.0-alpha.29",
44
"private": false,
55
"description": "Selenium IDE API command shapes and such",
66
"author": "Todd Tarsi <[email protected]>",

packages/side-api/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Browser } from '@seleniumhq/get-driver'
44
import { StateShape } from './models/state'
55
import { PluginRuntimeShape } from '@seleniumhq/side-runtime'
66

7+
export * from '@seleniumhq/side-model/dist/types'
8+
79
export interface BrowserInfo extends Pick<Chrome.BrowserInfo, 'version'> {
810
browser: Browser
911
}

0 commit comments

Comments
 (0)