Skip to content

Instantly share code, notes, and snippets.

@gclaussn
Last active January 14, 2023 16:35
Show Gist options
  • Save gclaussn/fcc17d7e5e0c8c6c8c0bc78070f7e8c2 to your computer and use it in GitHub Desktop.
Save gclaussn/fcc17d7e5e0c8c6c8c0bc78070f7e8c2 to your computer and use it in GitHub Desktop.
Node.js - Test JavaScript function without export

How to test a JavaScript function that is not exported?

This example can be used to test functions in Google Apps Script code. It uses the Node.js VM module to create an ad hoc script, which consists of the function's code to be tested as well as an invocation of the function to be evaluated. The result of the script is returned by execute and can be asserted afterwards.

If the function uses global objects (e.g. DriveApp, SpreadsheetApp or GmailApp), stub implementations can be provided as context for the script execution.

import chai from "chai";
import fs from "fs";
import vm from "vm";

const expect = chai.expect;

const code = fs.readFileSync("./backend/code.js", "utf8");

function execute(functionName, args = [], ctx = {}) {
  // "myFunction", ["test", true, 123] -> "arg0,arg1,arg2"
  let argsExpr = "";

  // "myFunction", ["test", true, 123] -> {arg0: "test", arg1: true, arg2: 123}
  const context = Object.assign({}, ctx);

  for (let i = 0; i < args.length; i++) {
    argsExpr += (i != 0 ? "," : "") + "arg" + i;
    context["arg" + i] = args[i];
  }

  // "myFunction", ["test", true, 123] -> myFunction(arg0,arg1,arg2);
  return new vm.Script(`${code}\n${functionName}(${argsExpr});`).runInNewContext(context);
}

describe("code", () => {
  it("should parse and sort list", () => {
    const genres = execute("parseAndSort", ["z,y,x"]);
    expect(genres).to.have.lengthOf(3);
    expect(genres[0]).to.equal("x");
    expect(genres[1]).to.equal("y");
    expect(genres[2]).to.equal("z");
  });
  
  it("should throw an error, if desired file does not exist", () => {
    const DriveApp = stubDriveAppWithoutFiles();

    expect(() => execute("getFile", [], { DriveApp })).to.throw();
  });
});

function stubDriveAppWithoutFiles() {
  const files = {
    hasNext: () => false
  };

  return {
    getRootFolder: () => {
      return {
        getFilesByName: () => {
          return files;
        }
      };
    }
  };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment