Google Apps脚本支持Triggers,通过Events来触发功能。不幸的是,开发环境将允许您在没有参数传递的情况下测试函数,因此您无法以这种方式模拟事件。如果您尝试,则会收到如下错误:
ReferenceError:未定义'e'。
可以将事件视为可选参数,并使用“Is there a better way to do optional function parameters in JavaScript?”中的任何技术将默认值插入触发器函数。但这会带来一种风险,即一个懒惰的程序员(如果那就是你那么举手!)会留下那些代码,并带来意想不到的副作用。
当然有更好的方法吗?
答案 0 :(得分:70)
您可以编写一个测试函数,将模拟事件传递给触发函数。这是一个测试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://stackoverflow.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"
});
}
如果您感到好奇,可以编写这个来测试Google Spreadsheet conditional on three cells的onEdit
函数。
这是电子表格表格提交事件的测试功能。它通过读取表单提交数据来构建其模拟事件。这最初是为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://stackoverflow.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://stackoverflow.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 ) );
在电子表格表单提交事件中:
values
数组会跳过空白答案(在“新表单”+“新表格”中)。 filter(Boolean)
方法用于模拟此行为。* 单元格格式化的“纯文本”会将日期保留为字符串,并不是一个好主意。
答案 1 :(得分:5)
2017年更新:
针对Google Apps脚本使用Event objects调试Stackdriver Logging。从脚本编辑器的菜单栏中,转到:
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中的日志以查看输出
答案 2 :(得分:4)
您无需使用先前答案中建议的任何模拟事件。
如问题中所述,如果您直接在脚本编辑器中“运行”该函数,则错误类似
TypeError:无法从未定义中读取属性 ...
被抛出。这些不是真正的错误。此错误仅是因为您运行的函数没有事件。如果您的功能与预期不符,则需要找出实际错误:
要测试触发功能,
手动触发相应的事件:即,要测试onEdit
,请在工作表中编辑一个单元格;要测试onFormSubmit
,请提交伪表单响应。要测试doGet
,请在浏览器中导航到发布的Web应用程序/exec
网址。
如果有任何错误,它将记录到stackdriver。要查看这些日志,
在脚本编辑器中>“视图”>“执行”。
或者,单击here>单击您感兴趣的项目>在“项目详细信息”仪表板中>在右上方,单击三个点菜单>单击“执行”
您将在执行页面中找到执行列表。确保清除所有过滤器,例如左上方的“ Ran as:Me”,以显示所有执行。单击您感兴趣的执行,它将以红色显示导致触发器失败的错误。
注意:有时,由于错误,日志不可见。尤其是在Webapp由匿名用户运行的情况下。在这种情况下,建议将默认Google云项目切换到标准Google云项目,并直接使用“查看”>“堆栈驱动程序”日志记录。有关更多信息,请参见here。
console.log(/*object you're interested in*/)
,以查看该对象的详细信息。强烈建议您对要查找的对象进行字符串化处理:console.log(JSON.stringify(e))
,因为日志查看器具有特质。添加console.log()
之后,请从步骤1开始重复。重复此循环,直到缩小问题范围为止。恭喜!您已经成功解决了问题,并且越过了第一个障碍。
答案 3 :(得分:0)
作为对第 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()) ;
}