简体   繁体   中英

Can't mock promise function

I have the following lambda (aws) code:

exports.APILambda = (databaseConnection) => {
  return function (event, context, callback) {
    context.callbackWaitsForEmptyEventLoop = false

    const connection = databaseConnection()

    connection.then((connection, query, args) => {
      connection.query(queries(query, args), args)
        .then(result => {
          console.log(result)
          connection.end()
          callback(null, { data: result })
        })
        .catch(err => {
          throw err
        })
    })
      .catch(err => {
        logger.error(`${err.stack}`)
        callback(err)
      })
  }
}

databaseConnection is a mariaDb connection implemented as:

function databaseConnection () {
  return mariadb.createConnection({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    port: '3306',
    database: 'test'
  })
}

and my test is:

describe('on new query', () => {
  it('returns data', async (done) => {
    await runLambda(
      ['person', ['John']],
      (query) => {
        expect(query).toHaveBeenCalledWith(
          expect.arrayContaining(['person', ['John']])
        )
      }, done)
  })
})

for that test, I had to write the following function:

async function runLambda (args, assertions, done) {
  const query = jest.fn(args => {
    return Promise.resolve({
      'name': 'John',
      'lastName': 'Wayne'
    })
  })

  const onNewQuery = APILambda(async () => ({ query }))

  const event = {}
  const context = {}
  await onNewQuery(
    event,
    context,
    (err, result) => {
      if (err) done(err)
      assertions(query)
      done(result)
    }
  )
}

but I'm having trouble when I run it, it keeps throwing: TypeError: connection.end is not a function or saying that the args are undefined.

Could someone shed a light on how to properly mock this?

There are many problems with your code:

  1. You should create mock for connection.end() method.
  2. you should NOT pass the successful result to done() callback
  3. You should return an array to resolve multiple values for connection.then() .
  4. You didn't provide queries function, so I just pass query and args parameters directly.
  5. You passed args parameter, but you didn't use it, I use it below based on the meaning of the code

An working example:

testUtils.js :

const { APILambda } = require('./apiLambda');
// 5. You passed `args` parameter, but you didn't use it, I use it below based on the meaning of code
async function runLambda(args, assertions, done) {
  const query = jest.fn(() => {
    return Promise.resolve({
      name: 'John',
      lastName: 'Wayne',
    });
  });
  // 1. create mock for `connection.end()` method.
  const end = jest.fn();

  // 3. You should return an array to resolve multiple values for connection.then()
  const onNewQuery = APILambda(async () => [{ query, end }, args, null]);

  const event = {};
  const context = {};
  await onNewQuery(event, context, (err, result) => {
    if (err) done(err);
    assertions(query);
    // 2. you should NOT pass successful result to done() callback
    done();
  });
}

module.exports = { runLambda };

apiLambda.js :

exports.APILambda = (databaseConnection) => {
  return function(event, context, callback) {
    context.callbackWaitsForEmptyEventLoop = false;

    const connection = databaseConnection();

    connection
      .then(([connection, query, args]) => {
        connection
          // 4. You didn't provide `queries` function, so I just pass `query` and `args` parameters directly.
          .query(query, args)
          .then((result) => {
            console.log(result);
            connection.end();
            callback(null, { data: result });
          })
          .catch((err) => {
            throw err;
          });
      })
      .catch((err) => {
        console.error(`${err.stack}`);
        callback(err);
      });
  };
};

apiLambda.test.js :

const { runLambda } = require('./testUtils');

describe('on new query', () => {
  it('returns data', async (done) => {
    await runLambda(
      ['person', ['John']],
      (query) => {
        expect(query).toHaveBeenCalledWith(['person', ['John']], null);
      },
      done,
    );
  });
});

unit test result:

 PASS  src/stackoverflow/65179710/apiLambda.test.js (9.195s)
  on new query
    ✓ returns data (16ms)

  console.log src/stackoverflow/65179710/apiLambda.js:341
    { name: 'John', lastName: 'Wayne' }

--------------|----------|----------|----------|----------|-------------------|
File          |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files     |    85.19 |       50 |    81.82 |     87.5 |                   |
 apiLambda.js |       75 |      100 |    66.67 |       75 |          18,22,23 |
 testUtils.js |    93.33 |       50 |      100 |      100 |                19 |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.556s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM