Please note this is SPECIFIC to test environment using Jasmine. I am NOT having these issues in dev mode. Here’s a bare bones example I created:
Code
function mountTest() { $(document).on("click", ".test", function() { console.log(">> clicked test") }) }
Spec code
fdescribe("test click test", function() { beforeEach(function() { test_btn = affix(".test") mountTest() /******************** KEY LINE ****************/ }) describe("1st spec", function() { beforeEach(function() { console.log(">>1") test_btn.click() }) it("shoudl work", function(){ }) }) describe("2nd spec", function() { beforeEach(function() { console.log(">>2") test_btn.click() }) it("shoudl work", function(){ }) }) describe("3rd spec", function() { beforeEach(function() { console.log(">>3") test_btn.click() }) it("shoudl work", function(){ }) describe("4th spec", function() { beforeEach(function() { console.log(">>4") test_btn.click() }) it("shoudl work", function(){ }) }) }) })
As it stands, the output in console is this:
>>1 >> clicked test >>2 >> clicked test >> clicked test >>3 >> clicked test >> clicked test >> clicked test >>3 >> clicked test >> clicked test >> clicked test >> clicked test >>4 >> clicked test >> clicked test >> clicked test >> clicked test
I have discovered that the reason for the redundancy in clicks is because mountTest()
is called at the top-level beforeEach
. Further experimentation has revealed that if mountTest()
is called within one of the describe
blocks that is a spec (1, 2, 3, 4), then the redundancy is removed for ALL specs AFTER the first spec on which the mountTest()
is placed. FOR EXAMPLE
Modified spec code
fdescribe("test click test", function() { beforeEach(function() { test_btn = affix(".test") }) describe("1st spec", function() { beforeEach(function() { console.log(">>1") test_btn.click() }) it("shoudl work", function(){ }) }) describe("2nd spec", function() { beforeEach(function() { console.log(">>2") mountTest() /******************** KEY LINE ****************/ test_btn.click() }) it("shoudl work", function(){ }) }) describe("3rd spec", function() { beforeEach(function() { console.log(">>3") test_btn.click() }) it("shoudl work", function(){ }) describe("4th spec", function() { beforeEach(function() { console.log(">>4") test_btn.click() }) it("shoudl work", function(){ }) }) }) })
Console output
>>1 >>2 >> clicked test >>3 >> clicked test >>3 >> clicked test >>4 >> clicked test
The redundancy is gone. The 1st spec doesn’t trigger any clicks because the mountTest()
is not called until the 2nd spec.
Can someone explain this behavior to me? I don’t even begin to know what I’m misunderstanding here… is it the nature of the affix
or the beforeEach
or…?
Here are some of my questions in looking at this:
In the modified spec example, if
mountTest()
is only called in the 2nd specdescribe
block, why are the clicks for the 3rd/4th specs working? How didmountTest()
translate over? My only thought would be that somehow theaffix(".test")
element keeps theeventHandler
added bymountTest()
, but according tojasmine-fixture
docs (https://github.com/searls/jasmine-fixture), affix cleans up its own elements after each spec?In the original spec example, I think the explanation for why the clicks are so redundant is that
mountTest()
has mounted N times by the Nth spec, so at Nth spec, each click registers once for each mount, so you get Nth clicks. But overlapping with #1, if theaffix(".test")
element is new each time, then you’re mounting on a new object each time, so it should only trigger once, no?
FWIW, to test the affix, I did manually write a afterEach(function() { $(".test").remove() })
and add it after each it
expectation block in the original spec code, and this did NOT fix the issue at all.
Relevant gemfile:
gem 'jasmine', "2.6" gem 'jasmine-jquery-rails' # resolving to 2.0.3
Then also jasmine-fixture
is loading via a file spec > javascripts > helpers > jasmine-fixture.min.js
which is requested because in the spec > javascripts > support > jasmine.yml
file, there’s a line:
src_files: ... helpers: - 'helpers/**/*.js'
Advertisement
Answer
The problem is the listener is being attached to the document not the element that is managed by affix
. This is why the listeners are not being removed and why removing the element manually doesn’t do anything either. You would need to attach it directly to the element created. You could do:
function mountTest(el) { el.on("click", function() { console.log(">> clicked test") }) }
And call it this way:
beforeEach(function() { test_btn = affix(".test") mountTest(test_btn); })
This will attach it directly on the element and not the document
.