使用 CLASP 测试 GAS 时如何模拟依赖关系

2023-11-23

背景

我最近了解到CLASP并对使用的可能性感到兴奋TDD编辑我的谷歌应用脚​​本(天然气)本地。

NOTE:可能有一种方法可以使用现有的 GAS 编辑器编写测试,但如果可能的话,我更愿意使用现代编辑器

clasp 效果很好,但我无法弄清楚如何模拟单元测试的依赖关系(主要通过jest,尽管我很乐意使用任何有效的工具)

  • I got farthest by using the gas-local package, and was able to mock a single dependency within a test
    • 但是,我找不到在单个测试/调用中模拟多个依赖项的方法,因此我创建了这个问题

挑战

尽管安装了@types/google-apps-script,我不清楚如何分别使用 ES5 或 ES2015 语法“要求”或“导入”Google Apps 脚本模块 - 请参阅下面的说明。

相关 StackOverflow 帖子

虽然单元测试也有类似的SO问题here,大多数内容/评论似乎来自前扣环时代,我在跟踪剩余线索时无法找到解决方案。 (当然,我未经训练的眼睛很可能错过了一些东西!)。

Attempts

使用本地天然气

正如我上面提到的,在使用gas-local时尝试模拟多个依赖项后,我创建了一个问题(请参阅上面的链接)。我的配置类似于jest.mock我在下面描述了测试,但值得注意的是以下差异:

  • 我使用 ES5 语法gas-local tests
  • 我的包配置可能略有不同

使用 jest.mock

LedgerScripts.test.js

import { getSummaryHTML } from "./LedgerScripts.js";
import { SpreadsheetApp } from '../node_modules/@types/google-apps-script/google-apps-script.spreadsheet';

test('test a thing', () => {
    jest.mock('SpreadSheetApp', () => {
        return jest.fn().mockImplementation(() => { // Works and lets you check for constructor calls
          return { getActiveSpreadsheet: () => {} };
        });
      });
    SpreadsheetApp.mockResolvedValue('TestSpreadSheetName');

    const result = getSummaryHTML;
    expect(result).toBeInstanceOf(String);
});

LedgerScripts.js

//Generates the summary of transactions for embedding in email
function getSummaryHTML(){  
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dashboard = ss.getSheetByName("Dashboard");

  // Do other stuff  
  return "<p>some HTML would go here</p>"
}

export default getSummaryHTML;

结果(运行后jest命令)

