I have created an automated test that logs a user in to a site and performs certain operations. The test first runs in Firefox, Chrome and then IE. It runs perfectly in Firefox, closes the browser and then performs the test in Chrome and again closes the browser. When the exact same test opens the URL in IE it says it is unable to locate the element 'UserName' for the login process.
I have a wait function which I tried to extend in case it was a problem with the page rendering but this didn't work. When using the dev tools and searching for the element it finds it no problem so I am confused as to how it fails in the test.
Does anyone know what could cause this in IE?
The HTML for the text field looks like this...
The Selenium code that works in FF and Chrome but not IE is:
private Results _Test_Login(IWebDriver driver)
{
Results rt;
driver.Navigate().GoToUrl("MyURL");
driver.FindElement(By.Id("UserName")).Click();
TextboxOperation type = new TextboxOperation("UserName", driver, "Success", EnumSearchType.ById);
OperationExecutor.PerformOperations(type);
rt = new Results(driver.Url, driver.PageSource, "Existing Users");
return rt;
}
[TestMethod]
public void Test_Login()
{
List<IWebDriver> drivers = new List<IWebDriver>() { firefoxDriver, chromeDriver, ieDriver };
foreach (IWebDriver driver in drivers)
{
Results results = _Test_Login(driver);
if (results.Exception != null)
{
throw results.Exception;
}
Assert.IsFalse(results.ErrorState);
}
}
Sometimes you need to put a pause just before trying to locate an element because the page or frame is not yet ready. Or, if you don't want to have a pause, you can use a time-limited while loop wrapping a try-catch that handles error conditions and retries the find if it fails.)
Related
Development Environment OS: Windows 7 Enterprise LTS
Browser compatibility minimum requirements: Should support all Edge, Firefox, Chrome browsers, as of 2018.
Current ongoing issue: Unable to run VM on dev workstation; Cannot run Windows 10 VMs to debug Microsoft Edge extensions.
To explain:
An "all-in-one browser extension" refers to a browser extension code that uses the same code with minor differences to work on various WebExtensions / Chrome Extensions supported browsers. At bare minimum, the same codebase should work and run on Edge, Firefox, and Chrome with very minor changes.
Callbacks on the content scripts for Edge/Firefox/Chrome extensions are handled differently.
For unknown reasons, I cannot run VM on my workstation machine. When VM is running, VM client is black. This is a localized issue on my end that I cannot resolve, so I'm forced to find a different solution/alternative.
How are they handled differently on the content scripts:
Edge: browser.runtime.sendMessage uses callbacks, and returns undefined.
Firefox: browser.runtime.sendMessage uses Promises, and returns a Promise.
Chrome: chrome.runtime.sendMessage uses callbacks, and returns undefined.
According to various references:
Firefox / Chrome / MS Edge extensions using chrome.* or browser.*
https://www.smashingmagazine.com/2017/04/browser-extension-edge-chrome-firefox-opera-brave-vivaldi/
On the content scripts, you can declare the following JavaScript snippet at the top in order to create a global variable that can be referenced everywhere else:
//Global "browser" namespace definition.
window.browser = (function() {
return window.msBrowser || window.browser || window.chrome;
})();
Unfortunately, because of the issue I'm experiencing (VM not running), I cannot tell if window.msBrowser is still being used. And this solution is not helpful for me when handling message callbacks when using namespace.runtime.sendMessage.
With all that said, my main question is: How to write a message passing function that can handle callbacks properly?
Currently, I'm using the following code:
function sendGlobalMessage(messageRequest, callback) {
if (chrome && window.openDatabase) {
//This is Chrome browser
chrome.runtime.sendMessage(messageRequest, callback);
}
else if (browser) {
try {
//Edge will error out because of a quirk in Edge IndexedDB implementation.
//See https://gist.github.com/nolanlawson/a841ee23436410f37168
let db = window.indexedDB.open("edge", (Math.pow(2, 30) + 1));
db.onerror = function(e) {
throw new Error("edge is found");
};
db.onsuccess = function(e) {
//This is Firefox browser.
browser.runtime.sendMessage(messageRequest).then(callback);
};
}
catch (e) {
//This is Edge browser
browser.runtime.sendMessage(messageRequest, callback);
}
}
}
I truly felt this is a hacky solution, because the code is based off of browser platform exclusive quirks in order to separate chrome.runtime.sendMessage and browser.runtime.sendMessage API calls, so as to handle callbacks in their respective platforms. I really wanted to change this.
So I'm asking what better ways are there, out there, that is useful to detect the different platforms, and handle message passing callbacks properly at the same time?
Thanks in advance.
I believed I solved it.
EDIT: The FINAL final version (updated and more stable, less message passing):
//Global "browser" namespace definition, defined as "namespace". Can be renamed to anything else.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
//Using instanceof to check for object type, and use the returned evaluation as a truthy value.
let supportPromises = false;
try {
supportPromises = window.namespace.runtime.getPlatformInfo() instanceof Promise;
}
catch(e) { }
if (supportPromises){
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
else {
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
}
}
(Original Post):
The final version (Now obsoleted):
//Global "browser" namespace definition.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
let returnValue = window.namespace.runtime.sendMessage({});
if (typeof returnValue === "undefined"){
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
else {
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
}
}
In the second if statement, by checking to see if the return value of a window.browser.runtime.sendMessage is a Promise or undefined, we can detect if the platform is Firefox or Edge.
I think this is the only solution to handle message passing callbacks/message responses on the content scripts.
I really couldn't think of a better solution than this. So I'll be using this from now on.
But if anyone else knows a better way, a way where you don't need to send out 1 extra dummy message for Firefox and Edge per function call, that would be great!
It sucks that anything inside the content script is not persistent, and even if you store information about what platform the code is being run on, you still have to fetch the information from the background script before filtering out which runtime.sendMessage function to call on, so it doesn't really save much time.
I am using Selenium 2.46 and Firefox 31. Whenever my test gets to a point that an web-element does not exist (or an exception is thrown) my test freezes, but it does not happen when I use Chrome. Just to let you know I have already used different versions of selenium-java and Firefox. Please find the code below:
List<WebElement> divs = driverChrome.findElements(By.tagName("div"));
int i = 0;
while (true) {
boolean breakIt = true;
System.out
.println("Waiting for map to load completely, thanks for your patience.");
for (WebElement weDiv : divs) {
try {
if (weDiv.getText().equals("Loading")) {
Thread.sleep(2000);
breakIt = false;
break;
}
} catch (Exception e) {
}
}
if (breakIt) {
break;
}
driverChrome.manage().timeouts()
.implicitlyWait(5, TimeUnit.SECONDS);
divs = driverChrome.findElements(By.tagName("div"));
}
I am using this code to wait till a map is completely loaded
The most probable reason for your test to freeze is the while(true) loop. If the text "Loading" does not show up, there still can be an (invisible) element with that text.
Anyway, I would never use a wait mechanism without timeout. And I would always try to use methods provided by the framework.
WebDriver offers explicit and implicit wait mechanisms. This one-liner could replace your whole listing (waits for up to 60s, polling every two seconds):
new WebDriverWait(driver, 60000L, 2000L).until(ExpectedConditions.invisibilityOfElementWithText(By.tagName("div"), "Loading"));
Hope it helps. If not, check out other methods of ExpectedConditions or implement your own ExpectedCondition.
With Firefox 17.0.1 I am using an add-on called KeyConfig 20110522 to set some new hot keys and also set the acceltext of menuitems for my new keys as well as for add-ons that do not bother to do so.
I want the acceltext of the menuitems to be set when Firefox starts, but currently I am just using a hot key to execute the following code against the UI via KeyConfig:
document.getElementById("tabmix-menu")
.setAttribute("acceltext","Alt+Ctrl+Shift+T");
// more of the same...
I need a couple of beginners tips:
How can I execute arbitrary code against the UI in the same way as I execute against an HTML page via the console?
Is there a sneaky way to get a clump of code to execute on browser start-up without delving into XUL development?
Is there a way to trace commands executed against the UI so I can get at command calls instead of using triggers when I set my hot keys like so:
document.getElementById("tabmix-menu").click();
Any other tips on this type of low-level hacking would also be welcome.
You can execute arbitrary code against the Firefox UI from an addon, but as you say, doing all the XUL related stuff is a bit boring :-)
Enter "Bootstrapped" extensions!
Part 1:
A "Bootstrapped" (or re-startless) extension needs only an install.rdf file to identify the addon, and a bootstrap.js file to implement the bootstrap interface.
Bootstrapped Extension: https://developer.mozilla.org/en-US/docs/Extensions/Bootstrapped_extensions
Good example: http://blog.fpmurphy.com/2011/02/firefox-4-restartless-add-ons.html
The bootstrap interface can be implemented very simply:
function install() {}
function uninstall() {}
function shutdown(data, reason) {}
function startup(data, reason) { /* YOUR ARBITRARY CODE HERE! */ }
You compile the extension by putting install.rdf and bootstrap.js into the top-level of a new zip file, and rename the zip file extension to .xpi.
Part 2:
Your code is privileged and can use any of the Mozilla platform APIs. There is however an issue of timing. The moment-in-time at which the "startup" function is executed is one at which no Chrome window objects exist yet!
If it's important for your code that you have a Chrome Window, we need to wait for it to appear:
// useful services.
Cu.import("resource://gre/modules/Services.jsm");
var loader = Cc["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
var wmSvc = Cc["#mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var logSvc = Cc["#mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
// get the first gBrowser
var done_startup = 0;
var windowListener;
function do_startup(win) {
if (done_startup) return;
done_startup = 1;
wmSvc.removeListener(windowListener);
var browserEnum = wmSvc.getEnumerator("navigator:browser");
var browserWin = browserEnum.getNext();
var tabbrowser = browserWin.gBrowser;
/* your code goes here! */
}
// window listener implementation
windowListener = {
onWindowTitleChange: function(aWindow, aTitle) {},
onCloseWindow: function(aWindow) {},
onOpenWindow: function(aWindow) {
var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
win.addEventListener("load", function(aEvent) {
win.removeEventListener("load", arguments.callee, false);
if (aEvent.originalTarget.nodeName != "#document") return;
do_startup();
}
};
// CODE ENTRY POINT (put this in bootstrap "startup" function)
wmSvc.addListener(windowListener);
I recently started a new testing job and my predecessor ran an automation suite using watin, which I've had no previous experience with so I'm sorry if I'm not able to give you the relevant information
When I run the suite it (against IE 8.0.7601.17514) seems to get stuck when ever there is a confirmation dialog and the next step is to press ok
//Enter invalid data
var confirmDialog = new ConfirmDialogHandler();
IE.DialogWatcher.Add(confirmDialog);
using (new UseDialogOnce(IE.DialogWatcher, confirmDialog))
{
//Click to reset data entry
IE.Page<DataEntryPage>().ResetVoucherButton.ClickNoWait();
confirmDialog.WaitUntilExists(40000);
confirmDialog.OKButton.Click();
WaitForPostBackToComplete.WaitForAsyncPostBackToComplete(IE);
}
It just hangs there and waits for the time out period to pass.
I thought the problem was with my IEStaticInstanceHelper.cs file but it seems to be correct
using System.Threading;
using WatiN.Core;
namespace WatiN
{
public class IEStaticInstanceHelper
{
private IE _ie;
private int _ieThread;
private string _ieHwnd;
public IE IE
{
get
{
var currentThreadId = GetCurrentThreadId();
if (currentThreadId != _ieThread)
{
_ie = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
_ieThread = currentThreadId;
}
return _ie;
}
set
{
_ie = value;
_ieHwnd = _ie.hWnd.ToString();
_ieThread = GetCurrentThreadId();
}
}
private int GetCurrentThreadId()
{
return Thread.CurrentThread.GetHashCode();
}
}
}
I've recently rebuilt my computer (well my sysadmin did) and this wasn't an issue before it was rebuilt, but I can't think what may have changed
Any help would be greatly appreciated
Edit
I didn't actually have to change the code, I just had to update my Watin Version as it couldn't handle what ever differences there were between earlier IE 8 dialog boxes and newer ones.
I had a similar problem with IE 9.
I used the following to simulate the shortcut keys on the dialogue
using (browser)
{
SendKeys.SendWait("+(%S)");
}
Send Keys = http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
Does this help?
I try to reload a Web page using (JavaXPCOM):
nsIWebBrowser webBrowser = (nsIWebBrowser) browser
.getWebBrowser();
nsIWebNavigation webNavigation = (nsIWebNavigation) webBrowser.queryInterface(nsIWebNavigation.NS_IWEBNAVIGATION_IID);
try {
nsISHistory sessionHistory = webNavigation.getSessionHistory();
if (sessionHistory != null) {
webNavigation = (nsIWebNavigation) sessionHistory.queryInterface(nsIWebNavigation.NS_IWEBNAVIGATION_IID);
}
} catch (XPCOMException e) {
}
webNavigation.reload(nsIWebNavigation.LOAD_FLAGS_NONE);
But reload doesn't happen at all. I tried force it by using the following flags, but page doesn't refresh as well:
nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY|nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE
Anyone knows what can be the reason for that?
Thanks!
Did you try checking Error Console for syntax errors? You seem to be trying to use C++ type casts in JavaScript. That cannot work. Assuming that browser is a <browser> element, this should work:
browser.reload();
Or:
browser.reloadWithFlags(Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY|Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
See https://developer.mozilla.org/en/XUL/browser for documentation on the <browser> element.
Edit: Given that this is apparently using JavaXPCOM the code seems to be correct with the exception that the entire try .. catch block should be removed. The only flag should be LOAD_FLAGS_BYPASS_CACHE to make sure you don't get a cached response.