javascriptjestjsmongodb-stitch

How to get Jest to see the functions I am writing for MongoDB Stitch?


I am trying out Stitch, a serverless/hosted JavaScript environment from MongoDB. My main purpose is to help me learn modern JavaScript, but I am trying to write a useful app as well.

I have written the following function, and saved it in my Stitch app. I believe this follows the documented way to write functions in Stitch, and I have tested it from the Stitch administration console:

exports = function(query){
  const http = context.services.get("HTTP");
  const urlBase = context.values.get("stackOverflowApiUrl");
  const options = [
    'order=desc',
    'sort=activity',
    'site=stackoverflow',
    'q=' + encodeURIComponent(query),
    'user=472495',
    'filter=!--uPQ.wqQ0zW'
  ];

  return http
    .get({ url: urlBase + '?' + options.join('&') })
    .then(response => {
      // The response body is encoded as raw BSON.Binary. Parse it to JSON.
      const ejson_body = EJSON.parse(response.body.text());
      return ejson_body.total;
    });
};

This code is pretty simple - it obtains an http object for making external API fetches, and obtains a configuration value for a URL urlBase to contact (resolving to https://api.stackexchange.com/2.2/search/excerpts) and then makes a call to the Stack Overflow Data API. This runs a search query against my user and returns the number of results.

So far so good. Now, I want to call this function locally, in Jest. To do this, I have installed Node and Jest in a local Docker container, and have written the following test function:

const callApi = require('./source');

test('Simple fetch with no user', () => {
    expect(callApi('hello')).toBe(123);
});

This fails, with the following error:

~ # jest
 FAIL  functions/callApi/source.test.js
  ✕ Simple fetch with no user (3ms)

  ● Simple fetch with no user

    TypeError: callApi is not a function

      2 | 
      3 | test('Simple fetch with no user', () => {
    > 4 |     expect(callApi('hello')).toBe(123);
        |            ^
      5 | });
      6 | 

      at Object.<anonymous>.test (functions/callApi/source.test.js:4:12)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.418s
Ran all test suites.

(In fact I was expecting it to fail, since it contains a global object context that Jest does not have access to. I will work out how to mock that later, but for now Jest cannot even see the function at all).

I suspect I can see the reason - in the Jest introduction docs, one has to do this for the SUT:

module.exports = function() { ... }

However the Stitch docs seem to require functions to be defined as:

exports = function() { ... }

I do not have a background in JavaScript to understand the difference. I could try module.exports in Stitch, but I would rather not, since this would either not work now, or cause a breakage in the future. Can Jest be instructed to "see" bare exports without the module prefix?

Incidentally, I have picked Jest because it is popular, and because some of my JavaScript colleagues vouch for it. However, I am not wedded to it, and would be happy to use something else if it is known to be better for Stitch development.

Update

Following the useful answer from jperl below, I find that the following construction is not possible in Stitch:

module.exports = exports = function() {}

I also cannot do this:

exports = function() {}
module.exports = exports

If I try either, I get the following error:

runtime error during function validation

So it looks like I have to get Jest to work without module.exports, or create a glue file that imports the exports version into module.exports, with the main file being used by Stitch, and the glue importer being used by Jest.


Solution

  • I suggest you to read this thread. And you're right in thinking it has to do with modules.exports vs exports. The thing is that module.exports and exports first point to the same thing. So something like this works:

    //modify the same object that modules.exports is pointing to
    exports.a = {}
    exports.b = {}
    

    but this won't:

    exports = {}
    

    Why? Because now exports points to something else than module.exports so what you're doing has no effect at all.

    Update

    Following some updates in the comments, we came to the view that Stitch does not seem to support the export format that Jest requires.