0

I'm trying to build some test helper functions that will help me to run some hooks with Mocha to test my GraphQL queries(just that you understand the context). I want to do the following steps each time before I run the tests:

  1. Connect to mongoDB with mongoose
  2. Start the server (node)
  3. Add some test data directly into the database (via mongoose models)

// this function returns back the server instance because I need it in the 'after' hook to be able to stop it after the tests execution.

export const startServer = () => {
  mongoose.Promise = global.Promise;
  mongoose.connect(MONGO_URI_TEST);
  return mongoose.connection.once('open', () => {
    const app = express();
    app.post('/graphql', bodyParser.json(), graphqlExpress(req => {
      return { schema: executableSchema };
    })
    );
    return app.listen(9000, () => {
      console.log('Server started!');
    });
  });
};

// now here's the before hook where the server is started
let server;
before( done => {
  server = startServer(done); // here I need to wait 
  // some other async code that inserts test data into mongo
  const user = new User({email: test@test.com});
  user.save().then(() => {
    // saved successfully
    done();
  })
});

I'm quite new in the JS world, how do you manage to wait (without async await syntax) until all the promises from startServer function are resolved and you get back the server instance and just after start inserting data into the database? It's a dummy question but also some links with a better explanation of this concept that I have here would be appreciated.

LE: The entire question has reduced to the followings:

const createServer = () => {
const server = app.listen(port, () => {
  //callback body here
  });
};

How to convert the callback to a Promise and at the same time return a valid server reference such that in the end I can do this:

const someOtherFunction = () => {
  createServer().then(myValidServerInstance => {
    //do something with that instance
  }
}
cosmarc
  • 562
  • 3
  • 19
  • What does `once()` return? I guess you shouldn't have to pass a callback if you want to use promises. – Bergi Apr 10 '18 at 18:49
  • Could you manage it with `async`/`await`? If yes, please show us your attempt at using it, if no, why don't you want to use it? – Bergi Apr 10 '18 at 18:50
  • A stated [here](https://stackoverflow.com/questions/17575300/mongoose-the-function-once), "Adds a one time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed. Returns a reference to the EventEmitter, so that calls can be chained.". Anyways I think I found the solution, to use the Promise returned by mongoose.connect. I'll get back with an answer if it works or not. – cosmarc Apr 10 '18 at 20:15
  • 1
    Yes, if `.connect()` does return a promise, that would be much more appropriate to use than the eventemitter returned by `once`. – Bergi Apr 10 '18 at 20:18
  • @Bergi: I've edited the question. I've used `connect()` with the Promise mechanism. – cosmarc Apr 12 '18 at 19:46
  • You might want to edit the part about `connect` as well :-) – Bergi Apr 12 '18 at 19:54
  • As you are good with reducing the question to the relevant, surely the abstract [How do I convert an existing callback API to promises?](https://stackoverflow.com/q/22519784/1048572) will help you – Bergi Apr 12 '18 at 19:55

1 Answers1

0

TLDR: Some of the things about JS Promises were not clear for me, like for example the returning of the result via resolve() method.

So the right answer looks like this:

export const startServer = () => {
  mongoose.Promise = global.Promise;
// first mistake was the use of callbacks rather than Promise approach offered by mongoose.connect
  return mongoose.connect(MONGO_URI_TEST).then(() => {
    console.log('Connected to MongoLab TEST instance.');
    return createServer();
  },
  err => {
    console.log('Error connecting to MongoLab TEST instance:', err);
  });
};

The second one was returning directly the result of listen() before the operation get finished. So I've moved the code that is starting the server in another method and wrap the result of listen() into a promise and resolve the promise only when the server actually started listening.

const createServer = () => {
  const app = express();
  app.post('/graphql', bodyParser.json(), graphqlExpress(req => {
    return {
      schema: executableSchema,
      context: { headers: req.headers},
    };
  })
  );
  return new Promise((resolve, reject) => {
    const server = app.listen(9000, () => {
      if (server) {
        console.log('Server started on port 9000');
        resolve(server);
      } else {
        reject();
      }
    });
  });
};
cosmarc
  • 562
  • 3
  • 19