Async testing with vows using the http.get library in Node.js
Asked Answered
D

2

3

I'm having a doozie of a time trying to get a basic http test to work with vows.

I think I've followed the async example from vows http://vowsjs.org/#-writing-asynchronous-tests and substitued the appropriate calls, but I must be missing something.

The test code looks like this:

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

vows.describe("homepage").addBatch({
  "Get the home page": {
    topic: function() {
      http.get({'host': "127.0.0.1", 'port': 5000, 'path': '/'}, this.callback);
    },
    'should respond with 200 OK': function(res) {
      assert.equal(res.statusCode, 200);
    }
  }
}).export(module);

I get the following error when I try to run the test for this:

/Users/<home_folder>/node_modules/vows/lib/vows.js:80
rrored', { type: 'promise', error: err.stack || err.message || JSON.stringify(
                                                                    ^
TypeError: Converting circular structure to JSON
    at Object.stringify (native)
    at EventEmitter.<anonymous> (/Users/<home_folder>/node_modules/vows/lib/vows.js:80:90)
    at EventEmitter.emit (events.js:64:17)
    at /Users/<home_folder>/node_modules/vows/lib/vows/context.js:31:52
    at ClientRequest.<anonymous> (/Users/<home_folder>/node_modules/vows/lib/vows/context.js:46:29)
    at ClientRequest.g (events.js:143:14)
    at ClientRequest.emit (events.js:64:17)
    at HTTPParser.onIncoming (http.js:1349:9)
    at HTTPParser.onHeadersComplete (http.js:108:31)
    at Socket.ondata (http.js:1226:22)

I can get a simple http example to work on it's own. I can get the vows example to work on it's own but I can't combine them for whatever reason. I'd really appreciate some help here. I've been trying to get this to work for a while now (including much googling).

UPDATE:

Apparently adding an error argument to the call back solves this problem, thanks to help from Alexis Sellier (creator of vows).

But I have no idea why. When writing out the http lib example on it's own no error argument is required. I can't find any documentation in vows to indicate why it's needed so I'm at a bit of a loss.

My new question is why is the error argument required when using the http lib in vows?

Deemphasize answered 10/6, 2011 at 20:51 Comment(0)
D
4

After checking vow's source code, I think I know why. Vows always ensure that when you call this.callback, the resulting receiver function's first argument is always an error object. Vows interpret the callbacks by these rules:

  1. If the first argument of your originating callback is a boolean, use that to determine whether or not to append an error object to the receiving callback (e.g. path.exists(boolean) will emit callback(error, exists) instead)

  2. If the first argument is an object, assume it's an error object and use that to determine whether to add the originating callback to the "error" or "success" list. The reason this list exists is to support promise based tests I guess?

While I can't confirm the above is correct, my experience is that vows' async style is made to support node-styled callbacks (e.g. err as the first arg), and 3rd party npm modules that don't conform to this standard will be hard to test.

Please don't take my answer as gospel, as this is my own experience. Another gotcha is when you have async operations inside the function that you want to test - unless you provide a callback, vows won't be able to handle it properly.

Personally, I think vows still make it hard to test async code. I wish it had some waitFor() or until() flow control functions though.

My suggestion? When dealing with async code, use Step. Don't let vows control your flow.

Disclamation answered 16/6, 2011 at 8:26 Comment(1)
The interesting thing is I'm using the node.js built in http lib, I guess they've changed the error first convention, or at least allow for a separate error handler function using the .on() convention.Deemphasize
I
1

It is actually missing in the documentations which is still a bit short. But you can get a glimpse of it here in this page :

'when peeled *asynchronously*': {
        topic: function (banana) {
            banana.peel(this.callback);
        },
        'results in a `PeeledBanana`': function (err, result) {
            assert.instanceOf (result, PeeledBanana);
        }
    }

As it was said by Morten Siebuhr and Ruben Tan, this is how vows works and that is why it works like that.

Incompletion answered 10/8, 2011 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.