How to test Electron app using selenium and java - selenium

Hi Im having an issue with testing an electron app. Up until last week our product was ran on chrome. But now the product has been changed to an electron desktop app and when launched the window isnt picked up.
The flow is basically I open the product on chrome and it appears as a pop up. Previously this was just a chrome pop up but now its an electron app. And now i cnat seem to switch to this window. Im wondering is it possible to switch between the two or do i need a different driver and just test he electron app by itself?
My driver factory is shown here
public class DriverFactory {
private static WebDriver driver;
public static WebDriver startDriver() {
String projectLocation = System.getProperty("user.dir");
// add in elements for logging into the mobile application also - Android and
// iOS.
if (OSValidator.isMac()) {
System.setProperty("webdriver.chrome.driver", projectLocation + "/chromedriver_mac");
} else if (OSValidator.isWindows()) {
System.setProperty("webdriver.chrome.driver", projectLocation + "/chromedriver.exe");
} else {
System.setProperty("webdriver.chrome.driver", projectLocation + "/chromedriver_linux");
}
if (System.getProperty("app.env") != null) { // If coming from Jenkins/Maven goal..
// This is for logging results. Added when investigating crashes on chrome driver. Can be disabled when not needed. 26/03/2020
System.setProperty("webdriver.chrome.verboseLogging", "true");
}
unknown-error-devtoolsactiveport-file-doesnt-exist-while-t
ChromeOptions options = new ChromeOptions();
options.addArguments("start-maximized");
options.addArguments("disable-infobars");
options.addArguments("--disable-extensions");
options.addArguments("--window-size=1920x1080");
options.addArguments("--disable-cache");
//options.addArguments("--headless");
options.addArguments("--disable-application-cache");
options.addArguments("--disk-cache-size=0");
options.addArguments("--disable-gpu"); // applicable to windows os only
options.addArguments("--disable-dev-shm-usage"); // overcome limited resource problems
options.addArguments("--dns-prefetch-disable");
//options.addArguments("--no-sandbox"); // Bypass OS security model
options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
driver = new ChromeDriver(options);
//--------------------
return driver;
}
}

It is described here.
https://applitools.com/blog/automating-electron-applications-using-selenium/
You just need to set appropriate options and use same code for the chrome and electron.
#Before
public void setup() {
ChromeOptions opt = new ChromeOptions();
opt.setBinary("/Users/yanir/Downloads/Electron API Demos.app/Contents/MacOS/Electron API Demos");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("chromeOptions", opt);
capabilities.setBrowserName("chrome");
driver = new ChromeDriver(capabilities);
if (driver.findElements(By.id("button-about")).size() > 0)
driver.findElement(By.id("button-about")).click();
}

Related

Accept microphone and camera permissions on Edge using selenium

I am running selenium scripts on Edge browser. one of the functionality requires to initiate a audio or video call between two windows. In chrome, we can use 'use-fake-ui-for-media-stream' in chrome options. Is there anything similar for Edge. If there isn't, is there a way to accept these alerts at runtime. I have tried -
driver.switchTo().alert().accept(),
but this also doesn't work, and throws error saying no such alert present
Edited
I am using Edge chromium and java selenium and have set properties as below in code. Still permission pop up shows when script runs
Map<String, Object> prefs = new HashMap<String, Object>();
prefs.put("profile.default_content_settings.popups", 0);
prefs.put("download.default_directory", fileDownloadLocation);
EdgeOptions options= new EdgeOptions();
options.setCapability("prefs", prefs);
options.setCapability("allow-file-access-from-files", true);
options.setCapability("use-fake-device-for-media-stream", true);
options.setCapability("use-fake-ui-for-media-stream", true);
DesiredCapabilities capabilities = DesiredCapabilities.edge;
capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS,true);
capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS,true);
System.setProperty("webdriver.edge.driver", getDriverPath("EDGE"));
driver = new EdgeDriver(options);
driver.manage().window().maximize();
I suggest you make a test with the sample code below. I tried to test with the Edge Chromium browser and it looks like it is not asking the permission popup.
JAVA code:
public static void main(String[] args)
{
System.setProperty("webdriver.edge.driver","\\msedgedriver.exe");
EdgeOptions op=new EdgeOptions();
op.addArguments("use-fake-device-for-media-stream");
op.addArguments("use-fake-ui-for-media-stream");
WebDriver browser = new EdgeDriver(op);
browser.get("https://your_URL_here...");
}
In Selenium 3.141 Version we dont have addArguments() method but in Selenium 4.0.0 alpha version we have addArguments() method
EdgeOptions edgeOpts = new EdgeOptions();
edgeOpts.addArguments("allow-file-access-from-files");
edgeOpts.addArguments("use-fake-device-for-media-stream");
edgeOpts.addArguments("use-fake-ui-for-media-stream");
edgeOpts.addArguments("--disable-features=EnableEphemeralFlashPermission");
driver = new EdgeDriver(edgeOpts);