Cannot find module '../node_modules/@types/google-apps-script/google-apps-script.spreadsheet' from 'src/LedgerScripts.test.js'

      1 | import { getSummaryHTML } from "./LedgerScripts.js";
    > 2 | import { SpreadsheetApp } from '../node_modules/@types/google-apps-script/google-apps-script.spreadsheet';
        | ^
      3 | 
      4 | test('test a thing', () => {
      5 |     jest.mock('SpreadSheetApp', () => {

      at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:307:11)
      at Object.<anonymous> (src/LedgerScripts.test.js:2:1)

作为参考,如果我去google-apps-script.spreadsheet.d.ts具有我想要的类型的文件,我在文件顶部看到以下声明...

declare namespace GoogleAppsScript {
  namespace Spreadsheet {

...文件底部的这个:

declare var SpreadsheetApp: GoogleAppsScript.Spreadsheet.SpreadsheetApp;

所以也许我只是导入SpreadsheetApp错误地?

其他文件

笑话配置.js

module.exports = {
    
    clearMocks: true,
    moduleFileExtensions: [
      "js",
      "json",
      "jsx",
      "ts",
      "tsx",
      "node"
    ],
    testEnvironment: "node",
  };

babel.config.js

module.exports = {
  presets: ["@babel/preset-env"],
};

包.json

{
  "name": "ledger-scripts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.11.1",
    "@babel/preset-env": "^7.11.0",
    "@types/google-apps-script": "^1.0.14",
    "@types/node": "^14.0.27",
    "babel-jest": "^26.3.0",
    "commonjs": "0.0.1",
    "eslint": "^7.6.0",
    "eslint-plugin-jest": "^23.20.0",
    "gas-local": "^1.3.1",
    "requirejs": "^2.3.6"
  },
  "devDependencies": {
    "@types/jasmine": "^3.5.12",
    "@types/jest": "^26.0.9",
    "jest": "^26.3.0"
  }
}

注意:您的问题范围很广,可能需要澄清。

clasp 效果很好,但我无法弄清楚如何模拟单元测试的依赖关系(主要通过开玩笑,尽管我很乐意使用任何有效的工具)

您不需要 Jest 或任何特定的测试框架来模拟全局 Apps 脚本对象。

// LedgerScripts.test.js
import getSummaryHTML from "./LedgerScripts.js";

global.SpreadsheetApp = {
  getActiveSpreadsheet: () => ({
    getSheetByName: () => ({}),
  }),
};

console.log(typeof getSummaryHTML() === "string");
$ node LedgerScripts.test.js
true

所以也许我只是错误地导入了 SpreadsheetApp ?

是的,导入不正确.d.ts进入笑话。 Jest 不需要 TypeScript 文件SpreadsheetApp。你可以省略它。 对于 Jest,您只需稍微修改上面的示例即可。

// LedgerScripts.test.js - Jest version
import getSummaryHTML from "./LedgerScripts";

global.SpreadsheetApp = {
  getActiveSpreadsheet: () => ({
    getSheetByName: () => ({}),
  }),
};

test("summary returns a string", () => {
  expect(typeof getSummaryHTML()).toBe("string");
});

尽管安装了 @types/google-apps-script,但我不清楚如何“要求”或“导入”Google Apps 脚本模块,无论是使用 ES5 还是 ES2015 语法

@types/google-apps-script不包含模块并且您不导入它们。这些都是TypeScript 声明文件。如果您的编辑器支持 TypeScript,它将在后台读取这些文件,并且突然间您将能够获得自动完成功能,即使是在纯 JavaScript 文件中也是如此。

补充评论

  • 在这里,您检查函数是否返回字符串,也许只是为了使您的示例变得非常简单。但必须强调的是,此类测试最好留给 TypeScript。
  • 既然你返回了一个 HTML 字符串,我觉得有义务指出这个优秀的HTML服务以及 Apps 脚本的模板化能力。
  • 单元测试还是集成测试?您提到了单元测试,但依赖全局变量通常表明您might不是单元测试。考虑重构您的函数,以便它们接收对象作为输入,而不是从全局范围调用它们。
  • 模块语法:如果使用export default foo,然后不带花括号导入:import foo from "foo.js"但如果你使用export function foo() {然后你使用花括号:import { foo } from "foo.js"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 CLASP 测试 GAS 时如何模拟依赖关系 的相关文章

随机推荐

  • 访问 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData

    谁能告诉我为什么我无法访问注册表项 HKEY LOCAL MACHINE SOFTWARE Microsoft Windows CurrentVersion Installer UserData 如果我查询GetSubKeysNames o
  • 优化 Jinja2 环境创建

    我的应用程序在 Google App Engine 上运行 由于 CPU 使用率高 大多数请求不断收到黄色标记 使用探查器 我将问题追溯到创建的例程jinja2 Environment实例 我正在模块级别创建实例 from jinja2 i
  • 为什么在 Intellij 中使用 Android SDK 时缺少 Android AVD Manager?

    I am trying to use the Android SDK in my IntelliJ project that is a larger project containing both web and ios clients a
  • Numpy:作为 Matlab 进行赋值和索引

    有时 分配仅具有一个索引的数组很有用 在 Matlab 中这很简单 M zeros 4 M 1 5 end 1 M 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 Numpy 有没有办法做到这一点 首先 我想展平数组 但该操
  • 最适合拼写检查器、字典和同义词库的算法和数据结构

    实施的最佳方式 字典 有没有比 Trie 更好的 DS 字典 同义词库 不知道 因为匹配的是单词的含义 相似的含义 拼写检查器 比哈希映射更好的东西 如果可能的话 提供正确的拼写建议 当在一小时的面试中被问到 我们是否需要为算法编写 c c
  • Android 搜索:使用 FTS 表以及普通 SQLite DB 表

    这更多的是一个设计问题 而不仅仅是一个编码问题 我已经有一个将数据存储在 SQLite DB 表中的应用程序 现在我想添加搜索功能 据我了解 为了启用搜索功能 我需要 FTS 表 我拥有的表格是 不完全相同 但给出了非常相似的示例 内容表
  • Android 音频:改变音调

    SoundPool 的 Android 文档称 该应用程序还可以通过实时调整多普勒或合成效果的播放速率来改变音调 所以我尝试这样做 使用 setRate 方法从一个音符平滑地变化到另一个音符 但结果很糟糕 声音变化非常参差不齐 这是我尝试过
  • MySQL 使用 CONCAT 条件进行选择

    我正在尝试在脑海中编译它 我有一个包含名字和姓氏字段的表 我有一个像 Bob Jones 或 Bob Michael Jones 这样的字符串以及其他几个字符串 问题是 例如我有 鲍勃的名字 以及 迈克尔 琼斯的姓氏 所以我想 SELECT
  • Java流是否有相当于带有变量赋值的while

    是否存在与以下内容等效的流 List
  • Tensorflow 从元图中打印所有占位符变量名称

    我有一个张量流模型 其中有 meta 和检查点文件 我试图打印模型所需的所有占位符 而不查看构建模型的代码 以便我可以在不知道模型是如何创建的情况下构建输入 feed dict 作为参考 这里是模型构建代码 在另一个文件中 def save
  • 优秀的 setjmp/longjmp 教程 [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 你好 我想阅读有关 C 语言 setjmp longjmp 的优秀教程 如果有真实的而不是人造的示例 那就更好了 Thanks 这并不是一个真正的教程 而是libpng 文档描述该库
  • 应用程序更新后共享首选项丢失

    我一整天都在研究这个问题 以下是要点 共享首选项should当用户更新应用程序时保持持久性 就我而言 更新应用程序后 它们丢失了 这个问题每次都会重现 我从 Play 商店安装旧的 APK 然后adb install r new apk使用
  • 色彩校正 MP4/Webm 视频

    我有一个大型视频 其中一些动画对于其他嵌入方法 gif png 序列等 来说太复杂 太长 并且我们遇到了视频中颜色的问题 本质上 我们将网页背景作为视频的一部分 以防止视频播放时出现任何边缘 我们正在尝试使视频上的渐变背景与网页上的渐变背景
  • Jenkins 的 Github 插件获取提交者和作者姓名

    如果我理解得很好 git 插件会将提交者和作者的姓名以及电子邮件暴露给环境变量GIT AUTHOR NAME GIT COMMITTER NAME GIT AUTHOR EMAIL and GIT COMMITTER EMAIL基于git的
  • Netbeans 等待连接到 XDEBUG

    Netbeans 不会连接到 xdebug 我尝试过以下帖子中的建议 调试 IDE 与 XDebug 的端口连接 等待连接 netbeans 显示 正在等待连接 netbeans xdebug 但这并不能解决我的问题 Netbeans 似乎
  • 带分隔符的 Android 列表视图

    我想创建一个带有分隔符的列表视图 就像在默认联系人应用程序中一样 我的应用程序需要对列表进行排序 并用分隔符分隔项目 如联系人应用程序中的字母顺序排序 能够使用分隔符标题进行滚动将是一个额外的优势 任何指示都会有帮助 谢谢 看看这个开源项目
  • 为什么 numpy.dtype('float64') 很特别?

    有人可以解释以下脚本输出背后的逻辑吗 import numpy if numpy dtype numpy float64 None print Surprise 谢谢 看起来像是一场不幸的事故 有人决定dtype None 将 默认 浮动
  • 如何创建可重用的表单 Vue 组件

    假设我想创建一个联系表单 在此联系表单中 用户可以有多个地址 我认为这是使用 Vue 组件的绝佳机会 这样我就不必创建冗余的地址表单字段 然后我就可以在网站的不同区域使用这个组件 比如编辑 创建等 我将如何创建一个父级可以使用的表单组件 并
  • 将参数传递给 Dart Polymer 元素

    我能找到的 Dart Polymer 的唯一可靠示例不使用任何参数 如何将参数传递给模板 是通过构造函数完成的吗 我的具体示例是 我有一个带有标题的卡片元素 我想将卡片的标题作为字符串传递给该元素 我看过将数据传递给 Polymer 元素
  • 使用 CLASP 测试 GAS 时如何模拟依赖关系

    背景 我最近了解到CLASP并对使用的可能性感到兴奋TDD编辑我的谷歌应用脚 本 天然气 本地 NOTE 可能有一种方法可以使用现有的 GAS 编辑器编写测试 但如果可能的话 我更愿意使用现代编辑器 clasp 效果很好 但我无法弄清楚如何