插件窝 干货文章 测试 AWS AppSync JavaScript 解析器

测试 AWS AppSync JavaScript 解析器

AppSync 解析 行时 JavaScript 761    来源:    2024-10-22

“还有什么比测试 JavaScript 文件更容易的呢?”

这是我上个月开始开发 AppSync JavaScript 解析器时问自己的问题。我需要转换 HTTP 调用的响应并执行一些错误检查。这应该需要进行一些单元测试,我将在半小时内完成。 错了.

是什么让这个特殊的测试如此困难? AppSync 的 JS 解析器与普通 JS 有何不同? AppSync Serverless 插件如何使事情变得复杂?所有这些以及更多,我将在本文中解释。

AppSync JS 解析器非常棒

在 GraphQL 中,解析器负责连接到数据源以及将数据传入和传出。它们甚至可以处理错误情况并进行一些基本的流量控制。自 2017 年以来,AppSync 使用 Apache VTL 作为其解析器运行时语言。速度很快。这很复杂。这是未知的(我学习 VTL 只是为了使用 AppSync 解析器;我所有的同事学习 VTL 只是为了使用 AppSync 解析器)。

立即学习“Java免费学习笔记(深入)”;

然后,在 2022 年末,AppSync 推出了一个名为 APPSYNC_JS 的特殊 JavaScript 运行时,可以为用基本 JavaScript 编写的 AppSync 解析器提供支持。该运行时必须快速(没有明显的冷启动)并且运行成本低廉(JavaScript 解析器不会产生直接的用户成本)。为了实现这些目标,AWS 省略了某些 JavaScript 功能,例如 throw、try/catch、while/do-while 和 async/await。

为了管理“引发错误”等一些基础知识,APPSYNC_JS 提供了特殊的运行时模块 util、扩展和运行时。您可以通过导入 @aws-appsync/utils npm 模块在代码中引用这些模块。这可以让你“抛出自定义错误”(util.error())、获取时间戳(util.time.nowISO8601())、提前返回(runtime.earlyReturn())等等。

如果您使用过 AppSync VTL 解析器(我在这里、这里和这里写过有关它们的文章),那么我今天所说的一切听起来都不会很糟糕。与你去过的地方相比,这里简直就是天堂。背景很重要。也就是说,让我们继续讨论我们需要克服的一些障碍。

适合我的运行时间,不适合你的运行时间

还记得我在上面介绍的 @aws-appsync/utils 库吗?当你有一分钟​​的时间时,cmd-单击它并环顾四周。有一个 TypeScript 声明文件、一个映射文件和一个仅处理一些导出绑定的小 JavaScript 文件。你没看到什么?没错,就是没有执行。 @aws-appsync 库都是类型声明。它们的功能 100% 来自 AWS 提供的 APPSYNC_JS 运行时。

AWS 为其 JS 解析器提供自己的运行时的原因之一是它需要。 APPSYNC_JS 仅支持一部分操作(请记住,无抛出、无异步、无 while 循环等),以便它能够以一致的快速方式执行您的 JavaScript。为了缩小代码大小,它在运行时提供内置实用程序和模块来执行诸如引发错误、创建 ID 和解析时间戳等操作。这意味着,如果您的 JS 解析器需要执行诸如引发错误、创建 ID 或解析时间戳之类的操作,您无法单位1 测试您的解析器.

例如,要在 JS 解析器中引发(抛出)错误,您可以使用 util 全局变量并调用 util.error(myError)。如果您可以使用 throw,则可以在单元测试中运行并测试解析器。但是,鉴于您无权访问 util.error() 的运行时实现,您的单元测试框架将正确地抱怨“util.error 不是函数。”

AppSync 客户端库的救援

AWS 预见到了这个问题,并在其 @aws-sdk/client-appsync 库中提供了解决方案。您可以获取解析器代码(包括所有 util 和运行时引用),并针对 AppSync 的 JS 运行时执行该代码。此执行发生在 AppSync 中,因此您需要 Internet 连接和 IAM 权限才能进行调用。这使我们远离了我对“单元测试”的定义,但至少我们仍然可以测试2.

在我们的示例中,我可以创建一个上下文对象,我希望 JS 解析器的响应方法能够接收该对象,然后创建一个 EvaluateCodeCommandInput 并让我的 AppSync 客户端发送它:

Image description

这让我们摆脱了最初的运行时缺失的困境。但是,还有另一个复杂的问题来自一个不太可能的来源,即我们的无服务器插件。

AppSync 无服务器插件参与其中

我喜欢无服务器框架及其插件生态系统。我可以使用无服务器框架更快地构建,并且多年来一直提倡使用它。出于同样的原因,我喜欢 serverless-appsync-plugin。在该插件的后续版本中,它添加了对 JS 解析器的支持,包括使用 esbuild 的内置捆绑器。这使您可以使用导入/导出语法 (ES6) 编写 JS(或 TS),并将所有内容归结为简单的、与 APPSYNC_JS 兼容的 JavaScript。

但是,如果你想使用 ES6 语法并像我上面解释的那样测试你的 JS 解析器,你就会遇到问题。如果您将 TypeScript 或 ES6 JS 文件直接传递给 AppSync,AppSync 将拒绝它。 serverless-appsync-plugin 通过在将代码交给 AppSync 之前使用 esbuild 捆绑代码来解决此问题。我们将不得不做同样的事情。

幸运的是,esbuild 可以作为 JavaScript 库导入并在您的测试设置中使用。本质上,在将测试文件传递给 AppSync 之前,我们将通过 esbuild.buildSync() 步骤传递它,如下所示:

测试 AWS AppSync JavaScript 解析器

这还有一个额外的好处,即可以将任何导入语句捆绑到您在测试文件中可能使用过的其他文件。您的所有代码(包括导入)最终都在一个文件中。 AppSync 现在可以读取解析器、执行它并向您提供结果。成功了!

概括

再次强调,如果您有使用 AppSync VTL 解析器的经验,您可能会对自己说“这是一个不必扰乱 VTL 的小代价”,我同意您的观点。将来,我可以看到 AWS 提供其 APPSYNC_JS 运行时作为完全实现的库。这将使我们跳过网络调用并使这些测试再次成为“单元”3。我希望这能让您有信心使用 AppSync 进行构建。这是一项很棒的服务

进一步阅读

AWS 文档:JavaScript 解析器概述
Benoit Bure:关于 AppSync JavaScript 管道解析器您应该了解的一切
Benoit Bure:为 AppSync JavaScript 解析器编写可重用代码
Eric Bach:开发和测试 AWS AppSync JavaScript 解析器
代码示例的 GitHub Gist


  1. 如果测试需要网络连接或AWS权限,那么它不是我书中的“单元”测试↩

  2. 请不要嘲笑这些东西。所有模拟都是有害的。我保证在不久的将来会就此写一篇咆哮。 ↩

  3. MTUA?戴在球帽上可能会很好看...↩