I am trying to test some of my javascript with Jasmine.
I am a newbie when it comes to Jasmine and my knowledge about Javascript is at best basic. What I want to do is to make sure the form is submitted. I can't figure out how the syntax for the tests should look like. I guess I need to use spyOn, but I'm not quite sure how. I would love it if someone could point me in the right direction.
function submitform(array) {
var token = array[0].replace("access_token=", "");
if ((token !== "")) {
$('input[name=Token]').val(token);
var frm = document.getElementById("tokenform");
frm.submit();
}
}
To test that frm.submit() was called you have to mock it. There are two ways to to it. The first way would work without code changes by spying on document.getElementById, this will work in your example as you only use it once, it will be harder if use document.getElementById more often.
var submit;
beforeEach(){
// when your code calls document.getElementById it return an object
// with just one property where you can spy on that it was called
submit = jasmine.createSpy();
spyOn(document 'getElementById').andReturn({submit:submit})
}
it ("should submit", function(){
submitform([somedata]);
expect(submit).toHaveBeenCalled();
})
The better way is to rewrite your code for better testability. So instead of getting the form by calling a DOM function, inject the form into your function as an argument. Now you can just pass the mock into your function instead of mocking document.getElementById. This pattern is also known as Dependency Injection
function submitform(array, frm) {
var token = array[0].replace("access_token=", "");
if ((token !== "")) {
$('input[name=Token]').val(token);
frm.submit();
}
}
it ("should submit", function(){
var submit = jasmine.createSpy();
var form = {submit: submit}
submitform([somedata],form);
expect(submit).toHaveBeenCalled();
})
Related
I was working on Co-drops Minimal Form Interface. I couldn't understand this code snippet in stepsForm.js. (Line 50)
stepsForm.prototype.options = {
onSubmit : function() { return true; }
};
I am new to JS, and wouldn't mind an explanation of the entire code in stepsForm if anyone has the time to do so. But, for the time being, an explanation for the above can do wonders for me. I know what a prototype is, but the onSubmit part is going over my head. I read on another question that this is to prevent refresh, but I feel that is wrong.
The library exposes options property that you may/can use to pass your own overriding values.This one in particular, exposes onSubmit.
For any html form an onSubmit is called when the submit action is invoked by another function or by click.
In the library the default onSubmit is returning true, meaning just execute the action. This can be overriden with you custom function like this...
<script>
var FORM_ELEMENT = document.getElementById( 'myForm' )
new stepsForm(FORM_ELEMENT, {
onSubmit :
function (FORM_ELEMENT) {
alert('You are about to submit the form ');
//manipulate your form or do any preprocess work...
return true;
});
</script>
Within the library the _submit (line 196 stepForm.js) is called which inturn calls the onSubmit. This time, instead of the default, it will execute the one we added above.
stepsForm.prototype._submit = function() {
this.options.onSubmit(this.el);
}
Hope that helps.
I've been rewriting various bits of code I've 'inherited' and come across something I don't understand. Both jslint and jshint think the below function is a constructor, and I have no idea why.
function GEReqsDone(failed) {
if (!failed) {
alert('Thank you for your submission! The page will now be reloaded.');
document.location.replace(mwConfig.wgScript + '?title=' + encodeURIComponent(mwConfig.wgPageName) + '&action=purge');
} else {
alert('An error occurred while submitting the edit.');
button.disabled = false;
button.innerHTML = 'Update price';
}
}
This is a callback from query using $.ajax() that queries the mediawiki API to automatically edit to update a price on a page. If the edit succeeds failed is not defined and the page reloads. If it fails, failed is set to true and it resets the button used to trigger the update.
button is simply a button element, the wg* variables are part of the mediaWiki object here used to access the pagename and url prefix (usually /index.php).
Does anyone know why jshint and jslint seem to think this function should be new GEReqsDone() rather than GEReqsDone()?
Constructors are the only functions in JavaScript that should start with a capital letter. JSLint/JSHint will see that it starts with an uppercase G and assume it is a constructor.
This is the only convention we have to make sure people know that the function should be used as a constructor. Some people write defensively to avoid people missing the new keyword:
var SomeConstructor = function () {
if (!(this instanceof SomeConstructor))
return new SomeConstructor();
}
Im looking to inject a variable into a page before a method is run. The situation is as follow
CUSTOM JS CAN GO HERE
my.var = 'cake';
my.function();
I dont have access to be able to modify the page directly, however there is a content area at the top of the page I can add some JS if i need to. Basically i need to overwrite the my.var variable with something else before my.function() is run. Is there a way to do this? (the site is running jQuery 1.4.2.
Thanks
Dan
Basically i need to overwrite the my.var variable with something else before my.function() is run. Is there a way to do this?
var oldfunction = my.function;
my.function = function () {
my.var = "whatever you want";
oldfunction.apply(this, arguments);
}
This is, of course, if my or my.function isn't overwritten by the code you can't modify directly before the call to my.function (as my.var is).
For example, in the following scenario:
///your code goes here
///code you cannot modify below
var my = {};
my.function = something;
my.var = 'cake';
my.function();
what you want is impossible (unless you're able to redefine something or something in it in the same way).
Basically, in this case the only thing you could do is to write (let's assume something is function () { alert(my.var) })
var oldalert = window.alert;
window.alert = function (message) {
oldalert(message === 'cake' ? 'whatever you want' : message);
}
Well, you've got an idea.
Injecting some code in between my.var = 'cake'; and my.function(); is, from the other side, imposible. Roughly speaking, you can choose between two options, whether your code will be executed before my.var = 'cake'; or after my.function();. Executing your code aftre my.var = 'cake'; but before my.function(); is impossible (if we're speaking of a production environment; of course you could do anything by hands using the debugger, if you need to modify my.var for a debugging purpose).
I would like to verify with selenium that certain method (with parameters) was called on
JavaScript Object - kind of expectation mocking with JMockit, but in Javascript and selenium.
Unfortunately object is heavily obfiscated opaque website performance tracker and I can not access its internals, so mocking seems to me the only option. Or do I miss something obvious?
Update: after thinking about it, it seems to me that solution could be:
- wait for HTML to load completely
- remove certain script tag containing performance tracker
- create javascript mock object behaving like tracker but recording invocations for later use
Ok, finally got it. Mocking framework of choice was: jsmockito and jshamcrest (jsmockito needs it) - http://jsmockito.org/
And it was peace of cake.
Spy on existing object:
<tr>
<td>storeEval</td>
<td>window.wwa = JsMockito.spy(window.wwa$); </td>
<td>mockedWipe</td>
... do whatever necessary
and verify it:
<tr>
<td>storeEval</td>
<td>JsMockito.verify(window.wwa$).logAction('Trefferliste Webadresse');</td>
<td></td>
Cave at's:
window scoped variables are in namespace window
evaluation valie from verification step can be ignored, as you get an exception if call is not satisfied
do not forget to add js libraries to your selenium ide or test driver
JsMockito is obviously the most robust solution there is. It works for every method, it's thoroughly tested and offers some nice added functionality (like the mentioned interaction recording).
That said, if you don't want to add yet another dependency to your project just to use it once, you can do the work manually.
window.origWwa = window.wwa;
window.wwa = function() {
if (arguments[0] === 'Trefferliste Webadresse') {
window.wwaFired = true;
}
window.origWwa.apply(this, arguments);
};
... do your work ...
if (!window.wwaFired) {
// do something, either throw an error or console.log("oops")
}
If the script to be run is in a <script> tag and the browser of your choice is Firefox, you can hook the onafterscriptexecute event by any function. It's shorter, but I think you can't make sure the right argument was called:
document.getElementById('script').onafterscriptexecute = function() {
window.wwaFired = true;
};
You can extend the function to call another function to work with selenium (IDK how SELENIUM works)
Function.prototype.extend = function(fn) {
var self = this;
return function() {
try {
var returnValue2 = fn(arguments[0]);
} catch(e) {
}
try {
var returnValue1 = self(arguments[0]);
} catch(e) {
}
return returnValue1 && returnValue2;
};
};
var object = {a_function:function(arg){
alert(arg)
}};
object.a_function('simple'); // alerts "simple"
object.a_function = object.a_function.extend(function(arg){
alert('prealert for '+arg)
});
object.a_function('simple'); // alerts "prealert for simple" and then alerts "simple"
I want to use an initialization function that will be called after a user visits a part of the application, but after that first visit I don't want to initialize anymore. A simple way to do this is using a flag and an if-statement, but there is a nicer solution to this problem:
in other languages I changed the body of the init function so that after the call of this method.
Can this be done in Javascript too? I wrote something like this, but eclipse says that it is an illegal assignment:
function initEdit(){
...
this = function() {};
}
Yes, you can, but this doesn't refer to the function, so you have to specify it by name:
function initEdit(){
...
initEdit = function() {};
}
Another alternative, that might be easier to follow, is to just use a variable:
var initialised = false;
function initEdit(){
if (!initialised) {
initialised = true;
...
}
}