Execute JavaScript Using Selenium Webdriver in C#

Execute JavaScript using Selenium WebDriver in C#

The object, method, and property names in the .NET language bindings do not exactly correspond to those in the Java bindings. One of the principles of the project is that each language binding should "feel natural" to those comfortable coding in that language. In C#, the code you'd want for executing JavaScript is as follows

IWebDriver driver; // assume assigned elsewhere
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
string title = (string)js.ExecuteScript("return document.title");

Note that the complete documentation of the WebDriver API for .NET can be found at this link.

Execute Javascript file in C# through WebDriver

There are three problems here:

  1. As @Crowcoder points out, you need ourFunction(), not ourFunction, otherwise you'll get an error along the lines of Uncaught ReferenceError: ourFunction is not defined(…)
  2. Next, ourFunction is added to document not the global scope, so you'd need document.ourFunction(), otherwise you'll get the same error.
  3. Finally, the function doesn't return anything, so executing it will return undefined. If you try to return the 'value' of it, you'll get something like Uncaught SyntaxError: Illegal return statement(…) in the browser, or probably null back in your code.

You can test all of this from your browser console without needing to fire up WebDriver.

If you changed the method to:

document.ourFunction = function(){ tabUrl = window.location.href;
imagesPath = chrome.extension.getURL("images");
var optionsPopupPath = chrome.extension.getURL("options.html");
return optionsPopupPath; // return here!
}

Then js.ExecuteScript("return document.ourFunction()"); ought to work.

Update:

(You could maybe try: js.ExecuteScript("return document.ourFunction();"); (added semicolon) but that shouldn't make a difference.)

I'd suggest (in addition to adding the return statement) temporarily commenting out the chrome.extension lines in case these are throwing errors and causing the function to fail to be created. I think that's far the most likely source of failure.

Having done that, this works fine for me in Firefox and Chrome without any explicit or implicit waits at all.

How can we determine when to use JavaScriptExecutor in selenium c#?

When we use selenium, it has methods written in such a way that it tries to emulate how user will interact with the webpage.

So, lets take the case there is a button on the screen but it never displays on the visible area of the screen. Maybe it is not scrollable (or maybe it is always hidden) and will be never be available to user. Now this is a valid bug.

  • If you use javascript executor, it will click on the buttob and your script won't be able to catch this issue
  • If you use selenium method for click, script will fail giving you some exception

In my case, I have encountered Element not interactable exception in mostly false positive (invalid, non-bug) scenarios

  • if some field on screen was inactive earlier, you performed some action it became active. but due to faster execution, it was still inactive, when script interacted with it
  • Say you have dropdown on screen, you expand the dropdown and click on some field. Now you click some other field when dropdown was closed. While execution dropdown does not close immediately and element you want to access next is obsecured by that dropdown (can happen for popups, or some element that expands on screen, combobox, searchbox)

If you see too many issues due to element not interactable , just catch this exception, take screenshot for your reference, generate a warning in logs for yourself and you can implement direct click using javascript executor in catch block.
Atleast by generating warning for yourself, you can check if you are not missing out on an actual issue.

Hope this helps.

C# Selenium Inject/execute JS on page load

Selenium.WebDriver 4.3.0 and ChromeDriver 103

Try use the ExecuteCdpCommand method

var options = new ChromeOptions();
options.AddArgument("--headless");
options.AddArgument("--user-agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'");

using var driver = new ChromeDriver(options);

Dictionary<string, object> cmdParams= new();
cmdParams.Add("source", "Object.defineProperty(navigator, 'webdriver', { get: () => false });");
driver.ExecuteCdpCommand("Page.addScriptToEvaluateOnNewDocument", cmdParams);

With this piece of code we bypass the first two but if you follow the guide you've already mentioned i think it's easy to bypass the rest.

Sample Image

UPDATE

var initialScript = @"Object.defineProperty(Notification, 'permission', {
get: function () { return ''; }
})
window.chrome = true
Object.defineProperty(navigator, 'webdriver', {
get: () => false})
Object.defineProperty(window, 'chrome', {
get: () => true})
Object.defineProperty(navigator, 'plugins', {
writeable: true,
configurable: true,
enumerable: true,
value: 'works'})
navigator.plugins.length = 1
Object.defineProperty(navigator, 'language', {
get: () => 'el - GR'});
Object.defineProperty(navigator, 'deviceMemory', {
get: () => 8});
Object.defineProperty(navigator, 'hardwareConcurrency', {
get: () => 8});";

cmdParams.Add("source", initialScript);
driver.ExecuteCdpCommand("Page.addScriptToEvaluateOnNewDocument", cmdParams);

Sample Image



Related Topics



Leave a reply



Submit