Using selenium's waitForCondition with an xpath - javascript

Selenium has some nice support for finding elements in a page via xpath
selenium.isElementPresent("//textarea")
and in ajax pages you can use waitForCondition to wait on a page until something appears
selenium.waitForCondition("some_javascript_boolean_test_as_a_string", "5000")
My difficulty is, I can't seem to get into a position to use the xpath support for the boolean test. document.getElementById seems to work fine, but selenium.isElementPresent doesn't.
Is there any easy way of accessing selenium's xpath element finding abilities from within waitForCondition's first parameter?

An more straightforward way to do it is:
selenium.waitForCondition("selenium.isElementPresent(\"xpath=//*[#id='element_id_here']/ul\");", time_out_here);

You could do something like this:
selenium.waitForCondition(
"var x = selenium.browserbot.findElementOrNull('elementIdOrXPathExpression');"
+ "x != null && x.style.display == 'none';", "5000");
The waitForCondition just evaluates the last js expression result as a boolean, thereby allowing you to write complex tests (as shown here). For example, we're also using this technique to test whether jQuery AJAX has finished executing.
The only drawback is you're also now relying on the browserbot and the lower level core js API.

If you want to select an element by id, the simplest thing is to use straight selenese:
isElementPresent("textarea")
If you insist on using xpath you may have to use
isElementPresent("//*[#id='textarea']")
or
isElementPresent("//id('textarea')")
(The id function may not be cross-browser compatible)
If this does not help your html document may also have structural issues that is causing this to happen. Run an html validator like html validator to check for nesting problems and similar on your page.

Related

Scope of inline JavaScript vs script element [duplicate]

It is common for me to register javascript functions for certain events by doing something like:
myBtn.Attributes.Add("onClick", "Validate(getElementById('"+txtFirstName.ClientID + "'));");
I've always used getElementById by itself, or in other words, sans document being prepended to it. But I'm having pages break on me lately when I try to use getElementById instead of document.getElementById. Why is this? Oddly, I have a website where one page allows me to use just getElementById, but another other page throws a javascript error because it can't find the element if I do just getElementById, and it'll only work if I do document.getElementById.
Anyone know why this is? Should I be using document.getElementById everywhere, regardless of whether it works without the document prefix?
EDIT:
Could it have anything to do with the fact that one page is using AJAX and the other isn't?
When you use getElementById() and it works that mean that the function where it's called is running on the context of the document, that's is this == document.
So, you should ALWAYS use document.getElementById to avoid that kind of errors.
Anyway, I would even stop using getElementById altogether and start using JQuery, i'm sure you'll never regret it.
Your code would look something like this if you used JQuery:
$("#myBtnID").click(function () { Validate($("#myTextboxID"))});
Any function or variable you access without an owning object (ex: document.getElementById) will access the property from window.
So getElementById is actually window.getElementById, which isn't natively defined (unless you defined it before (ex: getElementById = document.getElementById).
You should use the full document.getElementById(). If you find that too verbose, you could use jQuery:
$('#' + id)
or you could create an alias at the top of your script:
var byID = document.getElementById;
You should only use document.getElementById (even if I'd recommend using libraries like prototype or jquery to be able to use the $ sign).
If you are able to use getElementById on its own, it's just because the browser you're using is doing some kind of trick to get it to work, but the correct way is to use the document variable.
I dont really know how to explain it but its because the getElementById() finds an element in the html structure of a page. Some browsers know that by default you want to search the document, but other browsers need that extra guidance hence document.
The correct way is indeed document.getElementById().
The reason (speculation) it might work by itself is that depending on where you use it the current context may in fact be the document object, thus inexplicitly resulting in document.getElementById().

Get ckeditor object from innerHTML

I have a situation where i have to take the CKeditor text from an iframe, in javascript, following some answers to similar problems (but not exactly the sames) i've arrived to get the inner html of the page and what i get is the textarea of the CKeditor.
To get what i've written above i've used this method:
document.getElementById(id).contentDocument.body
Now from here i would like to do one of those two things, but i don't know how or if it's possible:
1) First and more preferable, i would like to parse the body as a CKEDITOR instance, so that i can use the libray methods to get the text inside, is it possible?
2) Second (if the first option is not possible) i would like to navigate more inside but the only way that i have in mind is another getElementsById, but by reading some answer around i've seen that this is not a good practice to do what i need, why?
What's the best practice between the two? (Or if there is another way, what is it?)

