Enable clipboard in automated tests with Protractor and webdriver - selenium

I want to test with Protractor an Angular application that accesses the system clipboard using the clipboard api. The problem is that, when executing the test, the Chromium browser asks the user for permission to access the clipboard. I can't close this box from the test, because this is not a DOM element nor an alert window, and it seems not to be any way to access it from Protractor.
clipboard permissions
I have tried to automatically give permission in Chrome, in protractor setup. First, I looked for a command line switch that do it, but it seems not to exist.
Then I found a way that apparently works, but I don't know if its stable: to set an "exception" in Chrome user profile, using the Capabilities of the chrome driver of webdriver. Basically, I add the following lines of my protractor config file:
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
'prefs': {
'profile.content_settings.exceptions.clipboard': {
'http://localhost:8000,*': {'last_modified': Date.now(), 'setting': 1}
}
}
}
}
I have found the value by looking inside Default/Preferences file inside my Chrome profile.
It now works for me, but I don't want to use undocumented features, since they can change anytime without notice. Do you know a better way of doing this? Thanks.

If anyone is looking to do something similar with C#, I have adapted the code as such:
var options = new ChromeOptions();
var clipboardException = new Dictionary<string, object> {
{"[*.]myurl.com,*",
new Dictionary<string, object> {
{"last_modified", DateTimeOffset.Now.ToUnixTimeMilliseconds()},
{"setting", 1}
}
}
};
options.AddUserProfilePreference("profile.content_settings.exceptions.clipboard", clipboardException);

Related

Selenium commands not working in Chrome web driver (working with firefox)

I'm writing integration/e2e tests and for some reason any selenium driver commands don't see to be working with chromedriver, but they are working flawlessly with firefox driver and the firefox headless driver.
Commands tried: moveByOffset, and doubleClick
Tried both Geb's Interact method
interact {
doubleClick(centerClickable)
}
and accessing the webdriver directly:
def driver = browser.getDriver()
Actions action = new Actions(driver)
WebElement element= driver.findElement(By.className("vis-drag-center"))
def doubleclick = action.doubleClick(element).build()
doubleclick.perform()
Both methods work with the firefox driver. Neither work with chrome driver.
GebConfig.groovy file is set up as thus:
import io.github.bonigarcia.wdm.WebDriverManager
import org.openqa.selenium.Dimension
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxOptions
def chromeWebDriverVersion = '70.0.3538.67'
def driverFirefox = {
WebDriverManager.firefoxdriver().setup()
def driver = new FirefoxDriver()
driver.manage().window().setSize(new Dimension(width, height))
return driver
}
// ChromeDriver reference: https://sites.google.com/a/chromium.org/chromedriver/
// Download and configure ChromeDriver using https://github.com/bonigarcia/webdrivermanager
def driverChrome = {
WebDriverManager.chromedriver().version(chromeWebDriverVersion).setup()
def driver = new ChromeDriver()
driver.manage().window().setSize(new Dimension(width, height))
return driver
}
environments {
firefox {
driver = driverFirefox
}
chrome {
driver = driverChrome
}
//driver = driverFirefox
driver = driverChrome
I also tried version 2.43 of chrome.
Additional information:
Mac Mojave
Selenium v 3.7.0
geb v 2.2
spockcore v 1.1-groovy-2.4
groovy v 2.4.5
webdrivermanager v 3.0.0
If anyone is interested, what the test is doing: Selecting a vis.js element by clicking on it. Sleeping for a second (code not included here), then opening/activating it by double clicking it. Or dragging it.
Apart from the selenium actions everything works fine with chromedriver and geb. It's only now that I need the doubleClick and moveByOffset (not move to an element!) that I'm getting issues getting things to work properly
I found a similar question on here, might be the same issue. Maybe not. But there's no solution provided: Selenium Web Driver DragAndDropToOffset in Chrome not working?
Any help is hugely appreciated.
Thank you for your response kriegaex.
Your tests work for me as well. This leads me to think there's just some lower-level interaction between differences in how selenium's chromedriver and firefox driver have implemented the doubleclick and dragAndDropBy actions + the way our application responds to commands.
For any other people observing similar behaviour, I use a work-around where I add an additional action for chromedriver. Perhaps it's nicer to actually find out which KEYDOWN events etc. you should be using and fire those, or perhaps find out why application isn't responding to these events. But I feel like enough time is spent on this already :)
if (browser.getDriver().toString().contains("chrome")) {
// Work-around for chromedriver's double-click implementation
content.click()
}
interact {
doubleClick(content)
}
And for the dragAndDropBy:
def drag(Navigator content, int xOff, int yOff) {
//Work-around: move additional time for when chrome driver is used.
int timesToMove = browser.getDriver().toString().contains("chrome") ? 2 : 1
interact {
clickAndHold(content)
timesToMove.times {
moveByOffset(xOff, yOff)
}
release()
}
}
I just had a little bit of time and was curious because I never tried to perform a double-click in any of my tests before. So I used this page as a test case and ran the following test with both Firefox and Chrome drivers:
package de.scrum_master.stackoverflow
import geb.spock.GebReportingSpec
import org.openqa.selenium.By
import org.openqa.selenium.interactions.Actions
class DoubleClickTest extends GebReportingSpec {
def "double-click via Geb interaction"() {
given:
go "https://demo.guru99.com/test/simple_context_menu.html"
def doubleClickButton = $("button", text: "Double-Click Me To See Alert")
expect:
withAlert {
interact {
doubleClick(doubleClickButton)
}
} == "You double clicked me.. Thank You.."
}
def "double-click via Selenium action"() {
given:
go "https://demo.guru99.com/test/simple_context_menu.html"
def doubleClickButton = driver.findElement(By.tagName("button"))
def doubleClick = new Actions(driver).doubleClick(doubleClickButton).build()
expect:
withAlert {
doubleClick.perform()
} == "You double clicked me.. Thank You.."
}
}
It works flawlessly, both ways of double-clicking trigger the expected Javascript alert.
I am not even using the latest driver version 2.45 but 2.41 against Chrome 71 64-bit on Windows 10. Besides, I also use bonigarcia's Webdriver Manager. I have no idea what is wrong with your setup. My Selenium version is 3.14.0, a bit newer than yours, Geb 2.2, Spock 1.1-groovy-2.4, Groovy 2.4.7.
Maybe it is a MacOS thing? I cannot verify that. Maybe you just run my test first, then maybe upgrade your Selenium and if that also does not help try to downgrade the Chrome driver in order to find out if the problem could be driver version related.
Update: I upgraded to Chrome driver 2.45, the test still works.
Update 2022-02-16: Updated the test to work with another example page, because the old URL still exists, but the Javascript there no longer works.

Geb test ignoring GebConfig.groovy file launched in IntelliJ

Running in IntelliJ IDEA.
GebConfig.groovy is in /src/test/resources.
I am using the Chrome driver.
When I type
System.setProperty("webdriver.chrome.driver", "my/path")
inside my spec file, and I right click and select run, the test works, meaning it opens Chrome and loads the page.
When I don't do that in the spec file, but just leave it in the GebConfig.groovy file, I get the error message "the page to the driver executable must be set".
There's an air-gap, so I can't copy-paste; I'll type as much as I can here:
GebConfig.groovy:
import org.openqa.selenium.chrome.ChromeDriver
...
environments {
chrome {
System.setProperty("webdriver.chrome.driver", "my/path")
driver = {new ChromeDriver()}
}
}
The spec file is really simple, like the example on GitHub
import LoginPage
import geb.spock.GebReportSpec
class LoginSpec extends GebReportSpec
{
// Works when I put this here, but I should not have to do this!
System.setProperty("webdriver.chrome.driver", "my/path")
def "user can log in" () {
when: "log in as me"
def loginPage = to LoginPage
loginPage.login("me")
then:
....
}
}
To fix your problem if you want to keep the path in the geb config, setting the path outside of the environment section like so should work:
import org.openqa.selenium.chrome.ChromeDriver
System.setProperty("webdriver.chrome.driver", "my/path")
//You can also set the driver up here as a default and running with an environment set will override it
driver = {new ChromeDriver()}
environments {
chrome {
driver = {new ChromeDriver()}
}
}
Personally I would avoid adding the driver path to the geb config and create a run configuration in intelliJ for running locally.
Right click the spec file > Click "Create 'nameOfMySpec'".
Now add your driver path to the VM parameters:
-Dgeb.env=chrome -Dwebdriver.chrome.driver=my/path
It's also worth considering a shell script that could then also be called via Jenkins etc:
mvn test -Dgeb.env=chrome -Dwebdriver.chrome.driver=my/path

