Calling a function in a JavaScript file with Selenium IDE - javascript

So, I'm running these Selenium IDE tests against a site I'm working on. Everything about the tests themselves is running fine, except I would like to do a bit of clean-up once I'm done. In my MVC3 Razor based site, I have a JavaScript file with a function that gets a JsonResult from a Controller of mine. That Controller handles the database clean-up that Selenium IDE otherwise couldn't handle.
However, I'm having a hard time finding any sort of documentation on how to do this. I know I can do JavaScript{ myJavascriptGoesHere } as one of the Values for a line in the test, but I can't seem to find a way to tell it to go find my clean-up function.
Is it even possible for Selenium IDE to do this sort of thing?
If it comes down to it, I can just make a separate View to handle the clean-up, but I'd really like to avoid that if possible.
Thanks!

If you want to execute your own JavaScript function that exists in your test page from Selenium IDE, you need to make sure you access it via the window object. If you look at the reference for storeEval for instance, it says:
Note that, by default, the snippet will run in the context of the
"selenium" object itself, so this will refer to the Selenium object.
Use window to refer to the window of your application, e.g.
window.document.getElementById('foo')
So if you have your own function e.g. myFunc(). You need to refer to it as window.myFunc().
This can be very handy for exercising client-side validation without actually submitting the form, e.g. if you want to test a variety of invalid and valid form field values.
If you use runScript, that should already run in the window's context.

This works for me.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string title = (string)js.ExecuteScript("myJavascriptGoesHere");
Make sure your javascript works first before using it here!

Actually to access your page javascript space, you need to get the real window of your page : this.browserbot.getUserWindow()
See this statement to get the jQuery entry point in your page (if it has jQuery of course ^^ )
https://stackoverflow.com/a/54887281/2143734

Related

Extending TestComplete: How to change cursor?

I wrote a TestComplete extension to update Keyword-Test signature from TestComplete in to an external tool.
However, this action takes very long time. That's why I need to change the cursor from arrow to hour glass, and back to arrow after action is done.
The module doing the opperation is writen in js.
If I try to use the following code, suggested by TestComplete code completition
Win32API.SetCursor(Win32API.IDC_WAIT);
I got the error "Object expected". I.e., the js in the TestComplete extension does not know About Win32API object, despite the code completition suggestion.
Ommiting the Win32API. prefix has the same effect. Trying to create appropiate object via
new ActiveXObject("SomeKindClass")
fails, because I am not able to find appropiate name for the class containing some methode to change cursor. (I tryed, Microsoft.Win32, Microsoft.Win32API, Win32, Win32API and some other non-sence names...)
SmartBears description on writing extentions seems to contain no hint about changing the cursor in a js ScriptExtension.
Please appologize, if I overlook it.
Any suggestions are appreciated. Thanx in advice for your F1!
Edit:
A possible way to solve this is described bellow. However, I am not able to follow it to the end, because of lack of time. Perhaps someone can confirm or deny the correctness. That' would be great.
Steps:
Create a new vbs module in the ScriptExtension (or extend an existing one if any).
In
the init method of vbs module, load user32.dll, create prototypes for
the LoadCursor and CreateCursor methods of user32.dll. (See Tutorial)
You call those methods in your setCursor2* methods.
Declare the setCursor2* methods in the Description.xml as method in RuntimeObject of your namespace (See Script Extension Description file)
Call the methods in the js module YourNameSpace.setCursor2Hourglass(); and YourNameSpace.setCursor2Arrow(); respectively.
It is impossible to show an hour glass from a TestComplete extension.
The reason is, following quote, that comes from https://support.smartbear.com/testcomplete/docs/working-with/extending/script/creating/specifics.htm.
"If your design-time action performs actions against the TestComplete
main window (for example, minimizes the window, changes the window
size and position, and so on), an error will occur. This happens due
to specifics of thread organization in TestComplete."
I guess, the "on so on" part includes changing the cursor…