jQuery and selectors: how can I make sure that there really is the element I'm looking for?

I'm no experienced JavaScript developer (I know quite a lot about Ruby, though), and so far, when I had to implement some lines of JS, it seemed enough to use jQuery and hack together something.
As far as I understand jQuery, it doesn't assume HTML elements to really be there, but it simply executes a query, and if there is a matching element (or many), some stuff is done with it. This works well for generic code which may want to apply some action to some elements on a page (which may be there or not), but when it comes to specific logic, it's a problem.
What do I mean with this? Let me give an example.
Let's suppose I have one single page with one single HTML element (with the ID '#my_element'). For exactly this page I have to run some JS code, and I have to be sure that it finds this element and does the things to it that I want.
Doing this with jQuery, I simply do something like $('#my_element').addTooltip(), which seems fine first: when I hover over the element, a tooltip is displayed.
Let's assume that some months later I already have completely forgotten about this JS script, and I change the ID of the element to something else. What happens? Nothing. I won't notice the problem with the missing tooltip until I stumble over it by accident.
So I wonder how I can make sure that my JS is really applied, which means: the required elements are found, the stuff is done to them, etc.
Is jQuery's philosophy the "wrong" tool for this? Do I need another framework? Maybe something more sophisticated pattern, e.g. something like MVC? I played with KnockoutJS before, and it seems that this may be better for this, as it's bound directly to elements using data-bind attributes, so it fits tighter on the code than jQuery does.
The comments mentioned always checking the .length property before performing actions on returned results (which is probably the best answer,) but in the case of an actual syntax error your statement that "nothing happens" isn't always true.
If you're using Chrome developer tools or a similar tool in another browser (firebug, etc.) you should see the error in the "Console"
You can also turn on javascript debugging for more information. When you call the "addTooltip()" on something which is null (the jQuery collection) you'll see an error pop up in the Console and may get an exception in the debugger.
This is one of the easiest ways to find errors in your client-side javascript.
You could add a specific plugin to verify the existence of a non-zero- length collection, and use that in the chain:
(function ($) {
$.fn.verify = function() {
if (this.length) {
return this;
}
else {
console.log("No elements found with supplied selector.")
}
}
})(jQuery);
$("#myElement").verify().addTooltip();
This does, of course, rely on the verify() plugin being manually applied, there is – to the best of my knowledge – no error-reporting built in to jQuery to automatically enable logging of invalid selectors, or reporting of selectors returning zero elements.

jQuery selector debugger

I recently started to work on existing project. The previous developer had a lot of javascript and html template files. Over time, he removed pieces of code from this files leaving parts without any reference (see the examples).
For example
(a) a button without a click event
(b) a jquery selector without a DOM element inside the HTML: $('#someSelector') but <someElement id="someSelector"></someElement> doesn't exists.
The case (a) is quite simple to solve, because I just see the unused element and I delete it from the appropriate file.
The second part is a little bit more difficult, because the browser console is not firing an error when jQuery does not find a selector.
I can test selectors using something like this:
if($('theSelector').length ){
//alert or console, the selector matches some element.
}
This technique is very expensive in time, because I need to test one by one every selector.
Is there a tool for automate this task? I tried FireQuery (a firefox plugin) but it is not giving me good results.
P.S:
The project is not using a javascript framework nor system template. (really bad!)
you can kick the tires for a bit after modifying $ to log it's calls.
load the following script
var $$=$, log=[];
$=function(s){
log.push(s);
return $$.apply(this, arguments);
};
$$.extend($,$$);
now click around and do "everything" jQuery does on the site, then run:
console.log(log.filter(function(s){
return jQuery(s).length===0;
}));
to dump a list of un-realized selectors to the console. of course, fix the problems and remove this code because it slows jQuery down a lot, and it might not be 100% compatible with all plugins, but it works on the quick tests i did here on stack via the console. you might also consider shadowing "jQuery" in addition to "$" to capture noconflict usages.

Is there a better way to do innerHTML?

