Testing whether script is being run by interactive debugger

Viewed 60

I have a project that reads a Google Sheets spreadsheet and maintains a summary of contents in another sheet. All the hooks are in place to run as needed (daily, weekly, whatever), starting where it last left off, and the unprocessed rows will affect the summary.

In case the summary sheet ever needs to be wiped out and all data reprocessed, I have added a menu option for reinitialization. Within that reinitialization function there is dialog:

    var ui = SpreadsheetApp.getUi();
    var result = ui.alert(
          "Please confirm"
        , "This will completely wipe out the summary data and start over, and may require many executions in order to catch up.  Are you sure you want to do this?"
        , ui.ButtonSet.YES_NO
          );
    if (result == ui.Button.NO) {
        ui.alert("Good thing I asked!");
        return;
        }

(This happens only when there are design changes to the summary.)

If I am running this process in the scripts debugger, the process dies with the message:

Exception: Cannot call SpreadsheetApp.getUi() from this context.

So I would like to avoid that part of the code when debugging. How can I determine if the script is being run in that mode?

2 Answers

Explanation:

I guess a straightforward solution would be to try...catch the error.

  • If you want to check for a specific error message, you can use the error property message which returns the error as a string.

  • If the error message is the expected error, namely: Cannot call SpreadsheetApp.getUi() from this context then continue with the rest of the code.

  • If the error is something else (within the try statement) then throw that unexpected error and stop the script.

Workaround Solution 1:

   try {
    var ui = SpreadsheetApp.getUi();
    var result = ui.alert(
          "Please confirm"
        , "This will completely wipe out the summary data and start over, and may require many executions in order to catch up.  Are you sure you want to do this?"
        , ui.ButtonSet.YES_NO
          );
    if (result == ui.Button.NO) {
        ui.alert("Good thing I asked!");
        return;
        }       
   }
   catch(e){
      if(e.message=="Cannot call SpreadsheetApp.getUi() from this context"){
      console.log("the expected error occured, everything is fine"); // the expected error occured, continue
      }
      else{throw e}; // throw the unexpected error and stop the script
   }
   
   // continue with the rest of the code with no issues

Workaround Solution 2:

I just stumbled upon this answer which might work for you. Essentially you can introduce a "debug" parameter within a function that encloses the "problematic" code and execute this code depending the "debug" parameter. Still that is a workaround solution which needs some manual intervention, therefore I would recommend the first solution of this answer which allows you to have full control of the error messages.

Based completely on @Marios' answer, I have created the following function to share in the event someone else runs into this problem. Note that the error message would be different in some other language.

To use it, copy/paste the getYesNo function below into your code. Then you can reference it as such:

if (getYesNo("It's wet down there", "Are you sure you want to jump off of this bridge?", false)) {
    jump();
    }

In the event that the dialog cannot be displayed, the default value will be returned. Here's the code:

function getYesNo(shorMessage, longMessage, defaultResult) {

    // We'll prompt the user if we can.  But in some instances (for example in a batch execution or a debug session)
    // we cannot do that.  If we run across that problem, we'll return the default value.

    var rtnValue = defaultResult;
    try {
          var ui = SpreadsheetApp.getUi();

          var result = ui.alert(
                shortMessage
              , longMessage
              , ui.ButtonSet.YES_NO
                );
          if (result == ui.Button.NO) rtnValue = false;
          else                        rtnValue = true;
          }
    catch(e) {
          if (e.message.indexOf("Cannot call SpreadsheetApp.getUi() from this context.") >= 0) {
                console.log("Expected error about dialog was received.  All is well: "
                          + e.message)
                           );
                }
          else throw e;
          }
    return rtnValue
    }

Thanks @Marios

Related