Mocking $.fn.find with Jasmine seems to have magic behaviour - javascript

I’m writing a method that’s a simple wrapper around calls to $.fn.modal. The method takes a selector and that selector should be passed to jQuery, so jQuery can find an element matching that selector.
Here’s what my spec looks like:
describe('The modal presenter', function() {
it('operates on the provided selector', function() {
spyOn($.fn, 'find');
myModule.presentModal('#the-modal', {});
expect($.fn.find).toHaveBeenCalledWith('#the-modal');
});
});
This is all fine. The odd behaviour is happening in my production code.
var myModule = {
presentModal: function(selector, event) {
event.preventDefault();
$(selector, document).modal('show'); // This line works
$(document).find(selector).modal('show'); // This line doesn’t work?!
// This should be fairly obvious, but I’m not running both
// of the above lines at the same time. I comment one out
// and run the method with one line at a time.
}
}
As far as I’m aware, those two lines that I’ve added comments to should be equivalent. They should both call $.fn.find with selector. The second commented line should definitely call .find, as I’ve written that explicitly.
When I run my test, I get TypeError: $(...).find(...) is undefined. How could this be?

Related

trying to attach a click event to an id that only fires once

UPDATE turns out the code is actually working see my answer below
I'm having some troubles here. I thought I found my answer in the .one method, but apparently, .one means ONLY ONCE PER PAGE PER ANYTHING EVER which isn't exactly what I was going for. Here's what my intention was:
$("#someID").one('mouseover', function() {
//do some stuff
});
$("#someOtherID").one('mouseover', function() {
//do some stuff
});
My expectation was that once that first one fired, that mouseover event would no longer fire for THAT ELEMENT.
The problem with this is that once the first one fires, the second one will not fire either. So the .one method appears to be disabling ALL mouseover events for ALL elements after that first one fires.
I did not expect this, I expected the .one to only apply to that first element. Is this just a flaw in my understanding of the .one method or am I coding wrong?
If it's just a flaw in my understanding, could someone point me in the right direction to correct my code?
Thank you in advance!
This is embarassing, I hope I don't get dinged for this and blocked again from stackoverflow (the easiest thing ever to get blocked from and the hardest to get unblocked).
First, #CertainPerformance, thanks for taking the time to look at my question. My real code didn't have the two mistakes you mentioned, I updated my post to reflect the correct syntax.
I'll be honest, my code is working now, and I have no idea why. I suspect I've been dealing with some crazy caching issues which frustrates me because I'm using inMotionHosting which has really great reviews, and I have caching disabled in cPanel.
If anything, maybe this thread will benefit somebody searching "how to make event fire only once in javascript".
You could make the callback run once like this:
// Extend the function prototype
Function.prototype.once = function() {
// Variables
var func = this, // Current function
result;
// Returns the function
return function() {
// If function is set
if(func) {
// Executes the function
result = func.apply(this, arguments);
// Unset the function, so it will not be called again
func = null;
}
// (:
return result;
};
};
// Bind the event to the function you will use as a callback
$("#someID").on('mouseover', function() {
console.log('just once');
}.once());

How to call custom method of a element in Polymer 1.0?