I want to know if there is a better way to be doing innerHTML than what I do here. The way I am doing it is causing problems because of the fact that I can't have triple nested quotes. along side that, it is really hard to look at and manage. Thanks!
function buttonClicked(buttonValue)
{
switch (buttonValue)
{
case 1:
soundFolders.innerHTML = "<li onClick='buttonClicked(11);'>Thunder 1</li> <li onClick='buttonClicked(13);'>Light Rain 1</li> <li onClick='buttonClicked(0);'>Back</li>";
break;
case 11:
if(!thunder1Control)
{
thunder1.play();
var thunder1Control = document.createElement("li");
soundList.appendChild(thunder1Control);
thunder1Control.innerHTML = "<h3>Thunder 1</h3> <button class='stopSound' onClick='thunder1.pause(); thunder1.currentTime=0; thunder1Control.parentNode.removeChild(thunder1Control); '>X</button> <button class='volDown' onClick='thunder1.volume -= 0.25;'>-</button> <button class='volUp' onClick='thunder1.volume += 0.25;'>+</button>";
thunder1Control.setAttribute("class", "playingSound");
}
P.S. Do you guys know why the thunder1Control.parentNode.removeChild(thunder1Control) is not working?
To your first question about another way to approach this type of code, "best" is a matter of opinion so I won't really try to address what is best. But, I will give you some alternatives:
Avoid putting code into strings in your HTML. There are all sorts of limitations with that and you generally want to separate code from presentation anyway.
Install event handlers in your code with obj.addEventListener() instead of putting event handlers and code in your HTML.
Use classes and IDs or DOM queries from a particular point in the hierarchy to retrieve specific objects in your page rather than trying to save references to them in global variables. In plain javascript, element.querySelectorAll() is pretty powerful.
In many cases, it's much simpler to just hide and show blocks of HTML using obj.style.display = "none" and obj.style.display = "block" than it is to dynamically create and destroy HTML and this has the added advantage of the HTML is all specified in the page and doesn't have to be shoehorned into a javascript string.
For large blocks of dynamic HTML that wouldn't work well with hide/show for whatever reason, you can dynamically load snippets/templates of HTML from your server using ajax or you dynamically create the HTML using javascript. My first preference is generally hide/show and then if that isn't practical for some reason, it depends upon how much the HTML I want to insert varies based on the state for whether I'd rather load a template or create it dynamically using javascript. If you have large blocks of HTML you have to fit in your javascript, it is messy with quoting, etc... - no way around that if you go that route other than using one quoting scheme for the JS string delimiter and the other in your HTML.
In your particular case, it sure looks like the hide/show method would be simple.
To your second question, this line of code:
thunder1Control.parentNode.removeChild(thunder1Control)
does not work because the thunder1Control variable is long, long out of scope when your click handler is executed because it's a local variable in your buttonClicked() clicked function.
When you put code into a string as part of HTML, it is evaluated in the global scope only so any variables that it tries to reference, must themselves be global in scope.
I'd suggest that you NOT put code into strings in your HTML like that. Use references to actual javascript functions. In that particular case, I'd have to see your HTML to know how to best advise you. If there is only ever one thunder1Control, then I'd suggest you just put an id value on it and retrieve it with document.getElementBtId() when you need it rather than trying to save a reference to it in a variable.
There are essentially two other ways that I can see:
Use a framework that helps with this kind of things. Others have
mentioned jQuery. A commenter is arguing that it might be overkill
to include a framework for just this. I would argue that if you're
doing any javascript at all, you should be using a framework to
make it less terrible. But continue onto suggestion 2 if you
disagree!
You can create each of the elements via plain old javascript and append it to the elements that you need, instead of inserting it directly into innerHTML. ex.
var li = document.createElement("li");
soundFolders.appendChild(li);
etc...
But, honestly, use jQuery with some of the suggestions from others. It's pretty small, and it will heavily clean up all of your javascript. Include it via Google and it will likely already be cached in the users browser.
https://developers.google.com/speed/libraries/devguide#jquery
I think a better alternative is to use jQuery, and then instead of using .html() (equivalent of innerHTML in jQuery), you can create a template with your html and use .load() instead. Works nicer and it's cleaner. And you don't have to worry about triple nesting quotes as you said.
Edit: I'm not sure why I'm getting downvoted so much here... The poster doesn't want to worry about triple nesting quotes. A simple and, to me, elegant solution is to use .load() and to create a template, rather than a really long string of html...

Categories

Resources