Keep file with Chromedriver in chrome://downloads

I'm trying to automate the download of an XML file with Google Chrome.
I'm using:
Google Chrome v73.0.3683.75 (64 bits)
Chromedriver v73
Selenium WebDriver v3.14.0
C#
The problem comes up when a message of harmful file appears:
As I'm using Chromedriver, I can not interact with this message, so I tried to accept the download from the chrome://downloads page.
Once I open the chrome://downloads page, I click on the Keep button, but an Alert comes up again to confirm the download.
This popup is not a popup Selenium and Chromedriver can Handle with the Dismiss()/Accept()/SendKeys()/... methods. When I try to SwitchTo() it, Chromedriver crashes.
I tried to directly send the keystrokes of {TAB} and {SPACE}/{RIGHT} and {ENTER}, but Chrome seems not to catch them...
The full code is:
String currentWindow = this.Drivers[Navegador].CurrentWindowHandle;
String popupHandle = "";
((IJavaScriptExecutor)this.Drivers[Navegador]).ExecuteScript("window.open('about:blank','_blank')");
ReadOnlyCollection<String> tabs = this.Drivers[Navegador].WindowHandles;
foreach (string handle in tabs){
if (handle != currentWindow){
popupHandle = handle;
break;
}
}
this.Drivers[Navegador].SwitchTo().Window(popupHandle);
this.Drivers[Navegador].Navigate().GoToUrl("chrome://downloads");
String script = "return document.querySelector('body > downloads-manager').shadowRoot.querySelector('#downloadsList > downloads-item').shadowRoot.querySelector('#dangerous > paper-button:nth-child(2)');";
//String script = "return document.querySelector('body > downloads-manager').shadowRoot.querySelector('#downloadsList > downloads-item:nth-child(2)').shadowRoot.querySelector('#url').textContent;";
IWebElement boton = (IWebElement) ((IJavaScriptExecutor) this.Drivers[Navegador]).ExecuteScript(script);
boton.Click();
Thread.Sleep(2000);
SendKeys.Send("{TAB}{SPACE}");
Thread.Sleep(1000);
this.Drivers[Navegador].Close();
this.Drivers[Navegador].SwitchTo().Window(currentWindow);
this.Drivers[Navegador].SwitchTo().DefaultContent();
result = true;
IMPORTANT NOTE:
I tried to launch Chrome with all the flags/options/experimental_options/user_preferences/... possible and it doesn't work. These options/arguments seem to be deprecated in the latest versions of Chrome or Chromedriver.
As discussed with OP, answering the question in Java.
Encountered the same problem few months back, so this is how it worked for me, might work for you as well.
Map<String, Object> chromePreferences = new Hashtable<String, Object>();
// Below preferences will disable popup dialog while downloading the file
chromePreferences.put("profile.default_content_settings.popups", 0);
chromePreferences.put("download.prompt_for_download", "false");
// Set the customised path for downloading the file, if required
chromePreferences.put("download.default_directory", "path");
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.setExperimentalOption("prefs", chromePreferences);
DesiredCapabilities cap = DesiredCapabilities.chrome();
cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
cap.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
//Now initiate ChromeDriver with the capabilities set above and continue with your automation
ChromeDriver chromeDriver = new ChromeDriver(cap);
I recently ran into this issue, and due to the deprecation of some of the methods in the ChromeDriver, the above solution didn't work.
After a lot of research I decided to switch to IE and explore an alternate option with the inspiration from this article - https://sqa.stackexchange.com/questions/3169/downloading-a-file-in-internet-explorer-through-selenium/3520 I came up with this solution in JAVA.
It is not as 'clean' but it worked for me.
public static void main(String[] args) throws NoAlertPresentException,InterruptedException {
System.setProperty("webdriver.ie.driver","C:\\selenium-java-3.141.59\\IEDriverServer.exe");
String url ="myfileurl";
WebDriver driver = new InternetExplorerDriver();
driver.get(url);
try {
Robot robot = new Robot();
Thread.sleep(2000);
//press alt+s key to save
robot.keyPress(KeyEvent.VK_ALT);
robot.keyPress(KeyEvent.VK_S);
robot.keyRelease(KeyEvent.VK_S);
robot.keyRelease(KeyEvent.VK_ALT);
Thread.sleep(2000);
}
catch (AWTException e) {
e.printStackTrace();
}
driver.close();
}