Test work properly on Chrome, not on Firefox

I wrote test using TestNG and selenium.
code...
actions.sendKeys(Keys.chord(Keys.CONTROL, "a"));
actions.sendKeys(Keys.BACK_SPACE);
actions.build().perform();
code...
I wanted to delete text in login window using these sendKeys, with DataProvider
#DataProvider(name = "inputs")
public Object[][] getData() {
return new Object[][]{
{"000000000", true},
{"000000000", true}
};
}
Html:
<div><input type="tel" class="valid TextInput-kJdagG iVdKHC" name="recoveryPhone" id="eb69ff0b-3427-6986-7556-b7af40ffb156" aria-describedby="eb69ff0b-3427-6986-7556-b7af40ffb156" value="+48 "></div>
Error message:
Unable to read VR
Path1523545392670 Marionette INFO Enabled via --marionette
1523545393744 Marionette INFO Listening on port 52644
1523545394180 Marionette WARN TLS certificate errors will be ignored for this session
Test work as I expected on Chrome, but on firefox these sendKeys not always mark the text, and clear this text. In project I have to use action class. Why the test runs differently?
Check this post https://github.com/mozilla/geckodriver/issues/665 against your versions (browser, browser driver, selenium etc which are always sensible to include in any question), it could be a known bug with the geckodriver.
The post includes a work around of creating the chord in a different way, using:
List<CharSequence> keyWithModifiers = new ArrayList<CharSequence>();
keyWithModifiers.add(Keys.CONTROL);
keyWithModifiers.add("a");
String ctrlA = Keys.chord(keyWithModifiers);
textFieldElem.sendKeys(ctrlA);
This approach worked for me using Selenium 3.7.1 Java bindings, gecko driver 0.18.0 (64 bit) and Firefox 57.0.2 - 59.0

How to disable 'This type of file can harm your computer' pop up