I'm coding a new version of a chrome extision, but got a trouble.
Here's my element code: Element code
At line 32 I'm tring to call the custom method willUpdateBackground, console tells me the method is undefined. Code below.
Polymer({
is: 'pure-newtab',
ready: function() {
console.dir(this.$.background);
this.$.background.willUpdateBackground('color', '#333');
// This line get error, 'willUpdateBackground' is undefined
}
});
The definition
Polymer({
is: 'pure-background',
ready: function () {
},
willUpdateBackground: function(type, imageOrColor) {
console.log(type);
console.dir(this);
}
});
But if I store this object, in console I can call the temp1.willUpdateBackground, it's weried.
Screenshot: http://i.stack.imgur.com/OTLgw.png
Fixed And Problem Happens Again
I move the custom method call to attached callback, elements not ready in ready function in some environment.
And after I fixed it, it happens again: in attached method, call failed again, and I move it to async call with 100ms delay, problem disappear again. It's not a solid solution, I'm still finding a way out.
this.async(function () {
this.$['background'].updateBackground('rgba(255,128,0,1)', 'url(https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png)');
}, 100);
I tried pasting your code into this jsbin and it worked just fine... (I commented your console.dir() and added a couple of console.log() of my own, but that's all I did)
http://jsbin.com/tomewigobu/1/edit?html,console,output
I would suggest you check that your polymer version is updated, that should help.

assertExists with if-else statement

I use this code:
var x = require('casper').selectXPath;
...
casper.waitForSelector(x("//a[contains(#id,'cell_13_1')]"), function() {
this.test.assertExists(x("//a[contains(#id,'cell_13_1')]"), 'Clickable');
this.click(x("//a[contains(#id,'cell_13_1')]"));
});
I am trying to use if-else with assertExists to click another element if the first is not there:
casper.waitForSelector(x("//a[contains(#id,'cell_13_1')]"), function() {
if(this.test.assertExists(x("//a[contains(#id,'cell_13_1')]")==="PASS"){
this.click(x("//a[contains(#id,'cell_11_1')]"));}
else{
this.click(x("//a[contains(#id,'cell_22_1')]"));
}
});
But that does not seem to work. How would one do it correctly?
That's exactly what casper.exists() is for. You can also explicitly pass or fail some things:
casper.waitForSelector(x("//a[contains(#id,'cell_13_1')]"), function() {
if(this.exists(x("//a[contains(#id,'cell_13_1')]")){
this.test.pass("Clickable");
this.click(x("//a[contains(#id,'cell_11_1')]"));
} else {
this.test.fail("Clickable");
//this.click(x("//a[contains(#id,'cell_22_1')]"));
}
});
This code is equivalent to your first snippet. Comment the fail() call and uncomment the last click in order to get your "intended" behavior.
Btw, it doesn't make sense to fail some assertion and still continue with the script. You have to think about what exactly you want to test and what part of your script is supposed to be navigation to the component under test.

Jquery DOM events called after events following it are executed

I am facing a very weird issue in chrome.
My code is
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
The text and the hidden class are being removed after the post action has been executed.
The code is working fine in firefox.
The only thing needed was
Server.async = true
before the server call.
Asynchronous functions fire in order of appearance but return in order of when they finish. It would be odd for those simple text and removeClass methods to return more slowly than whatever you're doing with your Server object, but I suppose it's possible. If you need the first two lines to happen before the postService, you might try jQuery's deferred.promise. Here's a fiddle demonstrating the potential, and some code to inspect:
function firstThing (){
var dfd = new jQuery.Deferred();
$('#import').text("Importing...");
$('#import img').removeClass("hidden");
dfd.resolve();
}
$.when( firstThing() ).then(
function() {
Server.postService("tests", row_datas, function(data) {
// some stuff here
});
}
)
As a side note, the logic of your code is problematic in that by setting the text of #import, whatever img had the hidden class won't be there anymore, but that might be beside the point.
Update
Noticing your response to my comment asking about your use of ajax, I would suggest you read about the async option and see how what you're doing might or might not be blocking events.
I would also recommend reading about jQuery ajax callbacks, particularly error, success, and complete (now, with jQuery 1.8+, fail, done, and always).

How can I turn this javascript into a function? Is it already a function? A few very basic questions about js structure

I am learning javascript, and am trying to adjust the following:
$('#myform').change(function() {
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
});
To be a a function with a name that I can call on different events, such as page load etc.
I don't yet fully understand each element, but I know that:
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
is the core "logic" of the function: if (condition) {then this} else {that}
and more or less understand what is happening there. Which leaves the bounding javascript (is there better terminology than that?):
$('#myform').change(function() {...});
My Questions (are the following true etc):
The dollar I think denotes that it is jQuery
The id my form obviously
pertains the script to events within that form (namespace?)
.change seems to be, a trigger that listens to ... any change taking place
within #myform? so every time a change happens within #myform this
runs? That seems inefficient
function() I don't yet understand what
an anonymous or empty function does, just defines what is contained
in {} as a function?
My goal: to be able to have something like
function myfunction()
{
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
}
and then
$(function() {myfunction});
so I can call that function on page load, but I don't wan't to loose the functionality the .change syntax is providing me (that it changes as the user interacts with the elements on the page also.
Apologies for the general and cumbersome levels of ignorance
You guessed how to define the function correctly — that is,
function myfunction()
{
if ($('#sv_I4b').attr('checked')||$('#sv_I4c').attr('checked')){
$('#sv_I5').removeClass('hidden');
} else {
$('#sv_I5').addClass('hidden');
}
}
works just fine. However, this:
$(function() {myfunction});
Should be written as:
$(myfunction); // Run on page load.
$('#myform').change(myfunction); // ...and also run it when the form changes.
However, that second line won't actually work until the page has loaded unless the form exists at the time the script runs, so you may want to change it to this:
$(function() { // On page load, run this anonymous function:
myfunction(); // Run the function now (where now, at this point, is page load).
$('#myform').change(myfunction); // ...as well as when the form changes.
});
$ is shorthand notation for jQuery, and essentially namespaces any functions to the jQuery framework.
my_form is a DOM selector. $('#my_form') wraps the matched DOM element up as a jQuery object, adding all sorts of useful methods and properties.
.change() is an event listener which, as you guessed, watches for change events on that jQuery object. It is a little inefficient - take a look .on() instead.
the most useful behaviour an anonymous function (closure) is to create private scope, something that javascript doesn't otherwise provide.

Categories

Resources