Single instance modules in JavaScript (TypeScript)

Viewed 24

I'm trying to define a simple assertion package in TypeScript so that assertions can be turned off during efficiency testing (and production eventually). Here's my attempt for a simple module:

let assertionsEnabled = true;

export function withAssertions<T>(val : boolean, body : () => T) : T {
    const savedEnabled = assertionsEnabled;
    try {
        assertionsEnabled = val;
        return body();
    } finally {
        assertionsEnabled = savedEnabled;
    }
}

export function assert(condition : () => boolean, message ?: string) {
    if (assertionsEnabled) {
        if (!condition()) {
            throw new Error("assertion failed" + (message ?? ""));
        }
    }
}

The problem is that both the Jest test and the class being tested each import this module and they seem to end up with two different assertionsEnabled variables. My test is encoded with

describe('building', () => {
    withAssertions(false, () => {
        ...
    });
});

and in the ADT, I have a bunch of assertions, but even though assertions are turned off in the Jest test, they are still on in the ADT. I thought modules were supposed to have a single instance. But obviously I'm doing something wrong.

1 Answers

I'm betting you have asynchronous stuff going on in your tests or stuff you instantiate as part of exporting from the module and it's happening before the jest stuff starts being executed.

Also, you might instead want to do a describeWithAssertion function instead, like so...

function describeWithAssertion(
  ae: boolean,
  title: string,
  f: any // this should be specified better
) {
  const prevAE = assertionsEnabled;
  return describe(
    title,
    () => {
      beforeEach(() => assertionsEnabled = ae);
      afterEach(() => assertionsEnabled = prevAE);
      f();
    }
  );
}

This way, even if f contains async functionality, jest is worrying about it, not you.

Related