I am trying to fix some bugs in a product I inherited, and I have this snippet of javascript that is supposed to hilight a couple of boxes and pop up a confirm box. What currently happens is I see the boxes change color and there is a 5 or so second delay, then it's as if the missing confirm just accepts itself. Does anyone smarter than I see anything amiss in this code?
function lastCheckInv() {
document.getElementById("ctl00$ContentPlaceHolderMain$INDet$txtInvNumber").style.background = "yellow";
document.getElementById("ctl00$ContentPlaceHolderMain$INDet$txtInvNumber").focus();
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_AddCharges").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
bRetVal = confirm("Are you sure the information associated with this invoice is correct?");
return bRetVal;
}
The only thing I can think of is if one of the lines before the confirm is throwing an exception and you're never actually getting to the confirm.
If you're using IE, make sure script debugging is enabled. If you're using Firefox, install the Firebug add-on and enable it for your website.
Or, for very primitive debugging, just put alerts after each statement and figure out where it's bombing.
You should use the following method to reference your controls from JavaScript:
document.getElementById(<%= txtInvNumber.ClientID %>).style.background = "yellow"
If that doesn't help, try setting a breakpoint in your JavaScript and stepping through it to see where it's failing.
This test script ran fine for me in IE, Firefox, and Opera. So there doesn't seem to be anything wrong with your basic syntax. The problem is either in the ID's (which doesn't fit with the fact that it acts as if confirmed after 5 seconds) or in some other conflicting JavaScript on the page. It will be difficult to help you without seeing more of the page.
<script language="javascript">
function lastCheckInv() {
document.getElementById("test1").style.background = "yellow";
document.getElementById("test1").focus();
document.getElementById("test2").style.background = "yellow";
document.getElementById("test3").style.background = "yellow";
bRetVal = confirm("Are you sure?");
return bRetVal;
}
</script>
<form method="get" onsubmit="return lastCheckInv();">
<input id="test1" name="test1" value="Hello">
<input id="test2" name="test2" value="Hi">
<input id="test3" name="test3" value="Bye">
<input type="submit" name="Save" value="Save">
</form>
A few thoughts: Could be the .focus() call is hiding your confirm behind the page? Or could it be that one of your control id's is not correct causing, the .style.background references to fail?
You should set the focus after showing the confirm box, otherwise the confirm box will grab focus away, making that line meaningless.
Don't hard-code ASP.Net id's like that. While they typically are consistent, a future version of ASP.net won't guarantee the same scheme, meaning your setting yourself up for pain when it comes time to update this code at some point in the future. Use the server-side .ClientID property for the controls to write those values into the javascript somewhere as variables that you can reference.
Update:
Based on your comment to another response, this code will result in a postback if the function returns true. In that case, there's not point in running the .focus() line at all unless you are going to return false.
I do not like accesing objects directly by
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
If the object is not returned JavaScript will error out. I prefer the method of
var obj = document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight");
if(obj)
{
obj.style.background = "yellow";
}
My guess is you are trying to access an object that is not on the DOM, so it never gets to the confirm call.
It might be worth checking that the elements actually exist. Also,try delaying the focus until after the confirm():
function lastCheckInv() {
var myObjs,bRetVal;
myObjs=[
"ctl00_ContentPlaceHolderMain_INDet_AddCharges",
"ctl00_ContentPlaceHolderMain_INDet_lblFreight",
"ctl00$ContentPlaceHolderMain$INDet$txtInvNumber"
];
bRetVal = confirm("Are you sure the information associated with this invoice is correct?");
for (var i=0, j=myObjs.length, myElement; i<j; i++){
myElement=document.getElementById(myObjs[i]);
if (!myElement){
// this element is missing
continue;
}
else {
// apply colour
myElement.style.background = "yellow";
// focus the last object in the array
if (i == (j-1) ){
myObj.focus();
}
}
}
return bRetVal;
}
function lastCheckInv()
{
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_txtInvNumber").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_txtInvNumber").focus();
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_AddCharges").style.background = "yellow";
document.getElementById("ctl00_ContentPlaceHolderMain_INDet_lblFreight").style.background = "yellow";
return confirm("Are you sure the information associated with this invoice is correct?");
}
The first two lines in your function are wrong, $ are in the UniqueID of an ASP.Net Control.
On Clientside you have to use the ClientID, replace $ with _ .
If you are sure that the Controls exists, the
code above might work.
Is bRetVal actually declared anywhere?
If not, "var bRetVal = confirm...." is a friendly way of telling jscript that it is a variable.
Related
I am writing integration tests in c# and when I use the click() method on certain elements inside a dialog box nothing happens and I get no errors. It will click some of the elements inside the dialog but not others. I thought if it wasn't selecting them properly then it would throw and exception but it runs smooth and says test passed even though it never actually clicked the button. The dialog box is an iframe.
I thought maybe it was trying to click a button that wasn't display yet or enabled so I added this before the click() call:
_driver.SwitchTo().Frame(_frameElement);
_wait.Until(d =>
{
var shippingInfoButton = d.FindElement(By.CssSelector("input[title ='Info']"));
return shippingInfoButton.Displayed && shippingInfoButton.Enabled;
});
var infoButton = _driver.FindElement(By.CssSelector("input[title ='Info']"));
ScrollToElement(infoButton);
infoButton.Click();
again this runs with no thrown exceptions so I'm assuming it has found the element and it is both displayed and enabled.
Let me know if you need any more info. Thanks
I can't explain why the selenium driver .click() method won't fire on some elements in the page but not others, but I did find a solution.
Using IJavaScriptExecutor you can click the element using javascript instead and in my case it worked.
Here is the code to run the IJavaScriptExecutor and below is my whole method.
//IJavaScriptExecutor
IJavaScriptExecutor js = _driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].click();", infoButton);
//my whole method for clicking the button and returning the page object
public ShippingMethodDetailsPageObject SelectShippingMethodInfo()
{
_driver.SwitchTo().Frame(_frameElement);
_wait.Until(d =>
{
var shippingInfoButton = d.FindElement(By.CssSelector("input[title='Info']"));
return shippingInfoButton.Displayed && shippingInfoButton.Enabled;
});
var infoButton = _driver.FindElement(By.CssSelector("input[title ='Info']"));
IJavaScriptExecutor js = _driver as IJavaScriptExecutor;
js.ExecuteScript("arguments[0].click();", infoButton);
_driver.SwitchTo().DefaultContent();
return new ShippingMethodDetailsPageObject(_driver, false);
}
I ran into a similar problem. If it's the same problem there's a fault in the ChromeDriver it can't click certain elements because of surrounding divs etc. Bit lame really.
A simple fix is to send the Enter key e.g. element.SendKeys(Keys.Enter). Seems to work across all browsers.
I have some tests that works in Firefox all the times, and in Chrome it drove me mad, because sometimes it passed successfully, and sometimes the ".click" didn't work and it would fail the test.
Took a long time to notice it, but the reason was: I used to sometimes minimize the browser to 80% to be able to see the browser along side my IDE. it appears that the ".click" doesn't work when I did it.
At least for me this was the issue
This is weird. I'll try to explain my pain by the following example:
I've got an object in the Session: Session["reportQuestionGroupingTracker"]. It contains a List of strings. When a string is NOT found, a new h3 header is written in the repeater via a string literal.
The problem seems to be the line: Session["reportQuestionGroupingTracker"] = ary; This line seems to somehow (black)magically remove the string value in lit.Text. The value is there when I breakpoint the code and seems to persist until it goes out of scope in the function(so that part works like expected) - but the string value never seems to make it to the Literal control on the ASP.NET page - they are always blank.
Note that if I comment out the problem line or this line: if (!ary.Contains(headingText)), the headers show (but too many of them, since every iteration triggers a header write).
protected void rptQuestionsGroupedByCountry_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
RepeaterItem item = e.Item;
ArrayList ary = new ArrayList();
if (null != Session["reportQuestionGroupingTracker"]) ary = (ArrayList)Session["reportQuestionGroupingTracker"];
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
DataRowView dr = (DataRowView)e.Item.DataItem;
string headingText = dr["Heading"].ToString();
Literal lit = (Literal)e.Item.FindControl("LiteralHeader");
if (!ary.Contains(headingText))
{
lit.Text = String.Format(#"<h3 class=""questionGroupingHeader"">{0}</h3>", headingText);
lit.Visible = true;
ary.Add(headingText);
Session["reportQuestionGroupingTracker"] = ary;
}
}
}
I've been on this for hours, banging my head - I've done similar things hundreds of times before, I just can't work out why it doesn't work this time! I've tried changing the Repeater to a DataList, Tried using the Context.Items object instead of the Session, a List instead of an ArrayList, but I'm stymied. Help!
I've also tried running it in IIS 6, just in case it was some Cassini weirdness, but the output is the same. It's an ASP.NET 4.0 Project.
Here's the code from the aspx page:
<asp:Repeater ID="rptQuestionsGroupedByCountry" runat="server" OnItemDataBound="rptQuestionsGroupedByCountry_OnItemDataBound">
<HeaderTemplate><table></HeaderTemplate>
<ItemTemplate>
<tr><td>
<asp:Literal ID="LiteralHeader" runat="server" Visible="false" />
<h3 class="report-country-tag"><%#DataBinder.Eval(Container, "DataItem.Numbers")%>.<%#DataBinder.Eval(Container, "DataItem.QusetionName")%></h3>
<div class="report-content">
<%#DataBinder.Eval(Container, "DataItem.Answer")%>
<p class="date">Date Updated: <%#DataBinder.Eval(Container, "DataItem.DocumentModifiedWhen")%></p>
</div>
</td></tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
your problem with line
if (!ary.Contains(headingText))
You must populate literal text every time page loaded
if (!ary.Contains(headingText))
{
ary.Add(headingText);
Session["reportQuestionGroupingTracker"] = ary;
}
lit.Text = String.Format(#"<h3 class=""questionGroupingHeader"">{0}</h3>", headingText);
lit.Visible = true;
As Micheal suspected, the databind routine was being hit twice for every page load. The first time through the Session gets set properly, but the second time through, the Headers get skipped because the if (!ary.Contains(headingText)) correctly told it to. My bad for not noticing the two databinding hits. I feel very foolish. Coding while tired is no excuse for such an obvious issue. Sorry for wasting your time!
Also I was working with too large a dataset - I'd walk through the first 5 loops and see that the value was being set and then just F5. It wasn't until I was clearheaded this morning and just put breakpoints in every function so that I could see the execution order and understand what the heck was going on. Then it was a headslap moment... quickly followed by a single line change to fix the issue... and then a feeling of elation. Ain't programming fun?
Cheers and thanks for the help!
PS - Shout out to Kochobay for the line: '...every time page loaded...' which induced the headslapping epiphany!
Here are the steps I'd like to take:
1) User enters search term into box in silverlight, then presses enter
2) Search term is passed into javascript via C# code: HtmlPage.Window.Invoke("CallAPI", SearchText);
3) CallAPI function hits the API via $.getJSON & returns a value into the JS callback function [this is already done]
4) Resultant object is returned to the Silverlight/C# page for display in silverlight UI
I can do everything except step 4. How do I get a JSON object from Javascript into C#? I've been working on this for the last few hours, and this is what I thought would do it:
ScriptObject myScriptObject = (ScriptObject)HtmlPage.Window.Invoke("CallWordStreamAPI", SearchText);
I set a breakpoint in my JS & validated that the object in my return statement is definitely populated with the 20 rows of data, as expected.
I set a breakpoint in my C# (ScriptObject myScriptObject = ....), and myScriptObject is null after the call.
If I set a breakpoint in firebug/chrome dev at the line "return r" (my object), I can see there are 20 items listed in r.data. If I set a breakpoint after the myScriptObject line listed above, myScriptObject is null.
Your help is appreciated.
Scott
I was calling this from a ViewModel on the server side. I ended up using MVVM Messaging to send the keyword over to my code behind on the client side. I then called my JS function, returned the result, and shot a message back into my view model.
Aside from that, the syntactic issues were resolved here:
How can I pass a JavaScript function to Silverlight?
My Code:
<!-- language: JavaScript -->
function sendText() {
return "Hi from Javascript!";
}
<!-- language: C# -->
string obj = HtmlPage.Window.Invoke("sendText", null) as string;
txtReturnData.Text = obj;
<!-- language: VB.Net -->
Dim obj As String = TryCast(HtmlPage.Window.Invoke("sendText", Nothing), String)
txtReturnData.Text = obj
I am trying to keep track of prints that are made for a page. The page has Print this page link. And the code for it is like below: This is written in .cs file as there are many conditions for displaying this. And i am appending here using String Builder.
sbOutput.AppendFormat("<td align=\"right\" valign=\"bottom\"><div style =\"float:right;text-align:right; valign:bottom;width:200px\"class=\"print_button notPrinted\"><a class=\"notPrinted\" href=\"#\" onclick=\"window.print();\">PRINT THIS COUPON </a><img src=\"images/print-icon-34x34.gif\" class=\"notPrinted\" align=\"absmiddle\" /></div> </td></tr></table>", couponid, Userid, locationid);
Do i have to use onclientclick or something else??
Thanks so much in advance.
Good option would be to write a Javascript function to enable Ajax call, so that you can send a request to server to record the print coomand.
PRINT THIS COUPON
function RecordPrint()
{
// Make a AJAX Call to your server Page to record Print Command.
// printRecorded : success from server
If(printRecorded)
{
window.print();
}
return false;
}
Hope that helps.
since you seem to print on the client side only, you could do
PRINT THIS COUPON
On the server side, implement the counter.aspx page to just count the request and quit silently. Make sure, the window.print() will return true - otherwise the link is not executed.
I am using Selenium 2 (latest release from Googlecode) and I have it firing up Chrome and going to a url.
When the page has loaded some javascript executes to set the value of a textbox.
I tell it to find a textbox by id which it does but it doesn't have the value within it (if I hardcode a value it finds it).
Looking at the PageSource e.g. Console.WriteLine(driver.PageSource); shows the html and the textbox is empty.
I've tried using :
driver.FindElement(By.Id("txtBoxId") to get the element and that too doesn't fetch the value.
I've also tried ChromeWebElement cwe = new ChromeWebElement(driver, "txtBoxId"); (which complains about Stale data).
Any thoughts?
John
Finally I found the answer! This is the code that works for me
WebDriverWait wait = new WebDriverWait(_driver, new TimeSpan(0,0,60));
wait.Until(driver1 => _driver.FindElement(By.Id("ctl00_Content_txtAdminFind")));
Assert.AreEqual("Home - My Housing Account", _driver.Title);
Here is my source!
http://code.google.com/p/selenium/issues/detail?id=1142
Selenium 2 does not have wait functions built in for elements in the DOM. This was the same thing as in Selenium 1.
If you have to wait for something you could do it as
public string TextInABox(By by)
{
string valueInBox = string.Empty;
for (int second = 0;; second++) {
if (second >= 60) Assert.Fail("timeout");
try
{
valueInBox = driver.FindElement(by).value;
if (string.IsNullOrEmpty(valueInBox) break;
}
catch (WebDriverException)
{}
Thread.Sleep(1000);
}
return valueInBox;
}
Or something along those lines
I use webdriver through ruby (cucumber watir-webdriver, actually), and I tend to do this:
def retry_loop(interval = 0.2, times_to_try = 4, &block)
begin
return yield
rescue
sleep(interval)
if (times_to_try -= 1) > 0
retry
end
end
yield
end
Then whenever I have content appearing due to javascript writes or whatever, i just wrap it in a retry_loop like so:
retry_loop do #account for that javascript might fill out values
assert_contain text, element
end
As you'll notice there is no performance penalty if it is already there. The reverse case (checking that something is NOT there) will always need to reach the timeout, obviously.
I like the way that keeps details packed away in the method and the test code clean.
Perhaps you could use something similar in C++?