How to generate keyboard text for the active process of Firefox - c#

I can send a text from my C# WinForm app to another application like Notepad using:
SendKeys.SendWait("Hello");
but I need to send text to an html input element in Firefox. There are several ways to select a target application. This SO Question uses code like:
Process p = Process.GetProcessesByName("notepad").FirstOrDefault();
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
to set the desired app to the foreground so it will receive the text. But this does not work with the app named "firefox", probably because it uses not 1 but 4 processes according to the Task Manager.
I tried another approach: right before calling SendKeys.SendWait, just switch back to the last active application just like Alt-Tab does, using code from this SO Question, which works for Notepad, and for the Chrome browser, but not for Firefox.
The purpose of this is to get data from a weight measurement device (scale), connected to the RS232 port, to the html input element in the browser. The same principle of simulating a keyboard is routinely used with USB barcode scanners.
Any idea how to do this with Firefox?
Am I perhaps on the wrong track, and are there perhaps much different methods to get text in the keyboard?

Can't you use WinForms WebBrowser? Also consider using Selenium WebDriver which is available via Nuget. I think it does exactly what you need.
That's an example from docs:
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
// Requires reference to WebDriver.Support.dll
using OpenQA.Selenium.Support.UI;
class GoogleSuggest
{
static void Main(string[] args)
{
// Create a new instance of the Firefox driver.
// Note that it is wrapped in a using clause so that the browser is closed
// and the webdriver is disposed (even in the face of exceptions).
// Also note that the remainder of the code relies on the interface,
// not the implementation.
// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
using (IWebDriver driver = new FirefoxDriver())
{
//Notice navigation is slightly different than the Java version
//This is because 'get' is a keyword in C#
driver.Navigate().GoToUrl("http://www.google.com/");
// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name("q"));
// Enter something to search for
query.SendKeys("Cheese");
// Now submit the form. WebDriver will find the form for us from the element
query.Submit();
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.Title.StartsWith("cheese", StringComparison.OrdinalIgnoreCase));
// Should see: "Cheese - Google Search" (for an English locale)
Console.WriteLine("Page title is: " + driver.Title);
}
}
}

Related