write to Java console when my Javascript callback (made in Selenium) returns

I have learned how to create Javascript callback functions and I have a basic understanding of 'functional programming' since it seems easy enough. I am however, new to javascript and it's syntax and I can't find a good way to test said syntax while in my IntelliJ IDE.
What is it you're doing?
I'm creating a Selenium based tool to click on a webelement, wait for it to reload the page, become stale or wait for a timeout. The reason I'm doing this is to classify webelements into three categories: causes a page reload, becomes stale, doesn't change. To do this I've made a simple javascript script with the JavascriptExecutor that comes with Java. Most of my code is in java and that is the language I am proficient in. I want to learn how to use javascript with java to do the things I want with web pages.
Ok but what specifically is the problem?
I have a javascript callback function:
function test(callback) {callback();}
function Return() {SeleniumTest.isPageReloaded.JavascriptWorking}
window.addEventListener('onload', test(Return));
which is executed inside a Javascript Executor like so:
System.setProperty("webdriver.chrome.driver",
"C:\\chromedriver_win32\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
String script = "function test(callback) {callback();}" +
"function Return()" +
"{SeleniumTest.isPageReloaded.JavascriptWorking}" +
"window.addEventListener('onload', test(Return));";
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript(script);
Which is basically the Javascript script from before, executing as a String. As you can see I am attempting to call a java class. SeleniumTest is my package, isPageReloaded is the current class and JavascriptWorking is a static method within that class. That static method looks like this:
public static void JavascriptWorking(){
System.out.println("Javascript ran here");
}
Its meant to be a simple way to get something from the javascript to my java code. The reason I tried it this way is because I read this:
https://documentation.progress.com/output/ua/OpenEdge_latest/index.html#page/bpm-appdev/invoking-java-methods-in-javascript.html
But then I realized that it wouldn't work and I dug deeper. I read that Javascript and Java are seperated by server and client and I gained some insight from this question:
calling java methods in javascript code
However I'm not 100% sure this is accurate to my case since the Javascript I'm executing isn't coming from the webpage I'm testing, Rather I made it myself inside the java code as a String. Additionally I'm still highly confused on if the answer to that question actually applies to me. There is only one and it basically just says, 'install some stuff because java is clientside and javascript is serverside'. I (kindof) understand what those terms mean but I'm not sure that the javascript I made in my class would be considered 'server-side' in fact it would seem to not be that way. What I need is clarification on A: is the javascript I'm running/creating in my java code actually serverside?
B: if yes then can someone give me a basic rundown on how I would go about calling java code from the server? does this require permissions? I assume I have to communicate with said server so does that mean I use GET and POSt requests?
C: If the Javascript Isn't server side then it must be clientside and I should be able to call it pretty easily right? How do I do this?
Show us what exactly you want
I want to be able to run:
System.setProperty("webdriver.chrome.driver",
"C:\\chromedriver_win32\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
String script = "function test(callback) {callback();}" +
"function Return()" +
"{//insert callback code here}" +
"window.addEventListener('onload', test(Return));";
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript(script);
and get either a static java method ran, something printed to console, or some other means that links the javascript code to the javacode. So for example if I inserted the correct code to call my static method:
SeleniumTest.IsPageReloaded.JavascriptWorking
(which again looks like):
public static void JavascriptWorking(){
System.out.println("Javascript ran here");
}
Then I'd want to see "Javascript ran here" on my java console. The driver being used is interchangebale, I just used chrome first because its fast. All that this needs is an enclosing main class and It ((should)) be runnable but no promises.
The purpose is to get something in java that I can then use as a flag to know that my asynchronous javascript is done in java and I can continue on with program execution. I can get the async javascript part and I understand it, I just need a link back to my java code.
Possible Solutions
I've been told that the common way to provide a flag for your java code is to create a certain webelement on the page with javascript and test for it in java (hence the link). I don't feel like adding to the webpages I test because I want to test them without actually editing/changing them. I'm generally open to other simple solutions but the biggest thing I need is clarification on the whole clientside serverside issue because its specific to my setup (Selenium java -> javascript -> java) where most questions only cover (javascript -> java) or vice versa.
The link you mentioned about JS invoking Java is for a specific application, that is meant to do that. Not saying it is impossible (I wrote FF plugins based on similar principle), but it is not applicable in this case. It also requires special application support (by default Javascript executed in browser is heavily sandboxed - it can't access anything out of its own scope. Invoking other apps on its own is a big no.).
The scripts you are injecting are always client side, they are executed only in the browser, that is isolated from the java code itself. With that said nothing is impossible.
Would like to mention two interesting features of the Selenium library that can come handy for you.
You mention a magic term many times "async Javascript execution" - and as I can see you are implementing your own version of executeAsyncScript. Webdriver does provide this method out of the box, pretty much for the purpose you want to use it with.
When you use executeScript, it will return pretty much immediately once it finished - in your case it will just inject your listener with your code, and then it returns. Using executeAsyncScript you can get a callback - just what you are doing. When calling executeAsyncScript, a default callback method is added to your code as the last argument, that needs to be called by your JS code for the method to return.
A simple example:
String script = "var callback = arguments[arguments.length - 1];" + //the last argument is the callback function
"var classToCall = 'SeleniumTest.IsPageReloaded';" + //the classname you want to return to call from Java in case of success)
"window.addEventListener('onload', callback(classToCall));";
//you can give any supported return value to the callback function. Here I assume that you want to call a static method. This is the class name that can be used later.
try {
JavascriptExecutor js = (JavascriptExecutor)driver;
//classToCall has the value we passed to the callback function
String classToCall = js.executeAsyncScript(script);
} catch (ScriptTimeoutException e) {
System.err.println("Uhhh... this failed I guess");
e.printStackTrace();
}
The executeAsyncScript does not return until the callback is called - to avoid infinite hangs, you can set the WebDriver.Timeouts.setScriptTimeout property to control this. If the script takes longer, JavascriptExecutor will throw an exception. Once returned, you can instantiate the returned class, and print like
Class clazz = Class.forName(classToCall); //it is only necessary if the classname is dynamic. If it is the same always, you can just go ahead with that.
((IsPageReloaded)clazz.newInstance()).JavascriptWorking();
Of course you can return a more complex datastructure also from the JS where you specify the method name also, but using reflection is really offtopic here.
Take a look at EventFiringWebdriver. This is a useful class that makes use of WebDriverEventListener to create custom Webdriver wrappers, with hooks on many events, allowing you to execute custom code before/after clicking, before/after pageload... and beside some others more importantly before/after executing javascript in the webdriver. You could leverage this to always call the same code around javascript execution - just create your own WebDriverEventListener.
You can find more info on the js executor here, and on WebDriverEventListener here.

jQuery variable name appended with a large number

I often see in my code I am loading from my company's media central that jQuery is not available in the console normally. (No $ and jQuery)
But sometimes, to those elements to which jQuery is attached, it has a long number with it.
jQuery18306575689211022109_1378907534666
What is the purpose of doing this? Security?
Also, jQuery is sometimes available directly in the console, but only with the above numbers.
I am therefore unable to debug my apps in console, where I need to query using jQuery.
However, in the JavaScript code, jQuery is perfectly being used as $ and jQuery. So I apply a break-point and export as window.jQuery = jQuery.
Is this a proper way to debug the app, when jQuery is obfuscated?
UPDATE:
For eg., check this URL the app is calling. It seems that the URL knows what is the number appended to jQuery. How do I come to know of the same number while debugging? Any lights on what is going on?
It's a callback id automatically generated by jQuery. See the documentation for jsonpCallback.
It is preferable to let jQuery generate a unique name as it'll make it easier to manage the requests and provide callbacks and error handling.
It seems that you are confusing two different variables. You can make a quick test on this website : http://www.jquery4u.com/function-demos/jsonp/#demo. Click "run demo", open Chrome's console, type "jQuery" in order to retrieve the callback's name, then perform this simple comparison :
jQuery16409391013463027775_1379048051365 === jQuery // false
That said, the fact that the variables named "$" and "jQuery" are not available in your case may be due to a specific implementation. One possibility could be the use of jQuery.noConflict() which allows either to customize the name used as a reference to jQuery, or to completely remove all references to jQuery from the global scope (window), so there is no way to access it in the console.

How do I get the path of the currently running script with Javascript?

We have an IE extension implemented as a Browser Helper Object (BHO). We have a utility function written in C++ that we add to the window object of the page so that other scripts in the page can use it to load local script files dynamically. In order to resolve relative paths to these local script files, however, we need to determine the path of the JavaScript file that calls our function:
myfunc() written in C++ and exposed to the page's JavaScript
file:///path/to/some/javascript.js
(additional stack frames)
From the top frame I want to get the information that the script calling myfunc() is located in file:///path/to/some/javascript.js.
I first expected that we could simply use the IActiveScriptDebug interface to get a stacktrace from our utility function. However, it appears to be impossible to get the IActiveScript interface from an IWebBrowser2 interface or associated document (see Full callstack for multiple frames JS on IE8).
The only thing I can think of is to register our own script debugger implementation and have myfunc() break into the debugger. However, I'm skeptical that this will work without prompting the user about whether they want to break into the debugger.
Before doing more thorough tests of this approach, I wanted to check whether anyone has definitive information about whether this is likely to work and/or can suggest an alternative approach that will enable a function written in C++ to get a stack trace from the scripting engine that invoked it.
Each script you load may have an id and each method of the script calling myfunc() may pass this id to myfunc(). This means that first you have to modify myfunct() and finally alter your scripts and calls.
This answer describes how I solved the actual issue I described in the original question. The question description isn't great since I was making assumptions about how to solve the problem that actually turned out to be unfounded. What I was really trying to do is determine the path of the currently running script. I've changed the title of the question to more accurately reflect this.
This is actually fairly easy to achieve since scripts are executed in an HTML document as they are loaded. So if I am currently executing some JavaScript that is loaded by a script tag, that script tag will always be the last script tag in the document (since the rest of the document hasn't loaded yet). To solve this problem, it is therefore enough just to get the URL of the src attribute of the last script tag and resolve any relative paths based on that.
Of course this doesn't work for script embedded directly in the HTML page, but that is bad practice anyway (IMO) so this doesn't seem like a very important limitation.

Using Selenium to Test jQuery element data()?

Is it possible to use selenium to test whether a jQuery data() is set on an element?
In my app, the user enters information about several orders. Each order gets appended to an overview table so they can see their progress as they're going. In addition to the visible order information, we store some additional information that we need about each order using an array stored in jquery.data(), like this:
$('#table').data('orders').push(neworderdata)
I'd like to write a selenium test to assert that when the user presses 'Add order', my additional data gets added to $('#table').data('orders').
I think I need something like:
Command: assertEval
Target: $('#table').data('order')[1].cust_no
Value: 99999
But I think the issue I'm having is that Selenium IDE doesn't know about the jQuery namespace, and functions, so it doesn't know how to find the table. But even if I used getElementbyID('table'), how do I get selenium to know about the data()?
Are you sure that Selenium IDE is having a problem with $? I was able to access it from Selenium IDE. Perhaps something else is broken in you jQuery expression? Can you first try "assertEval $ 0" etc. to see if the IDE can evaluate $ alone?
I find that selenium will only see the jquery function if you access it as:
window.$(...)
not as
$(...)
Perhaps that's (part of) the problem?

Categories

Resources