Tomas Romero
Tomas Romero

Reputation: 8698

Is it possible to lift a SailsJS app synchronously?

It would be handy for testing.

It would avoid the boilerplate of having to lift the app on every spec.

My current code:

beforeEach(function(done) {
  Sails.lift({ log: { level: 'error' } }, function(err, sails) {
    app = sails.express.app
    // beforeEach related stuff
    done()
  })
}

I want to put on my specs_global.js:

app = Sails.lift({ log: { level: 'error' } }).express.app

EDIT:

My problem to beign unable to lift Sails syncronously

The problem is that I want to instanteate Sails only once for all my specs, as it is an expensive task and I want my integration specs to run as fast as possible. Also I want to avoid the boilerplate of calling Sails lift on each of my specs files.

Upvotes: 0

Views: 674

Answers (3)

Edy
Edy

Reputation: 111

Put this snippet in your specs_global.js:

global.liftSails = function (cb) {
    // lift sails no more than once
    if (!global.app) {
        Sails.lift({ log: { level: 'error' } }, function(err, sails) {
            global.sails = sails;
            global.app = sails.express.app;
            cb();
        });
    } else {
        cb();
    }
}

Now you have sailsand app available globally.

In your tests you can write something like this:

beforeEach(function(done) {
    liftSails(function () {

        // do something with sails and app here

        done();
    })
});

Upvotes: 1

Tomas Romero
Tomas Romero

Reputation: 8698

Edy's answer solves the problem I had, but as I currently like using promises and I think they are a good fit here to avoid boilerplate, here is my solution using promises

My solution (using promises)

As I'm using promises (q module) both on my code and on my specs, I took advantage of it. What I've done:

  • load globals.js file before loading my specs
  • on globals.js declare a global variable to be a promise that Sails will lift.

    global.sails_lift_promise = liftSails()
    
    function liftSails() {
      return Q.ninvoke(Sails, 'lift', { log: { level: 'error' } })
              .then(function(_sails) {
                global.sails = _sails
                global.app = _sails.express.app
              })
    }
    
  • this sails_lift_promise promise will lift Sails only once and will be available through all specs, so we can use it:

    //on some_spec1.js
    beforeEach(function(done) {
      sails_lift_promise.then(doSomething).done(done)
    })
    //on some_spec2.js
    beforeEach(function(done) {
      sails_lift_promise.then(doAnotherThing).done(done)
    })
    

Upvotes: 1

sgress454
sgress454

Reputation: 24948

No, sails.load and sails.lift are both asynchronous. You're doing the right thing in your test (just make sure you call sails.lower in your afterEach method). Take a look at the current Sails integration tests for an example of how we do it. Also keep in mind that you might not need to lift and lower before each individual test--in some cases it might be okay to just lift once before a suite runs and use that instance for all the tests. In that case, you can use before and after instead of beforeEach and afterEach.

Upvotes: 1

Related Questions