Switching between two apps in appium iOS

I have a testcase where in an iPhone I have to
1. Perform a task in app A.
2. Switch to Safari browser and perform a task
3. Switch back again to App A and continue other tasks
Currently I can perform 1 & 2 & then switch back to App A but I cannot perform any tasks in App A after switching from the safari browser. What I did is as follows.
First of all to launch the app A I used the following code
public void createAppiumDriver() throws MalformedURLException, InterruptedException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", "iPhone 7 Plus");
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "11.2");
capabilities.setCapability("autoWebView", true);
capabilities.setCapability("app", getProperties().getProperty("appURL"));
capabilities.setCapability("autoAcceptAlerts", true);
capabilities.setCapability("useNewWDA", true);
capabilities.setCapability("startIWDP",true);
iosDriver = new IOSDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities);}
To switch from my app to Safari I started a new session using the following code to switch to safari
public void openSafari() throws MalformedURLException {
DesiredCapabilities capabilities2 = new DesiredCapabilities();
capabilities2.setCapability("deviceName", "iPhone 7 Plus");
capabilities2.setCapability("platformName", "iOS");
capabilities2.setCapability("platformVersion", "11.2");
capabilities2.setCapability("browserName", "Safari");
capabilities2.setCapability("autoAcceptAlerts", true);
capabilities2.setCapability("useNewWDA", true);
iosDriver2 = new IOSDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities2);
iosDriver2.get("https://www.gmail.com");}
The issue now I have is to switch back to App A again from the safari browser to perform some tasks for that at the moment I have created a new session again as follows
public void switchToNutrifix() throws MalformedURLException, InterruptedException {
DesiredCapabilities capabilities3 = new DesiredCapabilities();
capabilities3.setCapability("deviceName", "iPhone 7 Plus");
capabilities3.setCapability("platformName", "iOS");
capabilities3.setCapability("platformVersion", "11.2"); //Replace this with your iOS version
capabilities3.setCapability("autoWebView", true);
capabilities3.setCapability("app", getProperties().getProperty("appURL"));
capabilities3.setCapability("autoAcceptAlerts", true);
capabilities3.setCapability("useNewWDA", true);
capabilities3.setCapability("startIWDP",true);
iosDriver3 = new IOSDriver(new URL("http://0.0.0.0:4723/wd/hub"), capabilities3);}
The issue now is that the app A opens again from Safari but it cannot identify the elements in the app. I even changed the context correctly to webview but still it cannot perform any tasks in App A after switching from Safari browser. Can someone please tell me what I'm doing wrong here or another alternative way to do this switch.
The error I usually get is
May 09, 2018 6:43:42 PM org.openqa.selenium.support.ui.ExpectedConditions findElement
WARNING: WebDriverException thrown by findElement(By.xpath: //div[#class='login-content purpose']/h2)
org.openqa.selenium.remote.SessionNotFoundException: A session is either terminated or not started (WARNING: The server did not provide any stacktrace information)
and the appium logs display
debug] [iOS] No key id found. Choosing first id from page array
[debug] [iOS] Page change not referring to currently selected app, ignoring.
public class SwitchBtnAppsiOS {
public AppiumDriver<RemoteWebElement>iosDriver;
public DesiredCapabilities createAppiumDriver()
throws MalformedURLException, InterruptedException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", "iPhone 7 Plus");
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "11.2");
capabilities.setCapability("autoWebView", true);
capabilities.setCapability("app", getProperties().getProperty("appURL"));
capabilities.setCapability("autoAcceptAlerts", true);
capabilities.setCapability("useNewWDA", true);
capabilities.setCapability("startIWDP",true);
return capabilities;
}
public DesiredCapabilities openSafari()
throws MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", "iPhone 7 Plus");
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "11.2");
capabilities.setCapability("browserName", "Safari");
capabilities.setCapability("autoAcceptAlerts", true);
capabilities.setCapability("useNewWDA", true);
return capabilities;
}
public void switchBetweenApps() throws MalformedURLException, InterruptedException
{
DesiredCapabilities nativeAppCaps = createAppiumDriver();
iosDriver = new IOSDriver<>(new URL("http://0.0.0.0:4723/wd/hub"), nativeAppCaps);
/**
* Perform the actions on native app
*/
DesiredCapabilities webCaps = createAppiumDriver();
iosDriver = new IOSDriver<>(new URL("http://0.0.0.0:4723/wd/hub"), webCaps);
iosDriver.get("https://www.gmail.com");
/**
* Perform the actions on safari browser
*/
// Again switch to native app
iosDriver = new IOSDriver<>(new URL("http://0.0.0.0:4723/wd/hub"), nativeAppCaps);
}
}
Where ever you are using the driver instances pass the latest instance of driver.
Use RemoteWebElement instead of MobileElement if that is the case.
Since with XCode 9 Appium support multiple sessions, I suggest using 2 simultaneous sessions: app and safari:
Create driver for native app (e.g. driver1 object)
Do want you need in app, keep driver instance alive
Hint: you may put it in background:
driver.runAppInBackground(Duration.ofMinutes(1));
Create driver for safari (e.g. driver2 object)
Do want you need in safair and close driver2 if you don't need it
Continue using driver1 for native app
There is a better way of switching b/w iOS apps instead of creating driver session again and again as suggested in above answer
IOSDriver driver = new IOSDriver<>(new URL("http://localhost:4723/wd/hub"), capabilities);
try {
HashMap<String, Object> args = new HashMap<>();
args.put("bundleId", SWITCH_APP_BUNDLE_ID);
driver.executeScript("mobile: launchApp", args);
/*
TODO code for switch app
*/
// Now reactivate AUT App
args.put("bundleId", AUT_APP_BUNDLE_ID);
driver.executeScript("mobile: activateApp", args);
/*
TODO code for AUT App
*/
}
finally {
// quit driver
}