I'm using selenium chromedriver for automating web application.
In my application, I need to download xml files. But when I download xml file, I get 'This type of file can harm your computer' pop up. I want to disable this pop up using selenium chromedriver and I want these type of files to be downloaded always. How can this be done?
Selenium version : 2.47.1
Chromedriver version : 2.19
UPDATE it's long standing Chrome bug from 2012.
The problem with XML files started to happen to me as of Chrome 47.0.2526.80 m.
After spending maybe 6 hours trying to turn off every possible security option I tried a different approach.
Ironically, it seems that turning on the Chrome option "Protect you and your device from dangerous sites" removes the message "This type of file can harm your computer. Do you want to keep file.xml anyway?"
I am using 'Ruby' with 'Watir-Webdriver' where the code looks like this:
prefs = {
'safebrowsing' => {
'enabled' => true,
}
}
b = Watir::Browser.new :chrome, :prefs => prefs
Starting the browser like this, with safebrowsing option enabled, downloads the xml files without the message warning. The principle should be the same for Selenium with any programming language.
#####
Edited: 13-04-2017
In latest version of Google Chrome the above solution is not enough. Additionally, it is necessary to start the browser with the following switch:
--safebrowsing-disable-download-protection
Now, the code for starting the browser would look something like this:
b = Watir::Browser.new :chrome, :prefs => prefs, :switches => %w[--safebrowsing-disable-download-protection]))
I am posting below the complete code that got file download working for me:
Hope it helps :-) I am using Java-Selenium
System.setProperty("webdriver.chrome.driver", "C:/chromedriver/chromedriver.exe");
String downloadFilepath = "D:/MyDeskDownload";
HashMap<String, Object> chromePrefs = new HashMap<String, Object>();
chromePrefs.put("profile.default_content_settings.popups", 0);
chromePrefs.put("download.default_directory", downloadFilepath);
chromePrefs.put("safebrowsing.enabled", "true");
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("prefs", chromePrefs);
DesiredCapabilities cap = DesiredCapabilities.chrome();
cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
cap.setCapability(ChromeOptions.CAPABILITY, options);
WebDriver driver = new ChromeDriver(cap);
Following Python code works for me
chromeOptions = webdriver.ChromeOptions()
prefs = {'safebrowsing.enabled': 'false'}
chromeOptions.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(chrome_options=chromeOptions)
The accepted answer stopped working after a recent update of Chrome. Now you need to use the --safebrowsing-disable-extension-blacklist and --safebrowsing-disable-download-protection command-line switches. This is the WebdriverIO config that works for me:
var driver = require('webdriverio');
var client = driver.remote({
desiredCapabilities: {
browserName: 'chrome',
chromeOptions: {
args: [
'disable-extensions',
'safebrowsing-disable-extension-blacklist',
'safebrowsing-disable-download-protection'
],
prefs: {
'safebrowsing.enabled': true
}
}
}
});
Note that I am also disabling extensions, because they generally interfere with automated testing, but this is not strictly needed to fix the problem with downloading XML and JavaScript files.
I found these switches by reading through this list. You can also see them in the Chromium source.
I came across this recently, using Katalon Studio, Chrome version 88.
Thankfully just the enabling safebrowsing did the trick. You access the settings via "Project Settings" and you navigate to "Desired Capabilities" -> "Web UI" -> "Chrome".
If you don't have a "prefs" setting add it and set the type to Dictionary. Then in the Value add a boolean named "safebrowsing.enabled" and set the value to "true".
Result might look like:
(And you can the default directory setting has nothing to do with this example).
I used all of suggested chrome options in C# and only when my internet connected worked for me but when internet disconnected none of them work for me.
(I'm not sure.may be chrome safebrowsing need to internet connection)
By using older version of chrome(version71) and chromedriver(version 2.46) and after downloading,i saw downloaded XML file name constains 'Unconfirmed' with 'crdownload' extension
and parsing XML file wouldn't work properly.
Finally, creating wait with Thread.Sleep(1000) solved my problem.
IWebDriver Driver;
//chromedriver.exe version2.46 path
string path = #"C:\cd71";
ChromeDriverService driverService = ChromeDriverService.CreateDefaultService(path, "chromedriver.exe");
ChromeOptions options = new ChromeOptions();
// options.AddArgument("headless");
options.AddArgument("--window-position=-32000,-32000");
options.AddUserProfilePreference("download.default_directory", #"c:\xmlFiles");
options.AddUserProfilePreference("download.prompt_for_download", false);
options.AddUserProfilePreference("disable-popup-blocking", "true");
options.AddUserProfilePreference("safebrowsing.enabled", "true");
Driver = new ChromeDriver(driverService, options);
try
{
Driver.Navigate().GoToUrl(url);
Thread.Sleep(1000);
//other works like: XML parse
}
catch
{
}
For context, I had a .csv with a list of .swf flash documents and their respective urls. Since the files could only be accessed after a valid login, I couldn't use a simple requests based solution.
Just like .xml, downloading a .swf triggers a similar prompt.
None of the answers worked for me.
So I stripped away all the extra arguments and settings the above answers proposed and just made the chrome instance headless.
options.add_argument("--headless")
prefs = {
"download.default_directory": "C:\LOL\Flash",
"download.prompt_for_download": False,
"download.directory_upgrade": True,
}
options.add_experimental_option("prefs",prefs)
The only workaround that works for me:
Use argument with path to chrome profile
chromeOptions.add_argument(chrome_profile_path)
Search for file download_file_types.pb in chrome profile folder.
In my case ..chromedriver\my_profile\FileTypePolicies\36\download_file_types.pb
Backup this file and then open with any hexeditor (you can use oline).
Search for the filetype you want to download, i.e. xml and change it to anything i.e. xxx
Im using Google Version 80.0.3987.122 (Official Build) (32-bit) and ChromeDriver 80.0.3987.106. Getting the same error even after adding the below while downloading a .xml file.
$ChromeOptions = New-Object OpenQA.Selenium.Chrome.ChromeOptions
$ChromeOptions.AddArguments(#(
"--disable-extensions",
"--ignore-certificate-errors"))
$download = "C:\temp\download"
$ChromeOptions.AddUserProfilePreference("safebrowsing.enabled", "true");
$ChromeOptions.AddUserProfilePreference("download.default_directory", $download);
$ChromeOptions.AddUserProfilePreference("download.prompt_for_download", "false");
$ChromeOptions.AddUserProfilePreference("download.directory_upgrade", "true");
$ChromeDriver = New-Object OpenQA.Selenium.Chrome.ChromeDriver($chromeOptions)

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