After a loooot of testing... I stumbled upon some interesting behavior that I don't understand.
Code:
function someFunction() {
... // whatever this is stubbed
}
// below is called ("mounted") by finalDOM.mountUserActions()
$("#button").click(function() {
savedElement = $("#saved_element")
console.log("BEFPRE THEN in event listener ==========")
console.log("found saved_element? = " + savedElement.length)
console.log("found unsaved_element? = " + $("#unsaved_element").length)
someFunction().then(function(result){
console.log("INSIDE THEN in event listener ==========")
savedElement.val(result)
$("#unsaved_element").val(result)
console.log("ensure result is found = " + result)
console.log("found saved_element? = " + savedElement.length)
console.log("found unsaved_element? = " + $("#unsaved_element").length)
})
})
Test code:
fdescribe("on click of button", function() {
beforeEach(function(){
response = Promise.resolve("test")
spyOn(window, "someFunction").and.returnValue(response)
savedElement = affix("#saved_element")
affix("#unsaved_element")
affix("#button")
finalDOM.mountUserActions();
$("#button").click()
})
it("should change value of saved_element", function() {
response.then(function() {
console.log("INSIDE SPEC EXPECTATION ==========")
console.log("value of saved_element = " + savedElement.val())
console.log("value of unsaved_element = " + $("#unsaved_element").val())
expect(savedElement.val()).toEqual("test") // PASS
expect($("#unsaved_element").val()).toEqual("test") // FAIL
})
})
})
Console output:
BEFPRE THEN in event listener ==========
found saved_element? = 1
found unsaved_element? = 1
INSIDE THEN in event listener ==========
ensure result is found = test
found saved_element? = 1
found unsaved_element? = 0
INSIDE SPEC EXPECTATION ==========
value of saved_element = test
value of unsaved_element = undefined
The fact that the length of both elements are 1 in BEFORE THEN in event listener
proves that the affix worked, both elements are on the page, so then why is only the saved element found once INSIDE THEN in event listener
?
I don't think I've ever encountered this... is this a Javascript gotcha or a Jasmine one? Would love to learn more about it to avoid this in the future... have spent a lot of time scratching my head on it.
$("#unsaved_element").val(result)
? Are you even returning a value from someFunction() that can be passed to the callback? it's probably setting it to null.#saved_element
isn't really found inside thethen
callback, you're storing a reference to it in a variable. When you have this reference you'll have access to it even if it has been removed from the DOM. 2: Your test relies on a promise being resolved, but you haven't written the test accommodate for the fact that it's async. This means that some "post-test" code might run before yourthen
callback runs. Maybe this is what happens and this post-test code removes the#unsaved_element
?#unsaved_element
isn't found. The test has aresponse.then
to accommodate the fact that it's async. And if you look at the console output, you'll see that the order is correct, i.e., the entire event listener is called BEFORE the expectations are checked. If theresponse.then
were not there, then the first expectation would also fail and the console log would show in this order: 1)BEFORE THEN
, 2)INSIDE SPEC
, 3)INSIDE THEN
console.log
to check the value ofresult
and it in fact istest
, thespy.returnValue
is working appropriatelythen
block is executed. In other words, yourthen
block is still executed, but Jasmine has already moved on. You tell Jasmine that your test is async by using thedone
function and then tell Jasmine the test is done by invoking it.