Selenium Disable “Disable Developer Mode Extensions” Popup While adding extension

I want to disable the "Disable Developer Mode Extensions" popup while keeping an extension as mentioned in this post keep "Disable developer mode" closed while adding extension
There was no answer and I'm trying to do the same thing. Is there a chrome option like this available for Selenium?
import pywinauto
window_title = "Disable Developer Mode Extensions"
app = pywinauto.Application().connect(name_re=window_title)
win_ext = app.window(name=window_title)
win_ext.close()
Here is the Answer to your Question:
While working with Selenium 3.4.0, chromedriver v2.30, Google Chrome 59.0 through Java bindings, you can use the ChromeOption class to disable the "Disable Developer Mode Extensions" popup as follows:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class Q44959944_dev_extn {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("start-maximized");
options.addArguments("disable-infobars");
options.addArguments("--disable-extensions");
WebDriver driver = new ChromeDriver(options);
driver.navigate().to("https://google.com");
}
}
Let me know if this Answers your Question.
The solution provided by DebanjanB doesn't work with the latest version of Chrome and Chrome Driver.
To get this to work you need to specify the exclude switches and useAutomationExtension in the prefs flag.
System.setProperty("webdriver.chrome.driver", Constant.BROWSER_CHROME_PATH);
Map prefs = new HashMap<String, Object>();
prefs.put("profile.default_content_setting_values.geolocation", 1); // 1:allow 2:block
prefs.put("useAutomationExtension", false);
prefs.put("excludeSwitches", Collections.singletonList("enable-automation"));
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("-incognito");
chromeOptions.addArguments("--disable-gpu"); // applicable to windows os only
chromeOptions.setExperimentalOption("prefs", prefs);
chromeOptions.addArguments("--no-sandbox");
wDriver = new ChromeDriver(chromeOptions);
((LocationContext)wDriver).setLocation(new Location(37.774929, -122.419416, 0));
wDrivers.put("chrome", wDriver);
log.info("New Chrome Browser Instance Created.");

