I have a web application that, under some conditions, pop up JavaScript alert()s that I need to react to in a WatiN test. Google pointed me at Handling alerts in WATIN from way back in 2007 that seemed promising, and I adapted the example code in that post into the following (anonymized):
private void MyAssert(IE browser, WatinHelper helper)
{
AlertDialogHandler alertDialogHandler = new AlertDialogHandler();
using (new UseDialogOnce(browser.DialogWatcher, alertDialogHandler))
{
// DoWrong() causes a JavaScript alert(); false means use nowait.
DoWrong(helper, false);
alertDialogHandler.WaitUntilExists(10 /*seconds*/);
if (!alertDialogHandler.Exists())
{
Assert.Fail("No JavaScript alert when it should have been there");
}
alertDialogHandler.OKButton.Click();
}
SecondAssert(browser);
}
However, while the alert is displayed virtually instantaneously (as it is supposed to) when DoWrong() is called, the call to alertDialogHandler.WaitUntilExists() eventually fails with a WatiNException: Dialog not available within 10 seconds... The only problem was that I could see that the dialog most definitely was up on the screen.
I'm probably missing something simple; can someone point me in the right direction please?
I have also tried the following two variants, and some variations of them, with no luck; I keep getting the same error.
AlertDialogHandler alertDialogHandler = new AlertDialogHandler();
DoWrong(helper, false);
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
do
{
}
while (!alertDialogHandler.Exists() && stopwatch.Elapsed.TotalMilliseconds < 3000);
Assert.IsTrue(alertDialogHandler.Exists(), "No JavaScript alert when it should have been there");
alertDialogHandler.OKButton.Click();
SecondAssert(browser);
and
AlertDialogHandler alertDialogHandler = new AlertDialogHandler();
browser.DialogWatcher.Add(alertDialogHandler);
DoWrong(helper, false);
alertDialogHandler.WaitUntilExists();
alertDialogHandler.OKButton.Click();
browser.WaitForComplete();
Assert.IsFalse(alertDialogHandler.Exists());
SecondAssert(browser);
Yes, I know that code is getting a bit ugly, but right now I'm mostly trying to get it to work at all. If it sits for a few seconds cooking the CPU at 100% utilization because of the tight loop in my second attempt, but only does what I need it to (plain and simple, dismiss that alert()), it's OK.
This is an issue with WatiN and IE8 and the way IE8 changed the way it creates popups. The issue is fixed in the current code available at the Sourceforge SVN repository for the project. Get it, compile it and your problem is solved.
A new release of WatiN will be available before the end of this year.
HTH,
Jeroen
Related
After login, I am switching to this frame where I am getting the following error:
"Cannot evaluate expression because a native frame is on the top of the call stack."
Here is the line of code:
Driver.SwitchTo().Frame("tabMain__ctl0_ult.org.com-Default");
The script has been executed several times and was working perfectly fine. But today all of a sudden I am getting this error. I looked into earlier posts but nothing helped. Please suggest any solutions.
Use this helper function to switch to your tab of choice. The index is determined by the order they have been created. So your your default tabIndex is 0, if you open a new tab/window it will have tabIndex 1 and so forth..
internal void SwitchToTab(int tabIndex) {
WebDriver.Instance.Wait(2);
var newTab = WebDriver.Instance.Driver().WindowHandles[tabIndex];
Instance.Driver().SwitchTo().Window(newTab);
WebDriver.Instance.Wait(2);
}
The waits are just for letting the new tab load. These waits are not good practice, so you should look for other methods for waiting for whatever element/state you are waiting for.
This is the same answer I already posted in this thread: C# Selenium - Can't Get Elements in New Tab
I have a problem that my phantomjs loads one site too slow, always at least 60 seconds though on other sites like google.com it takes less than 1 second.
PhantomJSDriverService service = PhantomJSDriverService.CreateDefaultService();
service.IgnoreSslErrors = true;
service.LoadImages = false;
service.ProxyType = "none";
service.HideCommandPromptWindow = true;
using (IWebDriver driver = new PhantomJSDriver(service ))
{
driver.Navigate().GoToUrl("http://abc.xyz"); //blocks too long
...
}
Is there any way to force it finish loading after reaching some point so the script will continue?
I see what you are asking now. You have a long loading page that you want to stop after the relevant stuff loads. I run into this same issue with some of the sites that we have at work but I have not tried a programmatic solution. Sorry, I don't know phantomjs but I found some links that I think would be helpful.
The way I would approach it is to wait for the DOMContentLoaded event to fire and then send an ESC to the page. At least that's what I do manually to stop the long loading files that I don't care about so that the execution can continue.
I found this question How can I wait for the page to be ready in PhantomJS? Here's the relevant part:
var page = require('webpage').create();
var system = require('system');
page.onInitialized = function() {
page.onCallback = function(data) {
console.log('Main page is loaded and ready');
//Do whatever here
};
page.evaluate(function() {
document.addEventListener('DOMContentLoaded', function() {
window.callPhantom();
}, false);
console.log("Added listener to wait for page ready");
});
};
page.open('https://www.google.com', function(status) {});
Once you detect DOMContentLoaded, use sendkeys() to send the ESC key. I honestly don't know if this will work but it's where I would start. Hopefully it will get you started.
I've just found out the reasons why the phantomjs load so slow because the target web has too many extensions, ads... so I switch to chrome and use adblock like Running Selenium WebDriver using Python with extensions (.crx files)
I am attempting maintenance on a system I did not write (and aren't we all?). It is written in C Sharp and JavaScript, with Telerik reports.
It has the following code included in JavaScript that runs when the user clicks a button to display a report in a separate window:
var oIframe = $("iframe id='idReportFrame' style='display:none' name='idReportFrame' src=''>");
oIframe.load(function() { parent.ViewReports(); });
oIframe.appendTo('body');
try
{
$('#idReportForm').attr('target', 'idReportFrame');
$('#idReportForm').submit();
}
catch (err) { // I did NOT write this
}
Then the load function:
function ViewReports()
{
var rptName = $("#ReportNameField").val();
if (rptName == '') { return false; }
var winOption = "fullscreen=no,height=" + $(window).height() + "left=0,directories=yes,titlebar=yes,toolbar=yes,location=yes,status=no,menubar=yes,scrollbars=no,resizable=no, top=0, width=" + $(window).width();
var win = window.open('#Url.Action("ReportView", "MyController")?pReportName=' + rptNameCode, 'Report', winOption);
win.focus();
return false;
}
When I execute this (in Chrome, at least), it does pop up the window and put the report in it. However, breakpoints in the c# code indicate that it is getting called 2 or 3 times. Breakpoints in the JavaScript and examination of the little log in the JavaScript debugging environment in Chrome show that the call to win.focus() fails once or twice before succeeding. It returns an undefined value, and then it appears that the first routine above is executed again.
I am inclined to think it some kind of timing issue, except that the window.open() call is supposed to be synchronous as far as I can tell, and I don't know why it would succeed sometimes and not others. There is a routine that gets executed on load of the window, perhaps that's somehow screwing up the return of the value from open().
I am not a JavaScript person much, as those of you that are can likely tell by this time. If there is something with the code I've put here that you can tell me is incorrect, that's great; what I'm more hopeful for is someone who can explain how the popup-report-in-frame is supposed to work. Hopefully I can do it without having to replace too much of the code I've got, as it is brittle and was not, shall we say, written with refactoring in mind.
From what I could find the window.open will return null when it fails to open. Something may be keeping the browser from opening additional windows a couple of times; maybe it is a popup blocker.
The actual loading of the url and creation of the window are done asynchronously.
https://developer.mozilla.org/en-US/docs/Web/API/Window.open
Popup blocking
In the past, evil sites abused popups a lot. A bad page could open
tons of popup windows with ads. So now most browsers try to block
popups and protect the user.
Most browsers block popups if they are called outside of
user-triggered event handlers like onclick.
For example:
// popup blocked
window.open('https://javascript.info');
// popup allowed
button.onclick = () => {
window.open('https://javascript.info');
};
Source: https://javascript.info/popup-windows
I just ran into this and it seems to be because I had a breakpoint on the line that calls window.open and was stepping through the code, in Chrome dev tools. This was extremely hit-and-miss and seemed to fail (return null, not open a window, whether one already existed or not) more times that it succeeded.
I read #Joshua's comment that the creation is done asynchronously, so I figured that forcing the code to 'stop' each time I step might be screwing things up somehow (though on a single line like var w = window.open(...) doesn't seem like this could happen).
So, I took out my breakpoint.. and everything started working perfectly!
I also took note of https://developer.mozilla.org/en-US/docs/Web/API/Window/open where they specify that if you are re-using a window variable and name (the second argumen to window.open) then a certain pattern of code is recommended. In my case, I am wanting to write HTML content to it, rather than give it a URL and let it async load the content over the network, and I may call the whole function repeatedly without regard for the user closing the window that pops up. So now I have something like this:
var win; // initialises to undefined
function openWindow() {
var head = '<html><head>...blahblah..</head>';
var content = '<h1>Amazing content<h1><p>Isn\'t it, though?</p>';
var footer = '</body></html>';
if (!win || win.closed) {
// window either never opened, or was open and has been closed.
win = window.open('about:blank', 'MyWindowName', 'width=100,height=100');
win.document.write(head + content + footer);
} else {
// window still exists from last time and has not been closed.
win.document.body.innerHTML = content;
}
}
I'm not convinced the write call should be given the full <html> header but this seems to work 100% for me.
[edit] I found that a Code Snippet on Stackoverflow has a some kind of security feature that prevents window.open, but this jsfiddle shows the code above working, with a tweak to show an incrementing counter to prove the content update is working as intended. https://jsfiddle.net/neekfenwick/h8em5kn6/3/
A bilt late but I think it's due to the window not beeing actually closed in js or maybe the memory pointer not being dereferenced.
I was having the same problem and I solved it by enclosing the call in a try finally block.
try {
if (!winRef || winRef.closed) {
winRef = window.open('', '', 'left=0,top=0,width=300,height=400,toolbar=0,scrollbars=0,status=0,dir=ltr');
} else {
winRef.focus();
}
winRef.document.open();
winRef.document.write(`
<html>
<head>
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
${$(id).remove('.print-exclude').html()}
</body>
</html>
`);
winRef.document.close();
winRef.focus();
winRef.print();
} catch { }
finally {
if (winRef && !winRef.closed) winRef.close();
}
I've been looking for an answer to this problem, but couldn't find it anywhere.
I have written an app that utilizes Watin. It works fine, apart from the problem that if I click the "X" button to close the app BEFORE Watin completes all of the actions (before it's disposed, I guess), it doesn't close. My app is still running (although the form is no longer there), as well as all of the IE instances.
I guess I should use FormClosing event handler to kill Watin, but since I'm utilizing the using statement, I've no idea how to achieve that.
Here's a piece of code I'm using:
using (var newBrowser = new IE("http://address.com"))
{
AnalyzeTools FormActions = new AnalyzeTools(progressBar, labelProgress, labelProgressOutOf, richBoxKeywords.Lines.Count());
Analyzer Analytic = new Analyzer(newBrowser, richBoxKeywords.Lines.ToList<string>(), FormActions);
BeingAnalyzed = Analytic;
Analytic.Initialize(textBoxLogin.Text, textBoxPass.Text);
Analytic.HandleAnalysis();
}
EDIT:
OK, I did some more trouble-shooting and this is what I've come up with:
The app is working until all it's finished, simple as that. But it doesn't finish "properly", though -- it crashes, because it can't access the form which no longer exists.
I believe I could fix this by creating a FormClosing or FormClosed event that when triggered, would modify the behaviour of my app. A custom "exit" method. But still, I won't be terminating Watin (something I want to do) and the app would be still running.
The thing is, I don't really need it to accomplish all of the actions it's supposed to.
Is my idea of termination a good one? And is there a way to terminate Watin without dropping the using-statement idea?
EDIT 2:
OK, I tried a few new things.
I created that messagebox which asks for a decision. I tried using Application.Exit() to terminate, but it doesn't work as I hoped it would. The app's vshost is still running (WatiN?).
So I guess my question comes to this: is the only way to terminate WatiN to drop the using statement, make the IE object available everywhere in the class and dispose it when the user chooses to terminate it?
I think what you need to do is create an instance of IE and then just close that instance. When you need it again you can just recreate the instance. I found this on Stackoverflow a long time ago when I had a similiar problem but I couldn't find it again to link to it.
public sealed class BrowserIE
{
static readonly IE _Instance = new IE();
static BrowserIE()
{}
BrowserIE()
{ }
public static IE Instance
{
get { return _Instance; }
}
}
create a class with the code above. use
var browser = BrowserIE.Instance("myUrl");
and when your done with it use:
browser.Close();
hope this helps. If you have any other questions I'll try to help.
Which version of WatIn are you using
Watin has a specific dispose method for this job
browser.Dispose();
I start the Windows On-Screen-Keyboard like that:
s_onScreenKeyboard = new Process();
s_onScreenKeyboard.StartInfo = new ProcessStartInfo("osk.exe");
s_onScreenKeyboard.EnableRaisingEvents = true;
s_onScreenKeyboard.Exited += new EventHandler(s_onScreenKeyboard_Exited);
s_onScreenKeyboard.Start();
This works fine, but when I try to stop it using the following code, it does not work, i.e. the OSK keeps running and the method returns false:
s_onScreenKeyboard.CloseMainWindow();
if (!s_onScreenKeyboard.HasExited)
{
if (!s_onScreenKeyboard.WaitForExit(1000))
{
s_onScreenKeyboard.Close();
//s_onScreenKeyboard.Kill();
}
}
When uncommenting s_onScreenKeyboard.Kill(); it is closed, but the problem is that osk.exe obviously uses another process called "msswchx.exe" which is not closed if I simply kill the OSK process. This way, I would end up with hundreds of these processes which is not what I want.
Another strange thing is that the CloseMainWindow() call worked at some time, but then it suddenly did not work anymore, and I do not remember what has changed.
Any ideas?
EDIT: I have found a solution myself. Please see my answer for details.
Background:
I am implementing an On-Screen-Keyboard for my application because it should work with a touchscreen. It is important that the keyboard layout matches the layout which is configured in Windows since the application will be shipped to many different countries. Therefore, instead of implementing a custom keyboard control with approx. 537 keyboard layouts (exaggerating a little here...), I wanted to utilize the Windows built-in On-Screen-Keyboard which adapts to the selected keyboard layout automatically, saving a lot of work for me.
I have found the/a solution myself:
When I successfully retrieve the MainWindowHandle after the process has been started, the call to CloseMainWindow() is also successful later on. I do not understand the reason for this, but the important thing is: it works!
BTW, for others having the same problem: The MainWindowHandle is not available immediately after starting the process. Obviously, it takes some milliseconds until the MainWindow is started which is why I use the following code to retrieve the handle:
DateTime start = DateTime.Now;
IntPtr handle = IntPtr.Zero;
while (handle == IntPtr.Zero && DateTime.Now - start <= TimeSpan.FromSeconds(2))
{
try
{
// sleep a while to allow the MainWindow to open...
System.Threading.Thread.Sleep(50);
handle = s_onScreenKeyboard.MainWindowHandle;
}
catch (Exception) { }
}
In this code I continuously get the MainWindowHandle every ~50ms as long as it is still equal to IntPtr.Zero. If the handle could not be retrieved after 2 seconds, I quit the loop to avoid an endless loop in case of error.
You need to wait untill the process finishes initialization, run
Process.WaitForInputIdle Method in order to do that.