如何让 Jest 看到我为 MongoDB Stitch 编写的函数?

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

我正在试用 Stitch,这是来自 MongoDB 的 serverless/hosted JavaScript 环境。我的主要目的是帮助我学习现代JavaScript,但我也在尝试编写一个有用的应用程序。

我编写了以下功能,并将其保存在我的 Stitch 应用程序中。我相信这遵循了在 Stitch 中编写函数的记录方式,并且我已经从 Stitch 管理控制台对其进行了测试:

exports = function(query){
  const http = context.services.get("HTTP");
  const urlBase = context.values.get("WhosebugApiUrl");
  const options = [
    'order=desc',
    'sort=activity',
    'site=Whosebug',
    '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;
    });
};

这段代码非常简单 - 它获取一个 http 对象用于进行外部 API 获取,并获取一个 URL urlBase 的配置值以联系 (解析为 https://api.stackexchange.com/2.2/search/excerpts),然后调用堆栈溢出数据 API。这将针对我的用户和 returns 结果数运行搜索查询。

到目前为止一切顺利。现在,我想在 Jest 中本地调用这个函数。为此,我在本地 Docker 容器中安装了 Node 和 Jest,并编写了以下测试函数:

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

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

失败,出现以下错误:

~ # 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.

(事实上我预计它会失败,因为它包含一个 Jest 无法访问的全局对象 context。我稍后会弄清楚如何模拟它,但现在 Jest 甚至不能完全看函数)。

我想我能看出原因 - 在 Jest 介绍文档中,必须为 SUT 执行此操作:

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

但是 Stitch 文档似乎要求将函数定义为:

exports = function() { ... }

我没有 JavaScript 的背景,无法理解其中的区别。我可以在 Stitch 中尝试 module.exports,但我宁愿不这样做,因为这要么现在不起作用,要么在将来导致损坏。可以指示 Jest "see" 在没有 module 前缀的情况下裸露 exports 吗?

顺便说一下,我选择 Jest 是因为它很受欢迎,而且我的一些 JavaScript 同事也支持它。然而,我并不拘泥于它,如果已知它对 Stitch 开发更好,我会很乐意使用其他东西。

更新

根据下面来自 jperl 的有用答案,我发现以下构造在 Stitch 中是不可能的:

module.exports = exports = function() {}

我也做不到:

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

如果我尝试其中之一,我会收到以下错误:

runtime error during function validation

所以看起来我必须让 Jest 在没有 module.exports 的情况下工作,或者创建一个将 exports 版本导入 module.exports 的胶水文件,并使用主文件由 Stitch 开发,Jest 使用胶水导入器。

我建议您阅读这篇文章 thread。你认为它与 modules.exportsexports 有关是正确的。问题是 module.exportsexports 首先指向同一件事。所以像这样的东西有效:

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

但这不会:

exports = {}

为什么?因为现在 exports 指向 module.exports 以外的东西,所以你所做的根本没有效果。

更新

根据评论的一些更新,我们认为 Stitch 似乎不支持 Jest 要求的导出格式。

这是 jperl 回答的附录,展示了我如何在尊重 Stitch 的限制的同时让 Jest 工作。

首先,值得注意的是 Stitch 应用程序的布局方式。这是由 import/export 格式决定的。

auth_providers/
functions/
    function_name_1/
        config.json
        source.js
    function_name_2/
        config.json
        source.js
    ...
services/
values/

config.json文件由Stitch远程创建,通过导出获取。这包含 ID 信息以唯一标识同一文件夹中的函数。

我相信 JavaScript 将测试与源代码混合在一起是很常见的做法,所以我遵循这种风格(我是现代 JS 的新手,我承认我觉得这种风格不整洁,但我 运行 尽管如此)。因此,我在每个函数文件夹中添加了一个 source.test.js 文件。

最后,由于Stitch需要的和Jest需要的不一致,我写了一个脚本在每个函数文件夹_source.js下创建一个源代码文件。

因此,每个文件夹将包含这些文件(下划线文件可能会被 Git 忽略,因为它们将始终生成):

_source.js
config.json
source.js
source.test.js

为了创建带下划线的副本,我正在使用这个 shell 脚本:

#!/bin/bash

# Copy all source.js files as _source.js
for f in $(find functions/ -name source.js); do cp -- "$f" "$(dirname $f)/_$(basename $f)"; done

# Search and replace in all _source.js files
for f in $(find functions/ -name _source.js); do sed -i -e 's/exports =/module.exports =/g' $f; done

也许有点老套,但它确实有效!