How do I enable geolocation support in chromedriver?

I need to test a JS geolocation functionality with Selenium and I am using chromedriver to run the test on the latest Chrome.
The problem is now that Chrome prompts me to enable Geolocation during the test and that I don't know how to click that little bar on runtime, so I am desperately looking for a way to start the chromedriver and chrome with some option or trigger to enable this by default. All I could find here was however how I can disable geolocation altogether.
How can I solve this issue?
In the known issues section of the chromedriver wiki they said that you Cannot specify a custom profile
This is why it seems to me that #Sotomajor answer about using profile with Chrome as you would do with firefox will not work.
In one of my integration tests I faced the same issue. But because I was not bothering about the real geolocation values, all I had to do is to mock window.navigator.gelocation
In you java test code put this workaround to avoid Chrome geoloc permission info bar.
chromeDriver.executeScript("window.navigator.geolocation.getCurrentPosition = function(success) {
var position = {
"coords": {
"latitude": "555",
"longitude": "999"
}
};
success(position);
}");
latitude (555) and longitude (999) values here are just test value
Approach which worked for me in Firefox was to visit that site manually first, give those permissions and afterwards copy firefox profile somewhere outside and create selenium firefox instance with that profile.
So:
cp -r ~/Library/Application\ Support/Firefox/Profiles/tp3khne7.default /tmp/ff.profile
Creating FF instance:
FirefoxProfile firefoxProfile = new FirefoxProfile(new File("/tmp/ff.profile"));
FirefoxDriver driver = new FirefoxDriver(firefoxProfile);
I'm pretty sure that something similar should be applicable to Chrome. Although api of profile loading is a bit different. You can check it here: http://code.google.com/p/selenium/wiki/ChromeDriver
Here is how I did it with capybara for cucumber tests
Capybara.register_driver :selenium2 do |app|
profile = Selenium::WebDriver::Chrome::Profile.new
profile['geolocation.default_content_setting'] = 1
config = { :browser => :chrome, :profile => profile }
Capybara::Selenium::Driver.new(app, config)
end
And there is link to other usefull profile settings: pref_names.cc
Take a look at "Tweaking profile preferences" in RubyBindings
As for your initial question:
You should start Firefox manually once - and select the profile you use for Selenium.
Type about:permissions in the address line; find the name of your host - and select share location : "allow".
That's all. Now your Selenium test cases will not see that dreaded browser dialog which is not in the DOM.
I took your method but it can not working. I did not find "BaseUrls.Root.AbsoluteUri" in Chrome's Preferences config. And use a script for test
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("proxy-server=http://127.0.0.1:1087")
prefs = {
'profile.default_content_setting_values':
{
'notifications': 1,
'geolocation': 1
},
'devtools.preferences': {
'emulation.geolocationOverride': "\"11.111698#-122.222954:\"",
},
'profile.content_settings.exceptions.geolocation':{
'BaseUrls.Root.AbsoluteUri': {
'last_modified': '13160237885099795',
'setting': '1'
}
},
'profile.geolocation.default_content_setting': 1
}
chromeOptions.add_experimental_option('prefs', prefs)
chromedriver_path = os.path.join(BASE_PATH, 'utils/driver/chromedriver')
log_path = os.path.join(BASE_PATH, 'utils/driver/test.log')
self.driver = webdriver.Chrome(executable_path=chromedriver_path, chrome_options=chromeOptions, service_log_path=log_path)
We just found a different approach that allows us to enable geolocation on chrome (currently 65.0.3325.181 (Build officiel) (64 bits)) without mocking the native javascript function.
The idea is to authorize the current site (represented by BaseUrls.Root.AbsoluteUri) to access to geolocation information.
public static void UseChromeDriver(string lang = null)
{
var options = new ChromeOptions();
options.AddArguments(
"--disable-plugins",
"--no-experiments",
"--disk-cache-dir=null");
var geolocationPref = new JObject(
new JProperty(
BaseUrls.Root.AbsoluteUri,
new JObject(
new JProperty("last_modified", "13160237885099795"),
new JProperty("setting", "1")
)
)
);
options.AddUserProfilePreference(
"content_settings.exceptions.geolocation",
geolocationPref);
WebDriver = UseDriver<ChromeDriver>(options);
}
private static TWebDriver UseDriver<TWebDriver>(DriverOptions aDriverOptions)
where TWebDriver : RemoteWebDriver
{
Guard.RequiresNotNull(aDriverOptions, nameof(UITestsContext), nameof(aDriverOptions));
var webDriver = (TWebDriver)Activator.CreateInstance(typeof(TWebDriver), aDriverOptions);
Guard.EnsuresNotNull(webDriver, nameof(UITestsContext), nameof(WebDriver));
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
webDriver.NavigateToHome();
return webDriver;
}
ChromeOptions options = new ChromeOptions();
HashMap<String, Integer> contentSettings = new HashMap<String, Integer>();
HashMap<String, Object> profile = new HashMap<String, Object>();
HashMap<String, Object> prefs = new HashMap<String, Object>();
contentSettings.put("geolocation", 1);
contentSettings.put("notifications", 2);
profile.put("managed_default_content_settings", contentSettings);
prefs.put("profile", profile);
options.setExperimentalOption("prefs", prefs);
The simplest to set geoLocation is to just naviaget on that url and click on allow location by selenium. Here is the code for refrence
driver.navigate().to("chrome://settings/content");
driver.switchTo().frame("settings");
WebElement location= driver.findElement(By.xpath("//*[#name='location' and #value='allow']"));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
((JavascriptExecutor) driver).executeScript("arguments[0].click();", location);
WebElement done= driver.findElement(By.xpath(""));
driver.findElement(By.xpath("//*[#id='content-settings-overlay-confirm']")).click();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
driver.navigate().to("url");
Cypress:
I encountered with same problem but mocking was not worked for me.
My case:
Application use geo location for the login purpose. So with mock it not worked for me.
Solution:
I used below package and followed the steps and its works for me.
https://www.npmjs.com/package/cypress-visit-with-custom-geolocation
Working sample example:
https://github.com/gaikwadamolraj/cypress-visit-with-custom-geolocation