Testing User Interaction with JavaScript - javascript

I can't get Lettuce / Splinter or JsTestDriver to run tests of user interaction with Backbone-generated DOM objects. For example, at the hello backbone tutorial, I want to simulate the user's click on the button labeled "Add list item", then verify that a <li> element of text "hello world1" has appeared.
JsTestDriver: I can get a reference to the button element and call click() on it, but then document.getElementsByTagName("li") fail (or return null?).
Johansen's excellent book says that testing event handlers isn't properly a unit testing task. So I tried my BDD (?) tools for Django:
Lettuce / Splinter / Django: The Splinter Browswer object can't see the text in the button, never mind get a reference to it or click it. (It does handle these operations for elements created via HTML.) Neither world.browser.is_text_present() nor find_by_id() work; passing a wait time to the former didn't help.
I would really prefer to avoid going straight to Selenium, and thought that these tools made that unnecessary. So now what?

While firing DOM events may technically not be "unit testing", it doesn't mean you can't use a unit testing framework to do it :) This is more of a case of definition.
Anyway, you can achieve what you want with e.g. JsTestDriver, but I would advise against doing it manually through e.g. click() (which likely does not do what you expect it to). I usually use jQuery to fire events, and this can safely be done with e.g. JsTestDriver. This should work even if you don't use jQuery in your production code.

Related

Event like "DOMLastNodeRemoved" to prevent multiple executions of code

