superagent / supertest with async / await
Asked Answered
F

2

9

Goal is to set the variable auth correctly for further use, hence i want to refactor the function loginUser:

function loginUser(user, request, auth) {
  return function(done) {
    request
      .post('/users/login')
      .send(credentials)
      .expect(200)
      .end(onResponse);

    function onResponse(err, res) {
      auth.token = res.body.token;
      return done();
    }
  };
}


 loginUser(user, request, auth)(function() {
  request.get(testUrl)
    .set('Authorization', `bearer ${auth.token}`)
    .expect(200, done);
});

to use async / await like this (without the callback):

auth = await loginUser(user, request);
request.get(testUrl)
    .set('Authorization', `bearer ${auth.token}`)
    .expect(200, done);

But i am struggling of returning / setting auth correctly (it would not matter if i pass auth as parameter or as return value).

What i tried was stuff like this:

async function loginUser(user, request) {
  let auth;
  await request
    .post('/users/login')
    .send(credentials)
    .expect(200)
    .end(onResponse);

  function onResponse(err, res) {
    auth.token = res.body.token;
  }
  return auth;
}

But auth was never set correctly.

Fianna answered 20/7, 2018 at 9:3 Comment(2)
Possible duplicate of Promises es6 and superagentElane
hmm not sure, since i want to get rid of the callback when calling the login functionFianna
F
11

Don't use 'end' syntax, that's for callbacks:

const response = await request.post(...)
  .expect(200)
const {body: {token}} = response
return token

Basically it should look like sync code

Forde answered 20/7, 2018 at 9:47 Comment(2)
You are right, but you could've added some details in the (...) i had some trouble understanding how to rewrite my code.Fianna
The part about const {body: {token}} = response was a bit confusing for me, ended up trying const {response} = await... which resulted in undefined response. Doing let response = await... worked fine. Just leaving this as note for anyone else who might get confused about this.. Superagent is nice, but the await syntax seems a bit lacking in examples. Anyway, it works now.. I guess your example is just addressing the specifc OP question on parsing the token from the body, and the syntax is a bit strange to me.Otocyst
H
3

The problem is that the onResponse method is being executed later than you the return of the function because of the event loop in Nodejs. So you will have to do resolve the promise exactly when you receive the data

The method loginUserInternal could be like this:

function loginUserInternal(user, request) {
  return new Promise((resolve,reject) => {
    let auth = {};
    request
      .post('/users/login')
      .send({
        username: user.username,
        password: user.password_decoded,
      })
      .expect(200)
      .end(onResponse);
    function onResponse(err, res) {
      if(err) return reject(err)
      auth.id = res.body.id;
      auth.token = res.body.token;
      auth.tokenExpires = res.body.tokenExpires;
      resolve(auth)
    }
  })
}

And call it like you were doing with async await.

Hue answered 20/7, 2018 at 9:17 Comment(2)
Can you show how to call it? I always end up with a timeout of 2000ms, Unhandled promise rejection or Promise { <pending> }. Also onResponse needs a return value when no error occurs or skip return complete (i did it this way).Fianna
Like you had in your post auth = await loginUser(user, request);, if it gives you promise rejection is that the request has failed, try to do a console.log(err) to see what's going onHue

© 2022 - 2024 — McMap. All rights reserved.