javascript - Have useful "Red" and "Green" tests for a View Model with throttled observables -
with of another question , relevant qunit documentation can create unit tests deal async nature of throttled knockoutjs observables.
however, haven't yet found elegant way have both red , green tests behave nicely in both test runners use:
- the qunit browser based test runner
- the visual studio test runner (combined chutzpah run javascript tests)
suppose following view model:
var person = function(firstname, surname) { var self = this; self.firstname = ko.observable(firstname); self.surname = ko.observable(surname); self.fullname = ko.computed({ write: function(val) { var parts = val.split(" "); self.firstname(parts[0]); self.surname(parts[1]); }, read: function() { return self.firstname() + " " + self.surname(); } }).extend({throttle: 20}); };
and suppose these 2 basic tests:
test("can read full name", function(){ var john = new person("john", "doe"); strictequal(john.fullname(), "john doe"); }); test("can write full name", function(){ var person = new person(); person.fullname("john doe"); strictequal(person.firstname(), "john"); strictequal(person.surname(), "doe"); });
the latter will fail. makes sense, because asserts run instantly, whereas actual update fullname
call runs later: delayed 20 ms throttle
. without throttle things succeed.
no problem, linked question learned can use async test , use manual subscription make things green again:
asynctest("can write full name", function(){ var person = new person(); expect(2); person.surname.subscribe(function(val) { start(); strictequal(person.firstname(), "john"); strictequal(person.surname(), "doe"); }); person.fullname("john doe"); });
now, suppose break view model this:
// self.surname(parts[1]); // "bug" introduced demonstrate problem
then test runner hang. can "fix" issue resuming test after -say- 2 seconds no matter ending test this:
// after 2 secs assume test failed settimeout(function() { start(); }, 2000);
this works in browser based test runner bugged code, has error on correct code, console:
pushfailure() assertion outside test context, ... @ qunit.start
makes sense, because start()
called twice. first intuition check in settimeout
callback see "trancount" (i.e. ask qunit if need start or not), qunit has no support (probably reason :d).
anyways, sum possible situations:
- green because okay.
- red because subscription never fired.
- red because assertion failed.
how structure test situations accounted , both test runners react nicely?
found @ least 1 solution problem while writing question. posting question along answer (a) in case may others and/or (b) other folks may have better solutions this.
bottom line clear settimeout
return value subscription fires:
asynctest("can write full name", function(){ var person = new person(); // after 2 secs assume test failed var timeout = settimeout(function() { start(); }, 2000); expect(2); person.surname.subscribe(function(val) { window.cleartimeout(timeout); start(); strictequal(person.firstname(), "john"); strictequal(person.surname(), "doe"); }); person.fullname("john doe"); });
this works scenarios:
- green if well.
- red if subscription never fires.
- red if code has bug.
both red cases have nice assertion failure.
only downside solution it's bit verbose, need 4 lines of testing-plumbing. (perhaps else has answer utilizing feature of qunit purpose?)
also, 1 other downside: if increase throttle above timeout test first goes red qunit will crash bit later because start()
called once more.
Comments
Post a Comment