如何在 GAS 中测试触发功能?
Posted
技术标签:
【中文标题】如何在 GAS 中测试触发功能?【英文标题】:How can I test a trigger function in GAS? 【发布时间】:2013-04-11 22:15:17 【问题描述】:Google Apps 脚本支持Triggers,它通过Events 来触发函数。不幸的是,开发环境将允许您在不传递参数的情况下测试函数,因此您无法以这种方式模拟事件。如果您尝试,您会收到如下错误:
ReferenceError: 'e' 未定义。
或者
TypeError: Cannot read property *...* from undefined
(其中e
未定义)
可以将事件视为可选参数,并使用Is there a better way to do optional function parameters in javascript? 中的任何技术将默认值插入到触发函数中。但这带来了一个风险,即懒惰的程序员(如果是你,请举手!)会留下该代码,并产生意想不到的副作用。
肯定有更好的方法吗?
【问题讨论】:
始终查看所有答案并找到最新的更新,而不是仅接受的更新。当前(2020)更新为here。 【参考方案1】:2020-2021 年更新:
您不需要使用前面答案中建议的任何类型的模拟事件。
正如问题中所说,如果您直接在脚本编辑器中“运行”该函数,则会出现类似错误
TypeError: Cannot read property ... from undefined
被抛出。这些不是真正的错误。此错误只是因为您在没有事件的情况下运行了该函数。如果您的函数未按预期运行,您需要找出实际错误:
要测试触发功能,
手动触发相应的事件:即,要测试onEdit
,编辑工作表中的单元格;要测试onFormSubmit
,请提交一个虚拟表单响应;要测试 doGet
,请将浏览器导航到已发布的 webapp /exec
url。
如果有任何错误,它会被记录到 stackdriver。要查看这些日志,
在脚本编辑器中 > 左侧栏中的执行图标(旧版编辑器: 查看 > 执行)。
或者,点击here > 点击您感兴趣的项目 > 点击左侧栏的“执行”图标(第 4 个)
您将在执行页面中找到执行列表。确保清除左上角的“Ran as:Me”等任何过滤器以显示所有执行。点击你感兴趣的执行,它会以红色显示导致触发器失败的错误。
注意:有时,由于错误,日志不可见。尤其是在 webapp 由匿名用户运行的情况下更是如此。在这种情况下,建议将默认谷歌云项目切换为标准谷歌云项目,并直接使用 View> Stackdriver logging。请参阅here 了解更多信息。
-
为了进一步调试,您可以使用编辑代码在您感兴趣的任何行之后添加
console.log(/*object you're interested in*/)
,以查看该对象的详细信息。 强烈建议将要查找的对象字符串化:console.log(JSON.stringify(e))
,因为日志查看器具有特殊性。添加 console.log()
后,从第 1 步开始重复。重复此循环,直到缩小问题范围。
恭喜!您已经成功地解决了问题并越过了第一个障碍。
【讨论】:
此解决方案不适合插件开发测试,但更多的是插件开发问题本身。【参考方案2】:作为上述第 4 点中提到的方法(2020 年更新)的补充: 这是我用来跟踪触发代码的一个小例程,它已经为我节省了很多时间。我还打开了两个窗口:一个带有堆栈驱动程序(执行),一个带有代码(主要位于库中),因此我可以轻松找出罪魁祸首。
/**
*
* like Logger.log %s in text is replaced by subsequent (stringified) elements in array A
* @param string | object text %s in text is replaced by elements of A[], if text is not a string, it is stringified and A is ignored
* @param object[] A array of objects to insert in text, replaces %s
* @returns string text with objects from A inserted
*/
function Stringify(text, A)
var i = 0 ;
return (typeof text == 'string') ?
text.replace(
/%s/g,
function(m)
if( i >= A.length) return m ;
var a = A[i++] ;
return (typeof a == 'string') ? a : JSON.stringify(a) ;
)
: (typeof text == 'object') ? JSON.stringify(text) : text ;
/* use Logger (or console) to display text and variables. */
function T(text)
Logger.log.apply(Logger, arguments) ;
var Content = Stringify( text, Array.prototype.slice.call(arguments,1) ) ;
return Content ;
/**** EXAMPLE OF USE ***/
function onSubmitForm(e)
T("responses:\n%s" , e.response.getItemResponses().map(r => r.getResponse()) ;
【讨论】:
【参考方案3】:2017 年更新:
使用 Stackdriver Logging 为 Google Apps 脚本调试 Event objects。从脚本编辑器的菜单栏中,转到:
View > Stackdriver Logging
查看或流式传输日志。
console.log() 会写DEBUG
级别的消息
示例onEdit():
function onEdit (e)
var debug_e =
authMode: e.authMode,
range: e.range.getA1Notation(),
source: e.source.getId(),
user: e.user,
value: e.value,
oldValue: e. oldValue
console.log(message: 'onEdit() Event Object', eventObject: debug_e);
示例onFormSubmit():
function onFormSubmit (e)
var debug_e =
authMode: e.authMode,
namedValues: e.namedValues,
range: e.range.getA1Notation(),
value: e.value
console.log(message: 'onFormSubmit() Event Object', eventObject: debug_e);
示例onChange():
function onChange (e)
var debug_e =
authMode: e.authMode,
changeType: changeType,
user: e.user
console.log(message: 'onChange() Event Object', eventObject: debug_e);
然后检查标记为message
字符串的Stackdriver UI 中的日志以查看输出
【讨论】:
【参考方案4】:您可以编写一个测试函数,将模拟事件传递给您的触发函数。这是一个测试onEdit()
触发函数的示例。它传递一个事件对象,其中包含Understanding Events 中为“电子表格编辑事件”描述的所有信息。
要使用它,请在目标 onEdit
函数中设置断点,选择函数 test_onEdit
并点击 Debug
。
/**
* Test function for onEdit. Passes an event object to simulate an edit to
* a cell in a spreadsheet.
*
* Check for updates: https://***.com/a/16089067/1677912
*
* See https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events
*/
function test_onEdit()
onEdit(
user : Session.getActiveUser().getEmail(),
source : SpreadsheetApp.getActiveSpreadsheet(),
range : SpreadsheetApp.getActiveSpreadsheet().getActiveCell(),
value : SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue(),
authMode : "LIMITED"
);
如果您很好奇,这是为了测试 onEdit
的 Google Spreadsheet conditional on three cells 函数而编写的。
这是电子表格表单提交事件的测试函数。它通过读取表单提交数据来构建其模拟事件。这最初是为Getting TypeError in onFormSubmit trigger? 编写的。
/**
* Test function for Spreadsheet Form Submit trigger functions.
* Loops through content of sheet, creating simulated Form Submit Events.
*
* Check for updates: https://***.com/a/16089067/1677912
*
* See https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events
*/
function test_onFormSubmit()
var dataRange = SpreadsheetApp.getActiveSheet().getDataRange();
var data = dataRange.getValues();
var headers = data[0];
// Start at row 1, skipping headers in row 0
for (var row=1; row < data.length; row++)
var e = ;
e.values = data[row].filter(Boolean); // filter: https://***.com/a/19888749
e.range = dataRange.offset(row,0,1,data[0].length);
e.namedValues = ;
// Loop through headers to create namedValues object
// NOTE: all namedValues are arrays.
for (var col=0; col<headers.length; col++)
e.namedValues[headers[col]] = [data[row][col]];
// Pass the simulated event to onFormSubmit
onFormSubmit(e);
提示
模拟事件时,注意尽可能匹配记录的事件对象。
如果您希望验证文档,您可以从触发函数记录接收到的事件。
Logger.log( JSON.stringify( e , null, 2 ) );
在电子表格表单提交事件中:
所有 namedValues 值都是数组。 时间戳是字符串,它们的格式将本地化为表单的区域设置。如果从具有默认格式* 的电子表格中读取,它们是 Date 对象。如果您的触发函数依赖于时间戳的字符串格式(这是一个坏主意),请注意确保正确模拟该值。 如果您的电子表格中有不在表单中的列,则此脚本中的技术将模拟一个包含这些附加值的“事件”,这不是您从表单提交中收到的。 如Issue 4335 中所述,values
数组会跳过空白答案(在“新表单”+“新工作表”中)。 filter(Boolean)
方法用于模拟这种行为。
*格式化为“纯文本”的单元格会将日期保留为字符串,这不是一个好主意。
【讨论】:
@Mogsdad :感谢您注意到数组的事情......我相应地更新了我的脚本;-) 顺便说一句,我忘了提到我从你那里得到了这个想法,但这篇文章是这样的无论如何,它不会改变你的生活,不是吗?XD 对此感到抱歉,遗漏已修复 ;-) @Sergeinsas - 我发誓这些值并不总是数组,也许它们会随着新的表格而改变?或者也许我正在以适用于数组的方式使用它们,例如indexOf() 搜索。无论如何,最好把它做好。 我使用的表单提交模拟在没有数组的情况下工作得很好......它仍然可以使用它而没有明显的差异。我检查了另一个脚本,我在其中编写了真实表单的 Logger 结果,但没有看到数组括号,所以有两种可能性:1 我没有戴眼镜 - 2 没有括号......我不能确定哪一个是真的;-) test_onEdit,当从 GScript IDE 运行/调试时,给出错误:“请先选择一个活动工作表”。我尝试打开一个电子表格并在 test_onEdit 中设置一个活动工作表,但同样的错误会在调用 onEdit 时停止执行。我错过了一个初步步骤吗? JSON.stringify(e) = 真棒!以上是关于如何在 GAS 中测试触发功能?的主要内容,如果未能解决你的问题,请参考以下文章