2

I'm writing a node wrapper to interact with an external api and am having a difficult time testing the asynchronous createJob method. Below is the test case code:

api_key = "test_0dc8d51e0acffcb1880e0f19c79b2f5b0cc"

lob     = require('../src/lob')(api_key)
should  = require("should")
chai    = require("chai")

data = 
  name: "test name"
  to: "Bob"
  from: "Alice"
  object1: "foo"
  object2: "bar"

describe "Job", ->
  @timeout(50000)
  describe "create", ->
    it "should create a job with address_id", (done) ->
      lob.jobs.createJob data, (new_job) ->
        new_job.should.not.be.empty
        new_job['name'].should.equal(data['name'])
        done()

Edit

The above code resolves the issue

Anconia
  • 3,888
  • 6
  • 36
  • 65
  • duplicate http://stackoverflow.com/questions/24723374/async-function-in-mocha-before-is-alway-finished-before-it-spec – rofrol Aug 07 '15 at 07:11

2 Answers2

3

(Answer in coffeescript. If you'd like to convert coffee to js use http://coffeescript.org/, then the Try CoffeeScript tab.)

If you're testing asynch code you'll need to use the done pattern:

describe "User", ->
  describe "#save()", ->
    it "should save without error", (done) ->
      user = new User("Luna")
      user.save done

http://visionmedia.github.io/mocha/ under "Asynchronous code". Looks like createJob is returning true because the test is zipping through the code to send the post etc. and saying "yep, I sent all that stuff like you asked!".

I'd recommend Martin Fowler's article on testing asynch js code with mocha: http://martinfowler.com/articles/asyncJS.html.

I've got a chunk of code that tests retrieval of a user from the database (using sinon for stubbing). The real code connects to the db then calls the onSuccess with the user's configuration: onSuccess(config)

  describe 'Config', ->
    orgId = 'a'
    errorHandler = ((msg) -> (throw msg))
    beforeEach ->
      readConfig = sinon.stub(sdl , 'getConfig')
      readConfig.callsArgOnWithAsync(2, configSource, JSON.parse(jsonConfig))
    afterEach ->
      configSource.getConfig.restore()

... later

  configSource.getConfig('520bc323de4b6f7845543288', errorHandler, (config) ->
      config.should.not.be.null
      config.should.have.property('preferences')
      done()
  )
jcollum
  • 43,623
  • 55
  • 191
  • 321
  • I was also thinking that the `lob` variable needs to be declared globally as well as within the `beforeEach` function, similarly to how `data` is declared. I'll have to check this out after work. – Anconia Jan 20 '14 at 19:55
  • I'm not sure why it would be -- does it need to be initialized in some way before every run? – jcollum Jan 20 '14 at 19:59
  • No, I guess it doesn't - and if that's the case then `data` doesn't need to be wrapped in the beforeEach function either – Anconia Jan 20 '14 at 20:02
  • well it seems likely that you'll have a single `data` that is used across many tests, I think it's in the right place – jcollum Jan 20 '14 at 20:12
  • Also, should `done` be invoked in a callback within `createJob` or at the very end of the test? – Anconia Jan 20 '14 at 20:41
  • 1
    done is always invoked in your "success" callback. If you post to a site, put your done in the code that fires when the post is done with no error. Actually done would go in the error callback as well, but with a failure. I don't recall how to directly fail a test with mocha, sorry. – jcollum Jan 20 '14 at 21:28
  • Actually I was wrong, in your error handling code just `throw` the return message, that will cause a test failure. – jcollum Jan 20 '14 at 21:30
  • I've updated the code with the done callback; however, I'm not sure if this is correct – Anconia Jan 21 '14 at 00:24
  • I placed the insertions inside the callback with the done and the tests are now taking 2s to run, which gives me the impression the call to the api is being made; however, tests are still failing (updated both the test case and result) – Anconia Jan 21 '14 at 04:19
  • The result of the asynch call should be the first argument of the callback. I think what's happening is new_job is getting the value of `req.end()` which is `true`. My asynch test code looks like: `sdl.getCustomer orgId, 1234, errorHandler, (customer) -> customer.should.not.be.null` (sorry, formatting doesn't work well in this box). – jcollum Jan 21 '14 at 15:56
  • Also, debugging! `node-inspector --web-port=5860 & mocha --compilers coffee:coffee-script ./test/customerDataLayer-test.coffee --ui bdd --debug-brk=5860` – jcollum Jan 21 '14 at 15:57
  • Would you mind updating your answer to refactor the describe job test case? I'm having a difficult time seeing what you mean. – Anconia Jan 21 '14 at 16:24
  • I've updated it based on your example code, but won't be able to test until later today – Anconia Jan 21 '14 at 16:28
  • It's now in my favorites folder :-) – Anconia Jan 22 '14 at 01:37
3

Don't consider this like an answer to the op but a bonus for the one marked as correct.

Just to complete @jcollum answer here's the Javascript version of him code:

describe('User', function(){
    describe('#save()', function(){
        it("should save without error", function(done){
            var _user = new User("Moon");
            _user.save;
            done();
        });
    });
 });

It's pretty evident but maybe some newbies would need this addendum.

sospedra
  • 14,238
  • 3
  • 21
  • 32