cloudhead/vows — Issue #143: Topics should be passed down to async contexts
Author: kloshih
Created: 2011-10-17 18:59:58+00:00
State: open

To assert a condition in a sub context that's checked asynchronously, it's sometimes useful to grab the stack of topics. It looks like you can usually use `this.context.topics` to get topics in most cases. But that isn't available if you simply use `this.callback`. Here's an example:

```javascript
/*
* async-topics-test.js
*/

var vows = require('vows'),
assert = require('assert');

vows.describe('Async vows and subcontexts').addBatch({

'Using vows with topics and async subcontexts': {
topic: function() {
return 'some topic!';
},
'when callback is wrapped in a function': {
topic: function(some_topic) {
var callback = this.callback;
setTimeout(function() { callback(); }, 0);
},
'topic is accessible via context': function() {
assert.ok(this.context);
assert.ok(this.context.topics);
assert.equal(this.context.topics[0], 'some topic!');
},
},
'when callback is just used directly': {
topic: function(some_topic) {
setTimeout(this.callback, 0);
},
'topic is accessible via context': function() {
assert.ok(this.context);
assert.ok(this.context.topics);
assert.equal(this.context.topics[0], 'some topic!');
},
},
},

}).export(module);
```

This produces:

```
♢ Async vows and subcontexts

Using vows with topics and async subcontexts when callback is wrapped in a function
✓ topic is accessible via context
Using vows with topics and async subcontexts when callback is just used directly
✗ topic is accessible via context
» expected expression to evaluate to true, but was undefined // async-topics-test.js:30

✗ Broken » 1 honored ∙ 1 broken (0.004s)
```

The difference between the success and failure is whether it uses `function() { callback(); }` or `this.callback`. When you use just `this.callback`, `this` is an EventEmitter and has no `context.topics` property, which is sorely missed. As a workaround, I'm having to do something like this:

```javascript
'when forcing an argument into the callback': {
topic: function(some_topic) {
var callback = this.callback;
setTimeout(function() {
callback(null, some_topic);
}, 0);
},
'topic is given as an argument': function(some_topic) {
assert.equal(some_topic, 'some topic!');
},
},
```

Not so much fun.

(BTW, thanks for the excellent bdd framework.)