How to pack chromedriver.exe on Mac - selenium

I'm trying to use Selenium on Electron app and am using the following modules:
"chromedriver": "^78.0.1",
"selenium-webdriver": "^4.0.0-alpha.4",
"electron-builder": "^21.2.0",
I built my app on a Mac and Selenium is working fine. However, when I run Electron Selenium app on Widows it can't find chromedriver.
react-electron/node_modules/chromedriver is below.
Of course it doesn't have chromedriver.exe, so I put chromedriver.exe into chromedriver/bin. Then I built it again but the built app doesn't include chromedriver.exe. How can I pack chromedriver.exe into the built app?
I applicate your help.

I found the solution. I put chromedriver.exe into node_modules/chromedriver/lib/chromedriver.
I can check it was copied in
win-unpacked/resources/app.asar.unpacked/node_modules/chromedriver/lib/chromedriver/chromedriver.exe
When the app run, chromedriver can fined in C:\Users\user\AppData\Local\Programs\MyApp\resources\app.asar.unpacked\node_modules\chromedriver\lib\chromedriver\chromedriver.exe
I can get the driver path like this.
const chromedriver = require('chromedriver');
async getDriverPath() {
let driverPath:string = this.chromedriver.path;
driverPath = await driverPath.replace('app.asar','app.asar.unpacked');
log.info("this.driverPath " + driverPath);
return driverPath;
}
And also, I set driver path like this.
const webdriver = require('selenium-webdriver');
const {Builder} = webdriver;
let my_driver;
async startChrome() {
const driverPath = await this.getDriverPath();
const service = new chrome.ServiceBuilder(driverPath).build();
chrome.setDefaultService(service);
my_driver = new Builder().forBrowser('chrome').build();
}
I hope this will help someone.

Related

How to get Chrome Dev Tools logs with Selenium C#?

My aim is getting the transfer size of page. Explained below image.
How can I get it with C# code using selenium NuGet package? I searched chrome dev tools.
https://chromedevtools.github.io/devtools-protocol/tot/Network/
I see there is Network.dataReceived property. As I understand I need to get this.
My code
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;
ChromeOptions options = new ChromeOptions();
//Following Logging preference helps in enabling the performance logs
options.SetLoggingPreference("performance", LogLevel.All);
//Based on your need you can change the following options
options.AddUserProfilePreference("intl.accept_languages", "en-US");
options.AddUserProfilePreference("disable-popup-blocking", "true");
options.AddArgument("test-type");
options.AddArgument("--disable-gpu");
options.AddArgument("no-sandbox");
options.AddArgument("start-maximized");
options.LeaveBrowserRunning = true;
//Creating Chrome driver instance
IWebDriver driver = new ChromeDriver(options);
var url = " https://...............";
driver.Navigate().GoToUrl(url);
//Extracting the performance logs
var logs = driver.Manage().Logs.GetLog("performance");
for (int i = 0; i < logs.Count; i++)
{
Console.WriteLine((i+1) + " - " + logs[i].Message);
}
I found some code that possibly worked in old versions. I am using Chrome 105 version(as a nuget package, and selenium web dirver 4.0.0) and Chrome should be 105 version. In C# I can not find the below code, this is Java version:
for (LogEntry entry : driver.manage().logs().get(LogType.PERFORMANCE)) {
if(entry.getMessage().contains("Network.dataReceived")) {
Matcher dataLengthMatcher = Pattern.compile("encodedDataLength\":(.*?),").matcher(entry.getMessage());
dataLengthMatcher.find();
}
Even if we can do this with C# code, I dont believe driver.Manage().Logs.GetLog("performance") returns the same with the listed lines in dev tools network section. Is there nay option about that?

Error: The specified executable path does not exist: /tmp/.mount_JobAppuO0ICL/resources/app.asar/dist/main/chromedriver/chromedriver

I am trying to use Selenium and Chrome WebDriver in Electron, which works fine in development. However, once I package the application and run it, I get the following error:
Error: The specified executable path does not exist: /tmp/.mount_JobAppuO0ICL/resources/app.asar/dist/main/chromedriver/chromedriver
Here's the code that starts the driver:
const service = new chrome.ServiceBuilder(path).build();
chrome.setDefaultService(service);
const options = new chrome.Options();
options.options_.debuggerAddress = "localhost:9222";
this.driver = await new Builder()
.withCapabilities({ unexpectedAlertBehaviour: "accept" })
.forBrowser("chrome")
.setChromeOptions(options)
.build();
Where path is from require("chromedriver").path.
I'm not using selenium and chrome driver to test Electron app. I'm using selenium and chrome driver for functionality inside Electron app.
Thank you

How do I get selenium to open my electron app?

I'm attempting to setup Selenium to test my electron app. So far I have the code from the Electron documentation, however, this only opens the HTML file, not my actual app. Here is my code:
import * as path from "path";
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder()
// The "9515" is the port opened by ChromeDriver.
.usingServer('http://localhost:9515')
.withCapabilities({
'chromeOptions': {
// Here is the path to your Electron binary.
binary: '../../node_modules/electron/dist/electron.exe'
}
})
.forBrowser('chrome')
.build();
const current_path = path.join(__dirname, "../../dist/public/index.html");
driver.get('file://' + current_path);
How can I get it to open my app?
I've been trying to figure this out for several days, and all the other articles and stackoverflow posts either point to Spectron (which is now deprecated) or don't explain how to open my own app and not a different website.
EDIT: I figured out that adding "args": ['--app=PATH_TO_PROJECT_DIR')] in the chromeOptions object , and changing the name to "goog:chromeOptions", makes it open to the correct file path, however, now I get the following error:
WebDriverError: unknown error: no chrome binary at ../../node_modules/electron/dist/electron.exe
Changing back to "chromeOptions" stops it from opening the app directory, but does open a blank chrome window.
The solution was to:
Replace '../../node_modules/electron/dist/electron.exe' with path.join(__dirname, '../../node_modules/electron/dist/electron.exe')
To change chromeOptions to goog:chromeOptions
To add "args": [path.join(__dirname, '../../')] to the goog:chromeOptions object.
Working Code:
import * as path from "path";
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder()
// The "9515" is the port opened by ChromeDriver.
.usingServer('http://localhost:9515')
.withCapabilities({
'goog:chromeOptions': {
// Here is the path to your Electron binary.
"binary": path.join(__dirname, '../../node_modules/electron/dist/electron.exe'),
"args": ['--app=' + path.join(__dirname, "../../")]
}
})
.forBrowser('chrome')
.build();