How to get Selenium to operate two browser windows using only one driver selenium (using c# and chromedriver)?

I am attempting to control two browser windows via selenium using c# and a single chromedriver. The reason being that I need to share session details accross browser windows.
The code that I have tried and failed with is below;
var options = new ChromeOptions();
options.AddArguments("chrome.switches", "--disable-extensions --disable-extensions-file-access-check --disable-extensions-http-throttling --disable-infobars --enable-automation ");
options.AddUserProfilePreference("credentials_enable_service", false);
options.AddUserProfilePreference("profile.password_manager_enabled", false);
options.PageLoadStrategy = PageLoadStrategy.Default;
ChromeDriverService service = ChromeDriverService.CreateDefaultService();
service.HideCommandPromptWindow = true;
var Driver = new ChromeDriver(service, options);
//THIS WILL OPEN A NEW WINDOW. BUT BECAUSE IT IS A NEW DRIVER DOES NOT WORK FOR SHARING SESSION DETAILS.
//var TestDriver = new ChromeDriver(service, options);
//TestDriver.Manage().Window.Maximize();
//THIS JUST OPENS UP A NEW TAB. NOT A NEW WINDOW (IT WOULD SEEM MOST DOCUMENTATION SUGGESTS THAT IT SHOULD)
IJavaScriptExecutor jscript = Driver as IJavaScriptExecutor;
jscript.ExecuteScript("window.open();", "google.com.au");
//TRY USING THE SEND KEYS TECHNIQUE. NOTHING HAPPENS
var test = Driver.FindElement(By.TagName("html"));
test.SendKeys(Keys.Control + "n");
test.SendKeys(Keys.Control + "t");
//TRY AGAIN USING THE SEND KEYS TECHNIQUE USING A DIFFERENT TAG. NOTHING HAPPENS
var blah = Driver.FindElements(By.TagName("body"));
blah[0].SendKeys(Keys.Control + "t");
//TRY USING ACTIONS. NOTHING HAPPENS
Actions action = new Actions(Driver);
action.SendKeys(OpenQA.Selenium.Keys.Control + "n");
action.Build().Perform();
I may resort to AutoIt to open a browser if I have to, but one more dependency is not what I need. Documentation everywhere around the web seems to suggest than all the options I tried above should work...I suspect it may be a chromedriver issue of some kind.
Any ideas on how to achieve my goal would be greatly appreciated
UPDATE.
Arnons answer below lead me to the solution. If you are in a similar situation the best thing to do is just open up the browser console (from developers tools) and experiment with javascript until you get what you want. Then just execute that. In the end executing the following code has worked for me.
IJavaScriptExecutor jscript = Driver as IJavaScriptExecutor;
jscript.ExecuteScript("window.open('https://www.bing.com.au','_blank','toolbar = 0, location = 0, menubar = 0')");
The other alternative was to use Autoit, which I also got working, much easier than I did figuring out the javascript. But one less dependency is best :)
UPDATE2.
Further complications arise with trying to control the window as an independent browser window. I believe any new window created from a parent window, has the same process id (at least my testing has indicated so), and for all intense and purpose is treated as a tab in the selinium driver. I therefore conclude that certain things are just not possible (for example relocating the child browser window on the screen).
Your first attempt using ExecuteJavaScript was very close, but In order for it to open a new window instead of new tab, you should add the following arguments: `"_blank", "toolbar=0,location=0,menubar=0" to it.
See this question for more details.
I should have read the question better, here is my solution. Ended up using this for selecting windows that popped up after clicking a button but should work with swapping between windows.
//---- Setup Handles ----
//Create a Handle to come back to window 1
string currentHandle = driver.CurrentWindowHandle;
//Creates a target handle for window 2
string popupWindowHandle = wait.Until<string>((d) =>
{
string foundHandle = null;
// Subtract out the list of known handles. In the case of a single
// popup, the newHandles list will only have one value.
List<string> newHandles = driver.WindowHandles.Except(originalHandles).ToList();
if (newHandles.Count > 0)
{
foundHandle = newHandles[0];
}
return foundHandle;
});
//Now you can use these next 2 lines to continuously swap
//Swaps to window 2
driver.SwitchTo().Window(popupWindowHandle);
// Do stuff here in second window
//Swap back to window 1
driver.SwitchTo().Window(currentHandle);
// Do stuff here in first window
You need to explicitly tell Selenium which tab you wish to interact with, which in this case would be;
driver.SwitchTo().Window(driver.WindowHandles.Last());

Headless Browser C# and Alternatives

currently I have the following code using selenium and phantomjs in c#:
public class Driver
{
static void Main()
{
using (var driver = new PhantomJSDriver())
{
driver.Navigate().GoToUrl("https://www.website.com/");
driver.Navigate().GoToUrl("https://www.website.com/productpage/");
driver.ExecuteScript("document.getElementById('pdp_selectedSize').value = '10.0'"); //FindElementById("pdp_selectedSize").SendKeys("10.0");
driver.ExecuteScript("document.getElementById('product_form').submit()");
driver.Navigate().GoToUrl("http://www.website/cart/");
Screenshot sh = driver.GetScreenshot();
sh.SaveAsFile(#"C:\temp\test.jpg", ImageFormat.Png);
}
}
}
My objective is to be able to add a product to my cart and then checkout automatically. The screenshot is just included to test whether the code was successfully working. My first issue is that I often get an error that it cannot find the element with product id "pdp_selectedSize". I'm assuming this is because the the webdriver hasn't loaded the page yet, so I'm looking for a way to keep checking until it finds it without having to set a specific timeout.
I'm also looking for faster alternatives to use instead of a headless browser. I used a headless browser instead of http requests because I need certain cookies to be able to checkout on the page, and these cookies are set through javascript within the page. If anyone has a reccommendation for a faster method, it would be greatly appreciated, thanks!
For your first question, it would behoove you to look into using ExpectedConditions' which is part of theWebDriverWaitclass inSelenium`. The following code sample was taken from here and only serves as a reference point.
using (IWebDriver driver = new FirefoxDriver())
{
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>(d =>
d.FindElement(By.Id("someDynamicElement")));
}
More on WebDriverWaits here.
As to your second question, that is a really subjective thing, in my opinion. Headless Browsers aren't necessarily any faster or slower than a real browser. See this article.

