【问题标题】:Installable Trigger Failing with Test Add-On可安装触发器因测试插件失败
【发布时间】:2015-06-25 15:03:34
【问题描述】:

这几天我一直在努力解决一个可安装的触发器问题。我所有的研究都表明,附加组件应该允许在电子表格中安装可安装的 onEdit() 触发器,但我的尝试不断出错。我已经稍微简化了我的项目代码来举例说明我的问题。

错误信息:

执行失败:测试插件尝试执行不允许的操作。

我的代码(列出函数是它们被调用的顺序):

   function onOpen() //creates custom menu for the evaluation tool ***FOR ADMININSTRATORS ONLY***
{ 

  var ui = SpreadsheetApp.getUi();

  if(!PropertiesService.getDocumentProperties().getProperty('initialized'))
  {
    ui.createMenu('Evaluation Menu') // Menu Title
      .addItem('Create Installable OnEdit Trigger', 'createInstallableOnEditTrigger')
    .addToUi();
  }
  else
  {
    ui.createMenu('Evaluation Menu') // Menu Title
      .addSubMenu(ui.createMenu('Manage Observations & Evidence')
           .addSubMenu(ui.createMenu('Create New Observation')
               .addItem('Formal', 'createNewFormalObservation')
               .addItem('Informal', 'createNewInformalObservation')
            )          
      .addToUi();    
  }
}


function createInstallableOnEditTrigger() { // installable trigger to create employee look-up listener when user edits the EIN fields on the Documentation Sheet.
  var ss = SpreadsheetApp.getActive();
  ScriptApp.newTrigger('onEditListener')
      .forSpreadsheet(ss)
      .onOpen()
      .create();

  PropertiesService.getDocumentProperties().setProperty('initialized','true');
}

function onEditListener(event) //this function conitnually listens to all edit, but only engages only certain conditions such as when a timestamp is determined to be needed or the Documentation Sheet needs to be auto-populated
{
  //Determine whether or not the conditions are correct for continuing this function
  var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName(); //determines the name of the currently active sheet

  if (sheetName.indexOf("Evidence") > -1) // if the active sheet is an evidence collection sheet, a timestamp may be needed
  {
    populateEvidenceTimeStamp(event, sheetName);
  }
  else if (sheetName == "Documentation Sheet") //if the active sheet is the "Documentation Sheet" than auto-population and EIN lookups may be needed
  {
    employeeLookup(event, sheetName);
  }
}

我错过了什么?非常感谢任何帮助!

以下代码已根据@Mogsdad 的要求添加。

populateEvidenceTimeStamp() 依赖于 generateTimeStamp(),它也包含在下面:

function populateEvidenceTimeStamp(event, sheetName)
{
  var evidenceColumnName = "Evidence"; 
  var timeStampColumnName = "Timestamp";
  var sheet = event.source.getSheetByName(sheetName);

  var actRng = event.source.getActiveRange();
  var indexOfColumnBeingEdited = actRng.getColumn();
  var indexOfRowBeingEdited = actRng.getRowIndex();
  var columnHeadersArr = sheet.getRange(3, 1, 1, sheet.getLastColumn()).getValues(); // grabs the column headers found in the 3rd row of the evidence sheet

  var timeStampColumnIndex = columnHeadersArr[0].indexOf(timeStampColumnName); //determines the index of the Timestamp column based on its title
  var evidenceColumnIndex = columnHeadersArr[0].indexOf(evidenceColumnName); evidenceColumnIndex = evidenceColumnIndex+1; //determines the index of the evidence column based on its title
  var cell = sheet.getRange(indexOfRowBeingEdited, timeStampColumnIndex + 1); //determines the individual timestap cell that will be updated

  if (timeStampColumnIndex > -1 && indexOfRowBeingEdited > 3 && indexOfColumnBeingEdited == evidenceColumnIndex && cell.getValue() == "") // only create a timestamp if 1) the timeStampColumn exists, 2) you are not actually editing the row containing the column headers and 3) there isn't already a timestamp in the Timestamp column for that row
  {
    cell.setValue(generateTimeStamp());
  }
}

function generateTimeStamp()
{
  var timezone = "GMT-7"; // Arizona's time zone
  var timestamp_format = "MM.dd.yyyy  hh:mm:ss a"; // timestamp format based on the Java SE SimpleDateFormat class. http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html 
  var currTimeStamp = Utilities.formatDate(new Date(), timezone, timestamp_format);  
  return currTimeStamp;  
}

下面是依赖于lookupEIN()的employeeLookup()函数

function employeeLookup(event, sheetName)
{
  if(sheetName == "Documentation Sheet" && !PropertiesService.getDocumentProperties().getProperty('initialized')) // if the activeSheet is "Documentation Sheet" and the sheet has not yet been initialized
  {
    var actRng = event.source.getActiveRange();
    Logger.log("employeeLookup(): actRng: "+actRng.getRow()+" , "+actRng.getColumn());
    if(actRng.getRow() == 4 && actRng.getColumn() == 9 && event.source.getActiveRange().getValue() != "") //if the "Teacher EIN" cell is the active range and it's not empty
    { 
      var ein = actRng.getValue();
      clearDocumentationSheetTeacherProfile(); //first clear the teacher profile information to avoid the possibility of EIN/Teacher Info mismatch if previous search did not yield results
      var teacherDataArr = lookupEIN(ein, "Teachers");
      if(teacherDataArr)
      {
        //write retrieved teacher data to Documentation Spreadsheet
        var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Documentation Sheet");
        sheet.getRange(5, 9, 1, 1).setValue(teacherDataArr[1]); // Teacher First Name
        sheet.getRange(6, 9, 1, 1).setValue(teacherDataArr[2]); // Teacher Last Name
        sheet.getRange(7, 9, 1, 1).setValue(teacherDataArr[3]); // Teacher Email 

        sheet.getRange(11, 9, 1, 1).setValue(teacherDataArr[4]); // School Name
        sheet.getRange(11, 39, 1, 1).setValue(teacherDataArr[5]); // Site Code
        sheet.getRange(10, 30, 1, 1).setValue(calculateSchoolYear()); //School Year
      }
      else
      {
        Logger.log("employeeLookup(): type:Teachers 'died. lookupEIN() did not return a valid array'"); //alert message already sent by lookUpEIN
      }
    }
    else if (actRng.getRow() == 4 && actRng.getColumn() == 30 && actRng.getValue() != "" && !PropertiesService.getDocumentProperties().getProperty('initialized')) //if the "Observer EIN" cell is the active range
    {
      Logger.log("employeeLookup(): 'active range is Observer EIN'");
      var ein = actRng.getValue();
      clearDocumentationSheetObserverProfile(); //first clear the teacher profile information to avoid the possibility of EIN/Observer Info mismatch if previous search did not yield results
      var observerDataArr = lookupEIN(ein, "Observers");
      if(observerDataArr)
      {
        //write retrieved observer data to Documentation Spreadsheet
        var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Documentation Sheet");
        sheet.getRange(5, 30, 1, 1).setValue(observerDataArr[1]); // Observer First Name
        sheet.getRange(6, 30, 1, 1).setValue(observerDataArr[2]); // Observer Last Name
        sheet.getRange(7, 30, 1, 1).setValue(observerDataArr[3]); // Observer Email 
      }
      else
      {
        Logger.log("employeeLookup(): type:Observers 'died. lookupEIN() did not return a valid array'"); //alert message already sent by lookUpEIN
      }
    }
    else
    {
      Logger.log("employeeLookup(): 'active range is not a trigger'");
      //do nothing (not the right cell)
    }
  }
  else
  {
    //Observer log has already been initialized and documentation cannot be altered. notify user
    Logger.log("employeeLookup(): 'log already saved.... alerting user'");
    logAlreadyInitializedDialogue();
    restoreDocumentationSheetData();
  }
}

function lookupEIN(ein, type)
{
  Logger.log ("lookUpEIN(): 'engaged'");
  var ss = SpreadsheetApp.openById(teacherObserverIndex_GID);
  var sheet = ss.getSheetByName(type); //lookup type aligns with the individual sheet names on the teacherObserverIndex_GID document
  var values = sheet.getDataRange().getValues();
  var val = sheet.getDataRange();

  for (var i = 1; i < values.length; i++)
  {
     if(values[i][0] == ein)
    {
      Logger.log ("lookUpEIN(): values[i]: "+values[i]);
      return values[i];
    }
    else
    { 
      Logger.log ("lookUpEIN(): 'no match found'");
    }
  }
  //a match could not be found 
  Logger.log("An EIN match could not be found"); // create a feedback pop-up
  einNotFoundDialogue(type); //alert user that there is a problem with the provided ein
}

【问题讨论】:

  • 1.我认为这是一个简单的触发器,所以您需要做的就是将函数命名为 onEdit();
  • 2.如果您使用的是测试附加功能,我会遇到一些问题,即它会在测试中失败,但在发布时可以工作。
  • populateEvidenceTimeStampemployeeLookup 是做什么的?
  • @BjornBehrendt ,该项目的早期版本使用简单的 onEdit() 而不是可安装的触发器,但会抛出以下错误:“执行失败:您无权执行该操作。 (第 136 行,文件“Helper Functions”)“它所指的行是:var ss = SpreadsheetApp.openById(teacherObserverIndex_GID);我已将此代码添加到我的原始帖子中。它可以在lookupEIN 函数中找到。
  • 我在原帖中添加了“populateEvidenceTimeStamp”和“employeeLookUp”函数,以及它们所依赖的函数。 @BjornBehrendt 谢谢你们的帮助!

标签: testing google-apps-script google-sheets triggers


【解决方案1】:

根据我的经验,onEdit() 不能作为附加组件进行测试。

我同意文档不清楚,它似乎仅指“可安装触发器”,但我认为它适用于所有触发器,除了在您开始测试后立即运行的“onInstall”触发器。 (详情请见:Testing Google Sheet Addon Triggers

【讨论】:

    【解决方案2】:

    将脚本作为 Test as add-on 运行时无法创建触发器。

    来自https://developers.google.com/apps-script/add-ons/test

    在测试附加组件时需要牢记以下几点:

    • 测试时当前不支持可安装触发器。 依赖于可安装触发器的功能将不会 可测试。

    一些可能的解决方法

    • 对于 on open 和 on edit 可安装触发器,临时添加简单触发器以调用可安装触发器的功能。这可能仅在 的执行时间小于简单触发器限制时才有效。
    • 从创建模拟相应事件对象的对象的函数中调用可安装触发器中的函数
    • 不要使用独立项目,而是使用有界项目。您可以使用CLASPGoogle Apps Script GitHub Assistant Chrome extension 之类的扩展名,以便更轻松地将代码从独立项目复制到有界项目。

    相关

    【讨论】:

    • 我迟到了,但一个很好的解决方法是将 onEdit 代码复制到脚本编辑器中,然后在测试时在那里处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多