webdriverio-community / wdio-electron-service Goto Github PK
View Code? Open in Web Editor NEWWebdriverIO service for testing Electron applications
Home Page: https://webdriver.io
License: MIT License
WebdriverIO service for testing Electron applications
Home Page: https://webdriver.io
License: MIT License
which, most likely, it is still true when rephrased like ' wdio-electron-service cannot be used for most of the existing (big) projects' or
'wdio-electron-service can be used only on new electron projects'
If I try to use wdio-electron-service with contextIsolation: false, I get an error like 'contextBridge needs contextIsolation to be true' and nothing works.
This is happening because the below code uses contextBridge
https://github.com/webdriverio-community/wdio-electron-service/blob/main/src/preload.ts
But if I put contextIsolation: true for getting wdio-electron-service to work I get another error like 'require function not defined' and nothing works. This is happening because I have an existing project where the require function is needed and this project cannot be easily updated as per the latest Electron security best practices (this will be done but it will take a longer period of time to migrate all the existing code).
I understand that the newer versions of Electron, for security reasons, strongly recommends having contextIsolation:true and this is good for new projects but for older and bigger projects it takes more effort to update all the existing code which means that many times people will use contextIsolation:false for such projects.
I believe that wdio-electron-service should work no matter if contextIsolation:true or contextIsolation:false since your library should enable people to use webdriver.io in electron no matter if contextIsolation:true or contextIsolation:false (people will use this flag not because they want to but because for existing projects, they have no other choice).
The getBinaryPath
helper is currently tied to apps built with electron-builder
.
It might do something different in the case where electron-builder
(or Electron Forge) is not found, so that you can do for example (MacOS):
appBinaryPath: getBinaryPath('/Applications', 'myApp')
This would be functionally the same as
appBinaryPath: '/Applications/myApp.app/Contents/MacOS/myApp'
As part of the v8 effort we are currently migrating over to ESM as many packages will stop support CJS in the future. This means we have to transition all plugins to ESM as well, ideally with continuous support for CJS.
The first report of someone experiencing this directly with the service (apart from during the early stages of development) has been reported in #46...
The service docs should be updated to provide some of the information relayed in that issue, which should probably be part of a generalised section around debug / known issues.
We should support the user supplying an array of mappings for browser extensions to access custom API functions on the main process. Unless a clever solution can be found, they will need to use the same contextBridge channel.
Currently you can mock specific ElectronJS apis via, e.g.:
await browser.electron.mock('dialog', 'showOpenDialog', 'dialog opened!');
This approach has several limitations:
I suggest to align the mocking interface to what we strive for in WebdriverIO as well. The following primitives should be not to difficult to implement in the serviceL
execute
command that allows to run arbitrary code in the main processconst res = await browser.electron.execute((electron) => {
electron.dialog.showOpenDialog('foobar')
return 123
})
// console.log(res) // outputs 123
const dialog = await browser.electron.mock('dialog', 'showOpenDialog')
expect(dialog).toBeCalledTimes(2)
expect(dialog).toBeCalledWith('Hello World!')
With the recent release of WebdriverIO that includes new features around browser driver management it seems to have broken this service capabilities to do that for the user. I propose to have it set hostname
and port
capabilities so that WebdriverIO recognises to not have to setup the browser and driver itself.
Maybe this service can leverage these features and remove some code that prior downloaded Chromedriver.
I can run with webdriverio v8.13, but in later versions the chrome driver isn't resolved correctly.
I noticed that as of 8.14 wdio-chromdriver-service is deprecated and no longer maintained. There's also a blog post about how 8.14 handles chrome driver resolution for you.
Passing an electronVersion is ignored as is passing a chromedriverCustomPath. The runner located the electron executable and refuses to run because the driver it has selected (for the installed chrome) isn't a match.
I can run with 8.13, but after, including 8.15 seems DOA due to upstream changes.
The example repos should be using sandboxing and the new code in the README.
Hello,
I've started to test an application with Electron 22.0.0. We asked for the dialog support for electron what is come true, but now I ran into some configuration errors. Somebody can help me out what did I missed? (application build on windows 'release' dir. Angular 15 app.
when i run test i got:
Cannot read properties of undefined (reading 'electron')
[electron 22.0.0 win32 #0-0] TypeError: Cannot read properties of undefined (reading 'electron')
[electron 22.0.0 win32 #0-0] at LicenseSelector.<anonymous> (C:\Users\user\IdeaProjects\electronapp\test\pageobjects\page.ts:64:19)
main.ts
import('wdio-electron-service/dist/main')
const VISIBLE_SIDEBAR_MIN_WINDOWS_WIDTH = 1050
const VISIBLE_SIDEBAR_MIN_WINDOWS_HEIGHT = 750
win = new BrowserWindow({
width: initialWindowWidth,
height: initialWindowHeight,
minWidth: 800,
minHeight: 600,
title: CommonConstants.APP_TITLE,
icon: path.join(assetsDir, 'icon.icns'),
center: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, 'preload.js'),
sandbox: false,
},
})
preload.js
// build in support
require('wdio-electron-service/dist/preload')
wdio.conf.ts
import * as Path from 'path'
// More info on
// https://webdriver.io/docs/configurationfile/
export const config = {
runner: 'local',
specs: [Path.join(__dirname, 'test', 'specs', '*.ts')],
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
browserName: 'electron',
},
],
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
project: './test/tsconfig.json',
transpileOnly: true,
},
},
logLevel: 'info',
bail: 1,
baseUrl: 'http://127.0.0.1',
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
services: [
[
'electron',
{
appPath: Path.join(__dirname, 'release'),
appName: 'Application',
electronVersion: '22.0.0',
},
],
],
framework: 'mocha',
reporters: ['spec'],
mochaOpts: {
ui: 'bdd',
retries: 0,
timeout: 30 * 1000, // 30 sec
},
}
page.ts
import { browser } from 'wdio-electron-service'
/**
* Main page object containing all methods, selectors and functionality
* that is shared across all page objects
*/
export default class Page {
/**
* Get title from electron window
*/
async title(): Promise<string> {
return (await browser.electron.app('getName')) as Promise<string> // this line cause the error
}
/**
* Wait for upload filepath via browser windows
* @param selector element id for open the browser
* @param path path to file
*/
async waitForFileUpload(selector: string, path: string) {
await browser.electron.mock('dialog', 'showOpenDialog', 'path/to/file') // this line cause the error
const result = await browser.electron.dialog('showOpenDialog') // this line cause the error
console.log('result:' + result)
}
}
package.json
{
"main": "main.js",
"scripts": {
"wdio": "pnpm exec wdio run ./wdio.conf.ts"
},
"dependencies": {
"@electron/remote": "2.0.9",
...
"electron-updater": "5.3.0",
...
"wdio-electron-service": "4.1.0",
"webdriverio": "8.11.2"
},
"devDependencies": {
...
"@wdio/cli": "8.6.9",
"@wdio/devtools-service": "8.6.9",
"@wdio/junit-reporter": "8.6.8",
"@wdio/spec-reporter": "8.6.8",
"@wdio/local-runner": "8.6.9",
"@wdio/mocha-framework": "8.6.8",
...
"electron": "22.0.0",
"electron-builder": "23.6.0",
"electron-reload": "2.0.0-alpha.1",
...
"wait-on": "7.0.1",
"wdio-chromedriver-service": "8.1.1",
"wdio-cucumberjs-json-reporter": "4.4.3",
"wdio-eslinter-service": "0.0.4",
"wdio-json-reporter": "3.0.0",
"wdio-wait-for": "3.0.2",
"webdriver-manager": "12.1.8",
...
}
We currently use electron-chromedriver
to download the version of chromedriver which works with the latest version of electron, but if you are testing an app which is built with a different electron version then you will get version mismatch errors.
The following workaround needs to be properly documented and also to work with windows:
npm i --save chromedriver@94
chromedriver: {
port: 9519,
logFileName: 'wdio-chromedriver.log',
chromedriverCustomPath: 'node_modules/chromedriver/bin/chromedriver'
}
npm i --save electron-chromedriver@16
chromedriver: {
port: 9519,
logFileName: 'wdio-chromedriver.log',
chromedriverCustomPath: require.resolve('electron-chromedriver')
}
The batch file seems to be absent from the package and is not installed on windows, leading to chromedriver startup failure.
Would be nice to have some automated tests for this verifying the integration with WDIO. The wdio-geckodriver-service
has a nice solution in this area but relies on Firefox being available on the GH action runner. For Electron it would be more complicated, requiring a sample app to be built. Could pull down wdio-electron-service-example
and run those E2Es, or find some way to integrate that repo with this one.
https://github.com/webdriverio-community/wdio-geckodriver-service/blob/main/test/wdio.conf.js
Discussion here.
If you want to use the Electron APIs the browser commands are not correctly typed. This is made more complicated by customisable APIs, in this case I think we should just let the user provide typings for the custom commands and we will make types available for the commands provided by wdio-electron-service
.
wdio-electron-service-example
should be switched to TS as part of fixing this.
If the wdio.conf.js
file is in a sub directory, the service won't find the Electron version automatically anymore because the config file is not located next to a package.json
anymore. I suggest to use pkg-up
to find the closest one.
Dependabot does not currently have PNPM support (see this long-running issue) though a kind soul produced this gist to make it work (in theory):
https://gist.github.com/Purpzie/8ed86ae38c73f440881bbee0523a324b
The alternative is to use Renovatebot which works well with alternative package managers, but that is not currently installed on the webdriverio-community
org.
EDIT: seems we have some action finally on the dependabot support: dependabot/dependabot-core#1736 (comment)
The electron-builder config is currently assumed to be in package.json, it can also be in electron-builder.json
. EB supports YML/TOML flavours of this file too but I suspect usage of those is minimal so we should just support the JSON variant for now.
Ideally the WDIO CLI should auto-detect configuration in as many cases as possible when using electron-builder
or Electron Forge. Most users should not have to find the path to their app binary themselves.
pkg-up
to find the nearest package.jsonelectron-builder
or @electron-forge/cli
is being used
electron-builder
or @electron-forge/cli
is being used
appBinaryPath
appBinaryPath
https://www.electron.build/configuration/configuration
https://www.electronforge.io/config/configuration
electron-builder
is found, try to read config from the following in order:
@electron-forge/cli
is found, try to read config from the following in order:
config.forge
key in package.jsongetBinaryPath
to set the appBinaryPath
appBinaryPath
While testing out the wdio-electron-service-example project on a Windows machine I noticed that the chromedriver process was not being cleaned up after running the test suite (with npx wdio
).
I believe this line in the launcher is the start of the issue (snippet copied below).
if (isWin) {
process.env.WDIO_ELECTRON_NODE_PATH = process.execPath;
process.env.WDIO_ELECTRON_CHROMEDRIVER_PATH = chromedriverServiceOptions.chromedriverCustomPath;
chromedriverServiceOptions.chromedriverCustomPath = join(__dirname, '..', 'bin', 'chrome-driver.bat');
}
This is overriding any path to chromedriver (whether custom or default) to instead use this .bat file.
@echo off
"%WDIO_ELECTRON_NODE_PATH%" "%WDIO_ELECTRON_CHROMEDRIVER_PATH%" %*
if ERRORLEVEL 1 exit /b 1
exit /b 0
Now, this does make sense since the default chromedriverCustomPath
points to node_modules\electron-chromedriver\chromedriver.js
. However, the .bat file does not wait for node to exit before the terminal running the .bat file is allowed to exit. Node is allowed to keep running while its original parent terminal process has died, which causes problems in the wdio-chromedriver-service
.
At this line of the wdio-chromedriver-service
the child process for chromedriver is spawned and a reference kept, although because of the .bat file override earlier, this.process
refers to the terminal process that will soon start Node.
By the time we hit the this.process.kill()
command in the onComplete
service handler, this.process
has already long since died and the Node/chromedriver processes are running as their own process tree, disconnected from this.process
.
An example process tree might look like this (pids taken from my last run):
cmd.exe (28956) [this.process] <-- dies immediately after node.exe is started
|____ node.exe (22832)
|____ chromedriver.exe (24100)
A real solution to this issue will likely involve tracking the child node process or communicating with it to collaboratively shutdown. Unfortunately I don't have anything like that to offer right now, though I do have a relatively small workaround fix that would at least mitigate the problem.
The use of the .bat file launcher seems to only make sense if a chromedriver file is provided that needs to run within node (js file). If a user provides a path to chromedriver.exe in chromedriverCustomPath
, it is currently still passed through to the .bat file to be run in Node. I propose that we only use the .bat file for .js files and allow any other extension to be run directly via child_process.spawn()
.
Something like (in launcher.ts):
import { join, extname } from 'path';
// snip...
if (isWin) {
process.env.WDIO_ELECTRON_NODE_PATH = process.execPath;
process.env.WDIO_ELECTRON_CHROMEDRIVER_PATH = chromedriverServiceOptions.chromedriverCustomPath;
const shouldRunInNode = extname(chromedriverServiceOptions.chromedriverCustomPath) === '.js';
if (shouldRunInNode) {
chromedriverServiceOptions.chromedriverCustomPath = join(__dirname, '..', 'bin', 'chrome-driver.bat');
}
}
This would allow anyone encountering this issue to specify the chromedriver.exe path themselves and bypass the extra .bat file redirection (from wdio.conf.js):
const config = [
services: [
[
'electron',
{
appPath: join(__dirname, 'dist'),
appName: productName,
appArgs: ['foo', 'bar=baz'],
chromedriver: {
port: 9519,
logFileName: 'wdio-chromedriver.log',
// provide custom path to .exe to bypass use of .bat file
chromedriverCustomPath: require.resolve('electron-chromedriver/bin/chromedriver.exe'),
},
},
],
],
// snip...
]
This work around solves the problem in my case. Specs in the example project complete successfully and the chromedriver process dies at the end. If the work around is acceptable, I would be happy to submit a PR.
Extra logging which can be enabled in wdio-electron-service-example
.
Will help with development of #31
Hello,
after initiating a new project using `npm init wdio .', and configuring the electron service as described here, I'm getting the following error message:
@wdio/runner: wdio8-test/node_modules/wdio-electron-service/dist/cjs/index.js:35
export {};
^^^^^^
SyntaxError: Unexpected token 'export'
at internalCompileFunction (node:internal/vm:73:18)
at wrapSafe (node:internal/modules/cjs/loader:1176:20)
at Module._compile (node:internal/modules/cjs/loader:1218:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
at Object.require.extensions.<computed> [as .js] (wdio8-test/node_modules/ts-node/src/index.ts:1608:43)
at Module.load (node:internal/modules/cjs/loader:1117:32)
at Module._load (node:internal/modules/cjs/loader:958:12)
at Function.hookedLoader [as _load] (wdio8-test/node_modules/mockery/mockery.js:111:12)
at Module.require (node:internal/modules/cjs/loader:1141:19)
at require (node:internal/modules/cjs/helpers:110:18)
The wdio.conf.ts is this:
import type { Options } from "@wdio/types";
import * as path from "path";
export const config: Options.Testrunner = {
runner: "local",
outputDir: "all-logs",
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
files: true,
project: "./tsconfig.json",
transpileOnly: true,
},
},
specs: ["./features/**/*.feature"],
exclude: [],
maxInstances: 10,
capabilities: [
{
maxInstances: 5,
browserName: "chrome",
acceptInsecureCerts: true,
},
],
logLevel: "trace",
bail: 0,
baseUrl: "http://localhost",
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
services: [
[
"electron",
{
appPath: path.join(__dirname, "binaries"),
appName: "App Name",
electronVersion: "22.0.0",
},
],
],
framework: "cucumber",
reporters: ["spec"],
cucumberOpts: {
require: ["./features/step-definitions/steps.ts"],
backtrace: true,
requireModule: [],
dryRun: false,
failFast: false,
snippets: true,
source: true,
strict: false,
tagExpression: "",
timeout: 60000,
ignoreUndefinedDefinitions: false,
},
};
and the package.json like this:
{
"name": "wdio8-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"wdio": "wdio run ./wdio.conf.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@wdio/cli": "^8.6.7",
"@wdio/cucumber-framework": "^8.6.6",
"@wdio/local-runner": "^8.6.7",
"@wdio/spec-reporter": "^8.6.6",
"chromedriver": "^111.0.0",
"prettier": "^2.8.6",
"ts-node": "^10.9.1",
"typescript": "^5.0.2",
"wdio-chromedriver-service": "^8.1.1",
"wdio-electron-service": "^4.0.0"
}
}
node version is 18.15.0, tried it also with node 16.14.0.
For me, it looks like it tries to use the CommonJS version of wdio-electron-service, but everything else uses esm already.
Might this be a problem?
Setting "type": "module"
in package.json leads to this error instead:
wdio run ./wdio.conf.ts
2023-03-22T09:14:30.671Z ERROR @wdio/config:ConfigParser: Failed loading configuration file: file:///wdio8-test/wdio.conf.ts: exports is not defined in ES module scope
ReferenceError: exports is not defined in ES module scope
at file:///wdio8-test/wdio.conf.ts:2:23
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
Process finished with exit code 1
Just curious
When trying to set up the electron-service with npm init electron-app@latest my-app
(electron forge) and the wdio installer, I get the contextBridge Error when trying to run my packaged app (.exe) against the auto-generated test from create-wdio, despite loading the main & preload scripts from the service
Repo with reproduction Steps: https://github.com/tomm1996/electron-forge-wdio-test
Windows 22H2 Build 22621.2361
Addresses a comment made by an Electron core maintainer in electron/electron#39380 (comment). Can we just pick the version from the package.json
?
Hey, trying to run cucumber tests against electron inside docker in Jenkins and we're seeing this kinda error:
Request failed with status 500 due to unknown error: Chrome failed to start: exited abnormally.
(DevToolsActivePort file doesn't exist)
(The process started from chrome location ... is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
Internet suggests that I should be passing --disable-dev-shm-usage
flag for the chromium, but haven't been able to do that.
Any helpers or advice that I might have overlooked?
I'm doing a migration from spectron to wdio at the moment.
The docker entrypoint making use of xvfb was configured already for spectron and I guess it should work similarly for the wdio also?
wdio.conf.ts
services: [
[
'electron',
{
appPath: join(__dirname, '../../../package'),
appName: productName,
appArgs: [
"--disable-infobars", // not sure if this is needed
"--disable-dev-shm-usage",
"--no-sandbox", // not sure if this is needed
"--headless", // not sure if this is needed
],
chromedriver: {
port: 9519,
logFileName: 'wdio-chromedriver.log',
},
},
],
],
Grateful for any tips :)
We should use Electron Forge for building the main two example apps (example
& example-cjs
).
Proposing a new example-electron-builder
(ESM - duplicate of example
) for testing an app built with EB.
The Spectron fork from which this service was derived supported a number of Electron APIs, we should recreate this but with a different approach.
Despite the size and scope of the APIs provided by Electron, the number of functions which may be useful for testers is actually pretty small, so the greedy property looping and filtering of the Spectron fork can be ditched in favour of a whitelist. This has the benefit of avoiding the problem experienced by the Enzyme React testing library in which users would rely on directly manipulating component state, props, context in their suites, which results in immensely brittle tests; we only really want to be exposing Electron APIs which provide a way of testing values which are difficult or impossible to get hold of through WebdriverIO Testing Library or the browser
object.
Other constraints on what we allow access to (and how) will be:
main
and renderer
processes.API functions can be made available on the browser
object, namespaced under electron
. A minimal set of functionality will be exposed to begin with, users can raise issues / submit PRs to expose more Electron functionality if they want and documentation should be updated to encourage this.
This issue will be closed once the initial basic level of API support has been enabled.
The documentation for the service would benefit from being split into separate files with the main README dedicated to an overview of the service, "quick setup" section and links. We could also leverage the Github Wiki.
Currently we reload the session between tests to prevent state bleed, this should be configurable so that users can manage their own test state if they wish.
When running:
npm i -D wdio-electron-service
I am getting:
'''
npx only-allow pnpm
npx: installed 20 in 3.69s
╔═════════════════════════════════════════════════════════════╗
║ ║
║ Use "pnpm install" for installation in this project. ║
║ ║
║ If you don't have pnpm, install it via "npm i -g pnpm". ║
║ For more details, go to https://pnpm.js.org/
I am using:
npm: '8.5.2',
node: '14.18.1'
Is pnmp required to use the service?
We should make sure the official docs are updated with the new wizard and the service:
https://www.electronjs.org/docs/latest/tutorial/automated-testing
It seems the electron-builder generates the path like {outputDir}/mac-arm64.
https://github.com/electron-userland/electron-builder/blob/53327d51101b83641ece9f497577c3ac93d3e91d/packages/app-builder-lib/src/platformPackager.ts#L119
hardcoded 'mac' makes it incompatible
wdio-electron-service/src/service.ts
Line 28 in d28dce9
Hi!
I really like your work! Now I've just ran into a problem, there is a button with no inputto file upload in a project. I need to handle the electron dialog with sendkeys or just retrun some value as close event. Is there any solution for that?
Thanks and again great work!
Could we consider extending multi-remote capabilities to this service?
Use cases are to drive more than one app in parallel as well as a browser, etc.
We are currently requiring chromedriver
as a peerdep and initial testing suggests it is required - it seems the use of electron-chromedriver
does not fulfil this.
Possible options available:
electron-chromedriver
for chromedriver
and change docs to reflect that chromedriver
is a required peerdepwdio-chromedriver-service
to make chromedriver
an optional peerdepHi,
we have an Electron app that is mostly tested through wdio but some tests did rely on Spectron. I was thinking of just writing ipcMain listeners in the test bundle of our app whenever the test suite needs to do some electron-main specific functionality. Does this service provide a way to send a message to ipcMain of the app from our test suite? Or, is there a way to do that even without using this service?
Thanks
Upgrading TS to 5.1.x
results in the following compilation errors:
error TS2688: Cannot find type definition file for '@wdio/globals/types'.
The file is in the program because:
Entry point of type library '@wdio/globals/types' specified in compilerOptions
tsconfig.json:8:23
8 "types": ["node", "@wdio/globals/types"]
~~~~~~~~~~~~~~~~~~~~~
File is entry point of type library specified here.
src/service.ts:179:27 - error TS2684: The 'this' context of type 'WebdriverIO.Browser' is not assignable to method's 'this' of type 'import("<snip />/wdio-electron-service/node_modules/.pnpm/[email protected][email protected]/node_modules/webdriverio/build/types").Browser'.
Type 'Browser' is missing the following properties from type 'Browser': sessionStatus, sessionNew, sessionEnd, sessionSubscribe, and 25 more.
179 return await (browser.executeAsync as WebdriverClientFunc)(callApi, bridgeProp, args);
~~~~~~~
src/service.ts:179:27 - error TS2352: Conversion of type '<ReturnValue, InnerArguments extends any[]>(this: Browser | Element, script: string | ((...args: [...innerArgs: InnerArguments, callback: (result?: ReturnValue | undefined) => void]) => void), ...args: InnerArguments) => Promise<...>' to type 'WebdriverClientFunc' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
The 'this' types of each signature are incompatible.
Type 'Browser' is not comparable to type 'Browser | Element'.
Type 'Browser' is missing the following properties from type 'Element': elementId, ELEMENT, selector, parent, and 38 more.
179 return await (browser.executeAsync as WebdriverClientFunc)(callApi, bridgeProp, args);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Given that Electron will soon be supporting ESM natively, we should have a separate ESM example app and collapse the e2e packages into the example apps appropriately.
e.g. example/e2e/test
=> example/e2e
and example/e2e-cjs/test
=> example-cjs/e2e
.
The custom API is somewhat clunky to use, we might improve this by using a pattern borrowed from Playwright, which evaluates a function in the electron context, passing Electron main process APIs directly into the function. Some investigation is required to ascertain how the following works in Playwright:
// Launch Electron app.
const electronApp = await electron.launch({ args: ['main.js'] });
// Evaluation expression in the Electron context.
const appPath = await electronApp.evaluate(async ({ app }) => {
// This runs in the main Electron process, parameter here is always
// the result of the require('electron') in the main app script.
return app.getAppPath();
});
One possibility for this could be the WebContents executeJavaScriptInIsolatedWorld method.
Hello! I'm having an issue with trying to get the service up and running when using WDIO in a script running Jest. I've tried a couple of things, and the closest I got was doing the following:
Before test, start chromedriver:
const args = [ chromedriverPath, '--remote-debugging-port=9515', '--url-base=/', '--verbose', ]; const cdProcess = child_process.spawn(process.execPath, args);
Then create my remote:
const app = await remote({ logLevel: 'trace', services: [ [ 'electron', { appPath: appPath, appName: appName, chromedriver: { port: 9515, chromedriverCustomPath: chromedriverPath, logFileName: 'wdio-chromedriver.log', }, }, ], ], capabilities: { browserName: 'chrome', 'goog:chromeOptions': { binary: appExecutable, }, }, port: 9515, });
This will successfully start my electron application and let me do native WDIO things (app.saveScreenshot()
works as expected), however I get the following error when trying to use electronApp
:
TypeError: app.electronApp is not a function > 90 | const appName = await app.electronApp('getName'); | ^ 91 | console.log(appName);
I'm admittedly VERY new to WDIO so I'm fully aware that I may be missing something silly, but any advice I could get would be very much appreciated.
Thanks!
Initial discussion here.
The user should be able to specify an electron version for which the service will download and use the appropriate version of Chromedriver. Existing customPath prop should still work in case the user wants to roll their own.
Can use https://github.com/electron/get in a similar way to electron-chromedriver
, alternatively there is also electron-to-chromium
.
Prior art:
https://github.com/webdriverio-community/wdio-vscode-service
https://github.com/electron/chromedriver
We should allow customisation of the chromeArgs settings.
The chromeArgs defaults currently used by the service were defined when looking to fix the DevToolsActivePort file doesn't exist
error on CI, so in the first instance we should define which defaults are actually required and for what reasons.
Required args should still be applied by the service but with the option for users to override them if they wish. There is some logic around which args are applied (CI / non-Windows platforms); the service should use the default for each required arg only when the user has not specified that particular arg.
Additionally, #47 could be a part of this work.
I'm shopping for a Spectron replacement and since I'm looking under the hood...
Spectron exposed electron app innards by being constructed in the test runner and either your app has node integration enabled or it conditionally provided a require function for Spectron to use to gain access. So outside of the testing it had no effect (unless the environment var for testing is set during the pre-load).
The recommended way of getting at the innards with wdio-electron-service it so modify the preload and the content scripts to import scripts that patch the app to expose the innards over the context bridge. This has a lasting effect outside of the testing environment.
Since we use webpack, conditionally including the scripts doesn't work (we're not setup for dynamic imports yet)... but wrapping the included scripts internally with an if might be a way to accomplish this. Though I might just be missing something!
You installed the necessary packages with the following command:
npm i -D wdio-electron-service
And you also installed Electron in the Quasar Framework using the following commands:
npm init quasar
...
npx quasar dev -m electron
However, you encountered a problem during the installation process with the following error message:
**npx run ./wdio.conf.js**
? A project named "quasar-project" was detected at "C:\Users\shine\OneDrive\문서\workspace\node\mocha\quasar-project", correct? Yes
? What type of testing would you like to do? Desktop Testing - of Electron Applications
> https://webdriver.io/docs/desktop-testing/electron
? What is the path to your compiled Electron app? .quasar
? Which framework do you want to use? Mocha (https://mochajs.org/)
? Do you want to use a compiler? TypeScript (https://www.typescriptlang.org/)
? Do you want WebdriverIO to autogenerate some test files? Yes
? Where should these files be located? C:\Users\shine\OneDrive\문서\workspace\node\mocha\quasar-project\test\specs\**\*.ts
? Which reporter do you want to use? spec
? Do you want to add a plugin to your test setup? wait-for
? Do you want to add a service to your test setup? electron
? Do you want me to run `npm install` Yes
Setting up TypeScript...
✔ Success!
Installing wdio packages:
- @wdio/local-runner@latest
- @wdio/mocha-framework@latest
- @wdio/spec-reporter@latest
- wdio-wait-for
- wdio-electron-service
- ts-node
- typescript
added 58 packages, and audited 774 packages in 8s
154 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
✔ Success!
Creating a WebdriverIO config file...
✔ Success!
Autogenerating test files...
✔ Success!
Adding "wdio" script to package.json.
✔ Success!
To run your tests, execute:
$ cd C:\Users\shine\OneDrive\문서\workspace\node\mocha\quasar-project
$ npm run wdio
Adding scripts to package.json
node:internal/modules/cjs/loader:985
const err = new Error(message);
^
Error: Cannot find module 'C:\Users\shine\OneDrive\문서\workspace\node\mocha\quasar-project\run\package.json'
Require stack:
- C:\Users\shine\AppData\Local\npm-cache\_npx\471611576716610c\node_modules\wdio\build\index.js
- C:\Users\shine\AppData\Local\npm-cache\_npx\471611576716610c\node_modules\wdio\bin\wdio.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:985:15)
at Function.Module._load (node:internal/modules/cjs/loader:833:27)
at Module.require (node:internal/modules/cjs/loader:1057:19)
at require (node:internal/modules/cjs/helpers:103:18)
at createWebdriverIO (C:\Users\shine\AppData\Local\npm-cache\_npx\471611576716610c\node_modules\wdio\build\index.js:81:21) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'C:\\Users\\shine\\AppData\\Local\\npm-cache\\_npx\\471611576716610c\\node_modules\\wdio\\build\\index.js',
'C:\\Users\\shine\\AppData\\Local\\npm-cache\\_npx\\471611576716610c\\node_modules\\wdio\\bin\\wdio.js'
]
}
We should add a section to the main documentation "Electron Testing" with some documentation how to get started with this service and what a user needs to do to test an Electron application. It would be also nice if we could maybe integrate this into the WDIO configuration wizard.
We may be able to remove some dependencies by using the native Node testrunner for unit tests instead of Vitest. Requires investigation once the service has been updated from Node 16 to Node 20, where the Test API is stable.
Spectron had a timeout function for a test to wait until the window was loaded, we might need to implement something like this. The wdio-electron-service-example
window title test is quite flaky on CI (fine locally) and is dependent on the 'ready-to-show' handler being called for the title to be updated, I suspect there is a race condition.
https://github.com/goosewobbler/wdio-electron-service-example/blob/main/test/api.spec.ts#L31
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.