When testing reactivity with Jasmine some Tracker computations started behaving in a very intriguing way: Exactly half the computations are reactive, the other half is not.
What I did to test this behaviour is the following:
//In a describe block
var foo = new ReactiveVar(false);
it('should react to the changes of foo (1)', function(done) {
Tracker.autorun(function observeFoo(fooComputation) {
var fooValue = foo.get();
console.log('foo in its computation is', fooValue);
if ( fooValue === true ) {
fooComputation.stop();
done();
}
});
setTimeout(function setFoo() {
foo.set(true);
}, 100);
});
So basically:
- Initialize a reactive
foo
tofalse
. - Start tracking it, waiting for it to get to
true
so that the test is declared to bedone()
. - Use a timeout to
foo.set(true)
and thus resolve the test. - Stop this computation because it's not needed any more.
Now, let's do that very same thing with a different variable:
var foo = new ReactiveVar(false),
bar = new ReactiveVar(false);
it('should react to the changes of foo (1)', function(done) { /* ... */ });
it('should react to the changes of bar (2)', function(done) {
Tracker.autorun(function observeBar(barComputation) {
var barValue = bar.get();
console.log('bar in its computation is', barValue);
if ( barValue === true ) {
barComputation.stop();
done();
}
});
setTimeout(function setBar() {
bar.set(true);
}, 100);
});
That's where the fun begins. While this test is the very same code with a different name, and has exactly the same written logic, it fails because the computation tracking bar is never rerun.
The console.log
shows it very well:
foo in its computation is:
false
foo in its computation is:true
- reactivity kicked in!
bar in its computation is:false
[Nothing]
While it is very clear that the computation for foo
was rerun and thus its test was completed, the computation for bar
is never invalidated and thus the test fails.
However this does not stop here. If we add a third test case for a new reactive variable (say, baz
) and follow the same procedure as before (initializing it with the others, adding the test at the end in the same describe
function) then it works perfectly!
var foo = new ReactiveVar(false),
bar = new ReactiveVar(false),
baz = new ReactiveVar(false);
it('should react to the changes of foo (1)', function(done) { /* ... */ });
it('should react to the changes of bar (2)', function(done) { /* ... */ });
it('should react to the changes of baz (3)', function(done) { /* ... */ });
Here test (1)
succeeds, test (2)
fails, test (3)
succeeds.
Now if we add a fourth test, with a new cat
for example, following the same procedure... Then test (4)
will fail with the following log.
foo in its computation is
false
foo in its computation istrue
bar in its computation isfalse
bar is not rerun and fails
baz in its computation isfalse
baz in its computation istrue
cat in its computation isfalse
cat is not rerun and fails
[Nothing]
foo
and baz
have been reacted unto, not bar
and cat
.
I have done it with two others (fifth and sixth), same result: (5)
succeeds, (6)
fails.
The "odd" tests succeed, the "even" ones fail.
Full reproduction code:
describe('Tracker usage with Jasmine', function() {
var foo = new ReactiveVar(false),
bar = new ReactiveVar(false),
baz = new ReactiveVar(false),
cat = new ReactiveVar(false),
pup = new ReactiveVar(false),
elf = new ReactiveVar(false);
it('should react to the changes of foo (1)', function(done) {
Tracker.autorun(function observeFoo(fooComputation) {
var fooValue = foo.get();
console.log('foo in its computation is', fooValue);
if ( fooValue === true ) {
fooComputation.stop();
done();
}
});
setTimeout(function setFoo() {
foo.set(true);
}, 100);
});
it('should react to the changes of bar (2)', function(done) {
Tracker.autorun(function observeBar(barComputation) {
var barValue = bar.get();
console.log('bar in its computation is', barValue);
if ( barValue === true ) {
barComputation.stop();
done();
}
});
setTimeout(function setBar() {
bar.set(true);
}, 100);
});
it('should react to the changes of baz (3)', function(done) {
Tracker.autorun(function observeBaz(bazComputation) {
var bazValue = baz.get();
console.log('baz in its computation is', bazValue);
if ( bazValue === true ) {
bazComputation.stop();
done();
}
});
setTimeout(function setBaz() {
baz.set(true);
}, 100);
});
it('should react to the changes of cat (4)', function(done) {
Tracker.autorun(function observeCat(catComputation) {
var catValue = cat.get();
console.log('cat in its computation is', catValue);
if ( catValue === true ) {
catComputation.stop();
done();
}
});
setTimeout(function setCat() {
cat.set(true);
}, 100);
});
it('should react to the changes of pup (5)', function(done) {
Tracker.autorun(function observePup(pupComputation) {
var pupValue = pup.get();
console.log('pup in its computation is', pupValue);
if ( pupValue === true ) {
pupComputation.stop();
done();
}
});
setTimeout(function setPup() {
pup.set(true);
}, 100);
});
it('should react to the changes of elf (6)', function(done) {
Tracker.autorun(function observeElf(elfComputation) {
var elfValue = elf.get();
console.log('elf in its computation is', elfValue);
if ( elfValue === true ) {
elfComputation.stop();
done();
}
});
setTimeout(function setElf() {
elf.set(true);
}, 100);
});
});
Why is this happening?
How can I solve this matter while keeping all these reactive variables in the same describe
function?
I have tried to add nested describe
functions without success.
This issue magically disappears when isolating the tests in their own non-related describe
functions, please do not answer in such a way.