Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

166
Views
Mocha finds global variable is undefined when extended by class

I have the following ES6 module from a Chromecast receiver that I would like to test using Mocha...

// SUT - app.js
import { Queue } from 'queue.js'
export const app = async () => {
  const context = cast.framework.CastReceiverContext.getInstance();
  const options = {};
  options.queue = new Queue();
  context.start(options);
}

This code runs inside a Chromecast user agent which provides access to the global cast object. This cast object exposes an api which in turn enables the JS thread to interact directly with the Chromecast CAF SDK. This cast variable is always available at run time.

The Queue class is slightly unusual because in order for it to work according to the CAF framework documentation, is must extend an abstract class from the framework cast.framework.QueueBase...

// queue.js
class Queue extends cast.framework.QueueBase {
  initialize(){
    // build queue here
  }
}

Now I would like to write some unit tests to check my app function is correct. For example:

// app.test.js
import { app } from 'app.js';
it('should do some stuff', async function () {
  // inject a mock cast object
  global.cast = {
    framework: {
      QueueBase: class {},
      CastReceiverContext: {
        getInstance: () => {},
      },
    },
  };
  await app();
  // Make some assertions
});

However, even though I am injecting a mock using global.cast, which is sufficient for all regular references to the cast object, in the case where a class is extending the injected cast object, apparently it is not yet available and I receive the following error:

ReferenceError: cast is not defined

I found an ugly hack to make this error disappear. If I place the following snippet above the class declaration then I can inject the mock at runtime and it not only works for Mocha but also for execution on the Chromecast device....

try {
  // The following line throws in Mocha's node environment
  // but executes fine on the Chromecast device
  if (cast) {
  }
} catch {
  global.cast = {
    framework: {
      QueueBase: class {},
    },
  };
}

export class Queue extends cast.framework.QueueBase {
...

However, I would like to find a better solution so that I don't have to pollute my production code with this hack which is only there to allow me to run tests.

My .mocharc.yml file looks like this:

require:
  - '@babel/register'
  - 'ignore-styles'
  - 'jsdom-global/register'
  - 'babel-polyfill'

... and my command to run tests is:

mocha --recursive --use_strict

finally, my .babelrc file looks like this:

{
    "presets": [
        [
            "@babel/preset-env"
        ]
    ],
    "plugins": [
        "inline-svg",
        "import-graphql"
    ]
}
about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

Static imports are always evaluated first, so the order of operations is roughly:

import { Queue } from 'queue.js'
class Queue extends cast.framework.QueueBase { // ReferenceError outside Chromecast!
  initialize(){
    // build queue here
  }
}
global.cast = {
    framework: {
      QueueBase: class {},
      CastReceiverContext: {
        getInstance: () => {},
      },
    },
  };

You can see that the mock is created after the reference to cast in app.js.

The only reliable way to run the mock creation before importing the app module is using a dynamic import:

// app.test.js
it('should do some stuff', async function () {
  // inject a mock cast object
  global.cast = {
    framework: {
      QueueBase: class {},
      CastReceiverContext: {
        getInstance: () => {},
      },
    },
  };
  const { app } = await import('app.js');
  await app();
  // Make some assertions
  delete global.cast;
});

If you prefer not to repeat the mock creation and the import in every test, you can move both out of the test definition:

// app.test.js
// inject a mock cast object
global.cast = {
  framework: {
    QueueBase: class {},
    CastReceiverContext: {
      getInstance: () => {},
    },
  },
};
const { app } = await import('app.js');
it('should do some stuff', async function () {
  await app();
  // Make some assertions
});
// Optionally clean up the mock after all tests
after(() => delete global.cast);
about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!