0

I have read some guides and because I'm a noob and also pretty stupid, I still can't see a way to actually correctly locally invoking a Lambda in serverless.

I started by implementing a really basic lambda function below:

'use strict';

const AWS = require('aws-sdk');
const Politician = require('../model/politician.js');

const dynamoDb = new AWS.DynamoDB.DocumentClient();

module.exports.put = async (event, context, callback) => {

    const requestBody = new Politician(event.body);
    let response;

    console.log('did we get this far?');

    submit(requestBody)
        .then(res => {
            response = {
                statusCode: 200,
                body: JSON.stringify({
                    message: `Successfully submitted politician with name ${requestBody.name}`,
                    politicianId: res.id
                })
            }
                .catch(err => {
                    console.log(err);
                    response = {
                        statusCode: 500,
                        body: JSON.stringify({
                            message: `Unable to submit candidate with email ${requestBody.name}`
                        })
                    }
                });
        });
};

const submit = politician => {
    console.log('submitting politician: ' + politician.name);

    return new Promise((resolve, reject) => {
        if (politician) {
            resolve(politician);
        } else {
            reject(new Error('it all went bad!'));
        }
    });
};

I'm not using DynamoDB yet but I want to get to that (I just need the basic call working first).

and then I set up a very simple Jest unit test that calls the lambda function above:

'use strict';
const fs = require('fs');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);

const AWS = require('aws-sdk');
const options = {
    region: 'localhost',
    endpoint: 'http://localhost:8000'
};
AWS.config.update(options);
const eventStub = require('../events/graeme.richardson.json');
const { lambda } = readFile('../functions/coxon-put-politician');


describe('Service politicians: mock for successful operations', () => {

    test('Replies back with a JSON response', () => {

        const event = eventStub;
        const context = {};

        const result = lambda.put(event, context);

        result
            .then(data => {
                expect(data).toBeFalsy();
            })
            .catch(e => {
                expect(e).toBe('me');
            });

    });
});

I have tried various ways of making the call const result = lambda.put(event, context); invoking the lambda just with its name, recasting the object as a function, and tons of others, but all I ever get is variations on the error:

TypeError: Cannot read property 'put' of undefined

      37 |         const context = {};
      38 | 
    > 39 |         const result = lambda.put(event, context);
         |                               ^
      40 | 
      41 |         result
      42 |             .then(data => {

      at Object.put (functions-test/coxon-put-politician.test.js:39:31)

or

TypeError: lambda is not a function

      37 |         const context = {};
      38 | 
    > 39 |         const result = lambda(event, context);
         |                        ^
      40 | 
      41 |         result
      42 |             .then(data => {

      at Object.lambda (functions-test/coxon-put-politician.test.js:39:24)

I feel like I'm just missing one bit of information that the guides I linked to, aren't saying. Does anyone know how to get this working?

As I hope is obvious, I'm eventually targeting node.js 8.1 on AWS Lambda.

thanks

skyboyer
  • 15,149
  • 4
  • 41
  • 56
Michael Coxon
  • 2,737
  • 5
  • 35
  • 59
  • So you're trying to call a lambda function from a lambda function? Try this: https://stackoverflow.com/questions/31714788/can-an-aws-lambda-function-call-another – Jack Marchetti Apr 19 '19 at 23:26
  • You ain't a noob or stupid. It does take some time and thought to get things around, especially with AWS. Can you share the `coxon-put-politician` file? – Jose A Apr 19 '19 at 23:26
  • @JackMarchetti no, I'm definitely not trying to do that - merely locally testing a lambda function, using a jest unit test. – Michael Coxon Apr 19 '19 at 23:35
  • @JoseA sorry, my question wasn't clear enough the first block of code is the Lambda funciton, the second is a Jest unit test that (hopefully) can invoke the lambda function. I can post all the rest of the serverless project, but that all seems to work (well, deploys as expected), and I didn't think it would add to the clarity of the question. – Michael Coxon Apr 19 '19 at 23:37
  • 1
    looks like `lambda` is not initiated by `readfile`. Try this `const lambda = require('../functions/coxon-put-politician');` – Chetan Ranpariya Apr 20 '19 at 02:27

1 Answers1

0

Thank you for looking at this @Chetan Ranpariya, yes this seems to have been the problem. Not sure why lots of posts are recommending promisify() - there must be an approach where this works I guess, but I just don't have the magic. The code for the lambda that works is:

'use strict';

const AWS = require('aws-sdk');
const Politician = require('../model/politician.js');

module.exports.put = async (event, context) => {

    const requestBody = new Politician(event.body);
    let response;

    submit(requestBody)
        .then(res => {
            response = {
                statusCode: 200,
                body: JSON.stringify({
                    message: `Successfully submitted politician with name ${requestBody.name}`,
                    politicianId: res.id
                })
            }

        });
};

const submit = politician => {
    console.log('submitting politician: ' + politician.name);

    return new Promise((resolve, reject) => {
        if (politician) {
            resolve(politician);
        } else {
            reject(new Error('it all went bad!'));
        }
    });
};

and the Jest test for it is:

'use strict';
const AWS = require('aws-sdk');
const options = {
    region: 'localhost',
    endpoint: 'http://localhost:8000'
};
AWS.config.update(options);
const eventStub = require('../events/graeme.richardson.json');
const lambda = require('../functions/coxon-put-politician');


describe('Service politicians: mock for successful operations', () => {

    test('Replies back with a JSON response', () => {

        const event = eventStub;
        const context = {};

        const result = lambda.put(event, context);

        result
            .then(data => {
                expect(data).toBeTruthy();
            })

    });
});
Michael Coxon
  • 2,737
  • 5
  • 35
  • 59