Selenium is telling me the ID doesn't exist

When I run the following program it runs absolutely fine, until I get to filling out the form on the webclip section. Once it gets there it says the id "txtTemplateName" can't be found. I copied and pasted that name directly from Inspecting the element. It isn't that i'm not giving it enough time to load either, I've given it a full 5 seconds in the past just to make sure, and still nothing.
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System.Diagnostics;
using System.Linq;
namespace Build1Evan
{
class Program
{
static void Main(string[] args)
{
IWebDriver driver1 = new FirefoxDriver();
driver1.Navigate().GoToUrl("URL");
Process.Start(#FILE"); // This is just an Auto IT Script to get me by a login window
bool loginCheck1 = driver1.FindElements(By.Id("btnLoginAgain")).Count() > 0;
if (loginCheck1 == true)
{
driver1.FindElement(By.Id("btnLoginAgain")).Click();
}
System.Threading.Thread.Sleep(500);
driver1.FindElement(By.LinkText("Configuration")).Click();
System.Threading.Thread.Sleep(500);
driver1.FindElement(By.LinkText("Payloads")).Click();
System.Threading.Thread.Sleep(500);
driver1.FindElement(By.PartialLinkText("WebClip")).Click();
// BELOW IS WHERE I ENCOUNTER THE ISSUE
System.Threading.Thread.Sleep(500);
driver1.FindElement(By.Id("txtTemplateName")).SendKeys("TESTING");
}
}
}
I also encounter the error when I try selecting any other element in the form, rather it be a button or another text field.
EDIT: PHOTO AS ASKED
EDIT 2: PHOTO 2 Also just a FYI i have had no problems using Selenium IDE, it is easily able to select the element and fill it in.
According to your screenshot, I think your app embed the form by using <object id="panelcontentobject" data="....
In case the form is really inside object tag, you have to create a WebElement of the object tag then use JavaScriptExecutor to retrieve attribute or interact with the form.
For example,
IWebElement objectTag= driver.FindElement(By.Id("panelcontentobject"));
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
js.ExecuteScript("return (arguments[0].contentDocument.getElementById('txtTemplateName')).click()",objectTag);
Please see Examples from http://aksahu.blogspot.com/2015/05/dealing-with-object-tags-in-selenium-webdriver.html?m=1
The form is probably inside iframe, you need to switch to it before you can perform actions on elements inside it:
IWebElement frame = driver.FindElement(By.Id(frameId));
driver.SwitchTo().Frame(frame);
You can also use explicit wait to make sure the element you want is visible and you can interact with it:
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(ExpectedConditions.ElementIsVisible(By.Id("txtTemplateName"))).SendKeys("TESTING");

Selenium-WebDriver opened the new Firefox window, but didn’t navigate to URL

My source code is copied from selenium docs site. I didn’t make any change.
http://docs.seleniumhq.org/docs/03_webdriver.jsp#user-input-filling-in-forms
I installed Selenium library via NuGet, including
Selenium Remote Control(RC), Selenium WebDriver Mono, Selenium WebDriver Support Classes, Selenium WebDriver, and Selenium WebDriver-backed Selenium.
When I run this code, a new Firefox window was opened. But the Firefox doesn’t navigate to the URL, it just stuck, nothing was loaded.
I tried the Firefox v27, v29, v30 and v31, none of them worked.
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
// Requires reference to WebDriver.Support.dll
using OpenQA.Selenium.Support.UI;
class GoogleSuggest
{
static void Main(string[] args)
{
// Create a new instance of the Firefox driver.
// Notice that the remainder of the code relies on the interface,
// not the implementation.
// Further note that other drivers (InternetExplorerDriver,
// ChromeDriver, etc.) will require further configuration
// before this example will work. See the wiki pages for the
// individual drivers at http://code.google.com/p/selenium/wiki
// for further information.
IWebDriver driver = new FirefoxDriver();
//Notice navigation is slightly different than the Java version
//This is because 'get' is a keyword in C#
driver.Navigate().GoToUrl("http://www.google.com/");
// Find the text input element by its name
IWebElement query = driver.FindElement(By.Name("q"));
// Enter something to search for
query.SendKeys("Cheese");
// Now submit the form. WebDriver will find the form for us from the element
query.Submit();
// Google's search is rendered dynamically with JavaScript.
// Wait for the page to load, timeout after 10 seconds
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until((d) => { return d.Title.ToLower().StartsWith("cheese"); });
// Should see: "Cheese - Google Search"
System.Console.WriteLine("Page title is: " + driver.Title);
//Close the browser
driver.Quit();
}
}
I have had the same problem. the solution is simply uninstall your current firefox browser and download older version "i tried 2010 version 3.6.10 works great". your code is fine the problem is Mozilla people have decided to not give the right to any third party application to control Firefox.
good luck

An error occurred executing the click atom

Using C# and Selenium, I am building an automated script where I, amongst other things, try to select a certain value from a droplist (value being specified in a .csv-file). I get the error;
"An error occurred executing the click atom (WARNING: The server did not provide any stacktrace information)"
I have no idea what a click atom is, much less how to fix it... Any help is appreciated greatly!
thanks in advance
this is the code for the droplist:
public bool isellHOSelectAdultsDroplist(string adults)
{
writeToLog(String.Format("Selecting adults from drop list"), this.GetType().Name);
String xpathString = HO_ADULT_SELECTION;
if(GpoExplicitWaitXpathElement(xpathString, 3, 5))
{
IWebElement dropListObjects = webDriver.FindElement(By.XPath(xpathString));
writeToLog(String.Format("DEBUG: Trying to click on appropriate number of adults..."), this.GetType().Name);
selectValueFromAdultDropList(dropListObjects, adults);
return true;
}
else
{
return false;
}
}
//...and this is my select-method
private void selectValueFromAdultDropList(IWebElement dropListObjects, string adults)
{
SelectElement manipulateDroplistObject = new SelectElement(dropListObjects);
manipulateDroplistObject.SelectByValue(adults);
String selection = manipulateDroplistObject.SelectedOption.Text;
int numberOfElements = manipulateDroplistObject.Options.Count;
writeToLog("Number of elements in Adult Droplist: " + numberOfElements, this.GetType().Name);
writeToLog("Selection from adult droplist: " + selection, this.GetType().Name);
}
I'll answer the specific question you asked, which is, "What is a click atom?" There is quite a bit of functionality in the IE driver, and the implementation of this functionality rests on three pillars.
First is IE's COM interfaces. These are the objects and methods that have been used to automate various parts of IE for more than a decade.
The second technology is so-called "native events." That is, using OS-level mechanisms to perform user interactions, like key presses and mouse clicks. On Windows, that means using the Windows SendMessage API. Almost anytime you're using the keyboard or the mouse with the IE driver, you're using native events by default.
Finally, a good portion of the IE driver functionality is implemented using JavaScript functions, which are shared by all of the browsers. These functions are known as "automation atoms".
One of the very few exceptions to using native events for mouse operations is in selecting an <option> element from a <select> element. Since IE doesn't give discoverable dimensions to <option> elements, the IE driver is forced to simulate the click action via JavaScript. This means using the automation atom for the click action. In your case, something must've gone wrong executing that JavaScript, which was faithfully reported as a "failure to execute the click atom." Without more detail, including sample HTML pages to reproduce the issue, it will be exceedingly difficult to diagnose the root cause of the issue.
It's at this point I will echo the call to update to the latest IE driver. Some of the code in this area has been overhauled, and at the least, it should be possible to extract more precise errors from failure cases with a more recent driver.

Categories

Resources