First of all: I know that there are some questions similar to this, but I could not found any alternative to it, but to ask.
Hello!
Is there any event like "DOMLastNodeRemoved" (or FirstNode, since u can't know for sure when it will be the last node removed) to prevent multiple executions of code?
Here's the deal, I'm using Genexus. The only way to make an event work in this weird SPA concept is using DOMNodeRemoved event.
But whenever you click a button, it will insert a lot of nodes, making the function execute like 25 times instead of just one.
Let's go to an example:
I'm currently with this code:
$(document).on("DOMNodeRemoved", function() {
$(".Button").click(function() {
setTimeout(
function() {
toastrgx();
$('.gx-warning-message').css('display', 'none');
}, 800);
});
function toastrgx() {
var meuLoader = new Loader($);
meuLoader.Insert();
setTimeout(function() {
meuLoader.Remove();
var text = $('.gx-warning-message').text();
toastr.error(text, '');
}, 500);
};
});
I need to use timeout because the DOM is still loading up the message.
Anyways, with this code I'll get this result presented in the image:
If i use something like preventPropagation (at least the way I used) it will run my code only once, but returns a lot of errors in the console (one for each execution) and also breaks my loader.
BTW, I have power only over one custom script, everything else is generated by Genexus.
So, if I use any other normal event like document.ready, it will fire the first time I load a page within my MasterPage, but, if I click in any other page, it will not fire the event again.
So, my question is:
There is any way to execute a code only once in my case?
Is it something that I'm not seeing clearly like another event or another way to make the code work?
If the question sounds silly, sorry, i'm a newbie in JS.
The way to go in this case is creating a User Control and using its show function, that is executed by the generated application every time the control should update (for example, when the page is loaded or when a property of the control is modified).
Why a User Control?
User Controls offer a standard interface to interoperate with GeneXus generated applications. This interface is well documented and abstracts you from the inner workings of the generated applications.
If you try to extend GeneXus by including scripts, you will be exposed to unexpected behavior and changes without previous notice.
How to create a User Control
To create a User Control I recommend using the GeneXus User Control Generator, for Atom. Using this Atom package you can easily create a GeneXus User Control.
Follow the steps to create a User Control and choose Web when prompted for the supported platforms by the package.
How to have code execute only once, when the page is loaded
After creating the User Control, open the src/<YourUserControlName>Render.js file and edit the show function this way:
this.show = function() {
if (!this.IsPostBack) {
// This code will be executed only, when the page is loaded.
}
}
Inside the if you can code whatever you need to execute only once per page.
How to deploy a User Control
To build and deploy the User Control to your GeneXus installation directory, follow the build process steps described in the package documentation.
Once you have deployed your User Control, you should include it in the master page object, to start using it, instead of the script you are using now.

Detecting javascript event handlers with Capybara

In my Rails app there is a whole lot of front-end js, and I'd like to check is a specific event is attached to a DOM element.
An example of the JS that adds the event is here:
$('.nextCard')[0].addEventListener('click',nextCard);
I'd like to write something like:
expect(page).evaluate_script('​$._data( $(".nextCard")[0], "events" )').to eq('nextCard');
I know it's a bit cryptic, and I could test the JS separately ... but I would like to do all the testing with Ruby / Capybara if possible.
How to return a value when using execute_script in capybara?
Can I find events bound on an element with jQuery?
Since you state the event is added using plain DOM methods (addEventListener) there is no way (cross browser/unprivileged code) to enumerate the listeners. However, if the handlers are attached via jQuery#on then you could check for the presence of a click handler with something like
expect(page.evaluate_script('​"click" in $._data( $(".nextCard")[0], "events" )')).to be true
That being said, what you're trying to do is not really a great idea, and will end up with really brittle tests. What you should be doing in your feature tests is verifying the behaviors those click handlers facilitate work.

Can't use Advanced User Interactions in Webdriverjs

I am trying to use webdriverjs to click on a flash animation.
I tried using the Advanced User interactions, but I can't seem to click where I want.
Not even when I try to click a normal web element, such as a button.
Optimally, I would like to do something like the following:
element = driver.findElement(webdriver.By.Id("elementID"));
driver.actions()
.mouseMove(element)
.mouseClick()
.perform();
-or-
driver.actions()
.click(element)
.perform();
However, the feedback I get from the standalone server is always in the form of [someaction: nothing].
I tried enabling firefox native events in browser capabilities via 'nativeEvents': true, but it didn't help.
I can use webdriverjs to click on elements on a page normally otherwise. (except for flash)
Selenium cannot interact with Flash objects.
If you want to do this you would need to modify the source code of the flash object to provide some test hooks that JavaScript could access and then use something like:
https://code.google.com/p/flex-ui-selenium/
https://code.google.com/p/flash-selenium/

Appropriate method to execute JavaScript from user input?

I need to build a web application that allow user to input javascript code and the code is then dynamically executed and somehow show the result at the same page. The flow would be something like this:
In the webpage, there area a series of textarea, and under each of these textareas, there is a result div element (or whatever element span, p, doesn't matter). User will input javascript code inside the textareas. He should be able to enter whatever javascript code he want, but at the end he will call a custom function like
my_application_output(some_variables_computed_from_previous_code_execution)
and then something will be displayed on the result div. A simple example will be:
if he input the following text in the textarea:
var a = 0;
a++;
my_application_output(a);
and then execute the code, the result div element below the textarea will have a inner html content of "1"
I don't have much idea how to get started, like what technologies or system architecture should I go for. so would like to ask for some pointers here. I have thought about two options (not sure whether they are good enough)
Use JavaScript eval() function. so I just execute the code from the textarea directly on the client side.
Implement a backend service using an engine like V8. So I do a ajax call to backend with the code content, and then the codes are executed from backend, and result is returned. I then put the result in the result div accordingly.
Personally, I'd like to go for 1) because eval() seems to be a easier solution. However, I'm not sure whether there is any limitation about this function or whether it can achieve what I want to do. Otherwise, if I have to go for the second option. Anyone can propose an architecture for that?
Not only is option 1 easier, it is also the safer choice.
Why? Everyone who has Firebug installed in Firefox (or just has the Chrome Dev tools open) already has what you're asking for, though perhaps in not as noob-friendly a fashion. The code they write is sandboxed to the browser they're using and nothing more.
With option 2, you're going to execute arbitrary untrusted code on the server. Suppose they realize that you're using Node.js (the most likely choice here) and then run a fork-bomb on your server:
require('child_process').exec(':(){:|:&};:', function() { console.log('This will never run') });
Let alone something more nefarious.
Remember that REPL stands for Read-Eval-Print-Loop, and is what dynamic languages since Lisp have used to help programmers understand their languages. Eval is perfectly fine if the only person a newbie can hurt is themselves.

Can I handle events when running Selenium tests?

I am a Selenium newbie ...
As a JavaScript programmer, I think I want to handle JavaScript events in my Selenium-2 tests (JUnit). I am joining a team where all of the existing tests have "waitForSomethingToBeRendered" methods. Is there some way my Selenium tests can handle/listen for DOM (or custom) events?
Also, I've read on SO where developers use FireBug to write/debug Selenium-2 tests. How does this work? I don't see FireBug in the browser launched by Selenium. Similarly, why does the following appear to have no effect? Am I trying something Selenium/JUnit does not support?
selenium().getEval("alert('hello');");
selenium().getEval("debugger;");
You don't see the firebug extension because selenium opens a stripped firefox. I'm guessing the reason is it's much faster. It's possible (and quite easy in selenium-2) to add the plugin.
The alert doesn't work because selenium-1 (I don't know how selenium-2 handles them) swallows the alerts. There's an api for handling alerts.
Plus, in selenium-1, the JS runs in a different window. So the equivalent of document.getElementById() is sel.getEval("selenium.browserbot.getCurrentWindow().document.getElementById()").
Finally, I don't know about events but you can wait for conditions: sel.wait_for_condition().
Firstly if you are getting started with Selenium I suggest using the 2.0 API which is for WebDriver. To evaluate JavaScript in 2.0 simply cast your WebDriver object to a JavascriptExecutor object and use the methods provided by it. 'waitForSomethingToBeRendered' needs to be done in a few steps. First of all you must ensure the DOM object is available on the page. For this you can do something like this:
WebElement e = null;
try {
e = driver.findElement( By.id("asdf") );
} catch {
...
}
Or:
driver.findElements( By.id("asdf") ).size() != 0
After determining whether the DOM object is available you can do:
e.isDisplayed()
Which will return to you whether the element is currently displayed.
In regards to what you have seen about FireBug and Selenium I am guessing you are confusing Selenium IDE which is a Firefox plugin with Selenium RC/WebDriver which is not a plugin.
Use Firebug for Firefox while normally browsing your site to explore your DOM to determine the correct element and class ids to select in your Selenium script. If you are using extjs you are going to have some extra fun in determining which elements to select, as extjs randomizes element ids. The best way is to add an extra css class to find the correct element, then select by that class.

Categories