Selenium, WebDriver Manager, and Electron Desktop Apps

I'm building out some ui automation tests for an electron app. I have an existing test framework built in C# using Selenium and Appium for web and mobile devices.
I figured out how to start the chrome driver and target the electron app, but to do so, I had to not use the extremely handy WebDriverManager package.
This is my set up
[SetUp]
public void TestSetUp()
{
ChromeOptions chromeOptions = new()
{
BinaryLocation = #"ElectronApp.exe",
};
_driver = new ChromeDriver(#"local driver path", chromeOptions);
}
This works to open up the electron app using Chrome driver. I did have to match the version of Chrome the electron app used and made sure to download that version of the webdriver.
What I want to know is if there's a good way to use WebDriver Manager to set up my driver, but open the electron app.
This was what I was trying:
[SetUp]
public void TestSetUp()
{
ChromeOptions chromeOptions = new()
{
BinaryLocation = #"ElectronApp.exe",
};
ChromeConfig chromeConfig = new();
new WebDriverManager.DriverManager().SetUpDriver(chromeConfig, "98.0");
_driver = new ChromeDriver(chromeOptions);
The 98 is the version of Chrome that the electron app is apparently using -- that's the same version I had to match the driver for.
This is the stack error:
Message:
System.Net.WebException : The remote server returned an error: (404) Not Found.
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
HttpWebRequest.GetResponse()
WebClient.GetWebResponse(WebRequest request)
WebClient.DownloadBits(WebRequest request, Stream writeStream)
WebClient.DownloadFile(Uri address, String fileName)
BinaryService.DownloadZip(String url, String destination)
BinaryService.SetupBinary(String url, String zipPath, String binaryPath)
DriverManager.SetUpDriverImpl(String url, String binaryPath)
DriverManager.SetUpDriver(IDriverConfig config, String version, Architecture architecture)
DesktopTests.TestSetUp() line 41
--TearDown
DesktopTests.Teardown() line 54
I was so focused on the WebDriver Manager, I missed that the chrome version I was specifying wasn't valid. Instead, I used the full version, and it worked great.
[SetUp]
public void TestSetUp()
{
ChromeOptions chromeOptions = new()
{
BinaryLocation = #"ElectronApp.exe",
};
ChromeConfig chromeConfig = new();
new WebDriverManager.DriverManager().SetUpDriver(chromeConfig, "98.0.4758.102");
_driver = new ChromeDriver(chromeOptions);
}

Unable to install WebExtension with Selenium

I'm trying to test my firefox webextension but firefox refuses to install it because it doesn't have the install.rdf file. But that file is not used anymore by webextensions.
const firefox = require('selenium-webdriver/firefox');
const webdriver = require('selenium-webdriver');
require('geckodriver');
let profile = new firefox.Profile();
profile.addExtension(process.cwd() + '/build/firefox/');
profile.setPreference('extensions.firebug.showChromeErrors', true);
let options = new firefox.Options().setProfile(profile);
let _driver = new webdriver.Builder()
.forBrowser('firefox')
.setFirefoxOptions(options)
.build();
Error: ENOENT: no such file or directory, open '/dev/webext/build/firefox/install.rdf'
Is there a setting that I need to enable to tell it it's a webextension?
The WebExtension API is not yet supported by Selenium v3.4.0 . The method Profile::addExtension only works for a legacy addon where install.rdf is present at the root.
To test a web extension, you can either use a profile where the extension is already installed, or you can implement the custom command available with GeckoDriver since v0.17.0:
var webdriver = require('selenium-webdriver');
var Command = require('selenium-webdriver/lib/command').Command;
function installWebExt(driver, extension) {
let cmd = new Command('moz-install-web-ext')
.setParameter('path', path.resolve(extension))
.setParameter('temporary', true);
driver.getExecutor()
.defineCommand(cmd.getName(), 'POST', '/session/:sessionId/moz/addon/install');
return driver.schedule(cmd, 'installWebExt(' + extension + ')');
}
var driver = new webdriver.Builder()
.forBrowser('firefox')
.build();
installWebExt(driver, "C:\\temp\\extension.zip");
This is an issue with FirefoxDriver. This issue is already logged in both SeleniumHQ/selenium#4184 and
mozilla/geckodriver#759
GeckoDriver says that
A workaround for the time being would be to use the add-on endpoints
geckodriver 0.17.0 provides to get an extension installed from the
local disk.
https://github.com/mozilla/geckodriver/blob/release/src/marionette.rs#L66
So you have to use the geckodriver endpoints to do that. I have already mentioned on how to use the endpoints here