17

I need to enable some global variables to be reachable for my test so I am setting up a Custom Environment to be used in the testEnvironment option in my jest.config.json to achieve that.

For our project we have a TypeScript file that we use for setupFilesAfterEnv option and that works just fine, however the testEnvironment seems to support only ES5. Is there any way to use TypeScript in such option?

I successfully created a Custom Jest Environment using ES5 syntax, however since we are injecting global variables I need TypeScript to also declare a global namespace see: https://stackoverflow.com/a/42304473/4655076.

{
  ///...
  setupFilesAfterEnv: ['<rootDir>/test/setup.ts'], // This works with ts
  testEnvironment: '<rootDir>/test/customJestEnvironment.ts', // This doesn't work with ts
}
Andres C. Viesca
  • 332
  • 5
  • 19

5 Answers5

1

You might find this helpful: Configure Jest global tests setup with .ts file (TypeScript)

But basically you can only pass in compiled JS files as environments.

You can do what that article suggests. But it didn't work for me out of the box. So I manually compile my env.

i.e.

in package.json

"test": "tsc --lib es6 --target es6 --skipLibCheck -m commonjs --esModuleInterop true path/to/env.ts && 
jest --config=jest.config.js",

And in jest.config.js

{
  testEnvironment: '<rootDir>/path/to/env.js', // Note JS extension.
}
McTrafik
  • 2,843
  • 3
  • 29
  • 31
1

I solved this by using ts-node and the following command:

node -r ts-node/register ./node_modules/jest/bin/jest.js

This essentially compiles the typescript on-the-fly, so that jest receives the emitted javascript, without the need of actually compiling your typescript sources to js.

You will need to enable esModuleInterop TS compiler option for this to work properly.

TestEnvironment.ts


import NodeEnvironment from 'jest-environment-node';
import type {Config} from '@jest/types';

class TestEnvironment extends NodeEnvironment {
    
    constructor(config: Config.ProjectConfig) {
        super(config);
        // this.testPath = context.testPath;
        // this.docblockPragmas = context.docblockPragmas;
    }

    public async setup(): Promise<void> {
        await super.setup();

        console.log('SETTING UP...');
        // await someSetupTasks(this.testPath);
        // this.global.someGlobalObject = createGlobalObject();
    
        // // Will trigger if docblock contains @my-custom-pragma my-pragma-value
        // if (this.docblockPragmas['my-custom-pragma'] === 'my-pragma-value') {
        //   // ...
        // }
    }

    public async teardown(): Promise<void> {
        await super.teardown();
        console.log('TEARING DOWN!');
        // this.global.someGlobalObject = destroyGlobalObject();
        // await someTeardownTasks();
        
    }
}

export default TestEnvironment;

This solution however, will break globalSetup -- if you use jest-ts.

Norman Breau
  • 2,132
  • 16
  • 35
0

As you might know, typescript files are just superset to javascript to provide strong type checking. Jest's engine/runtime however expects your files in CommonJS format javascript files.

You can have a separate tsconfig.env.json just for this env.ts. Compile this before running jest test and use the compiled env.js in your jest.config.js.

tsc -p tsconfig.env.json && jest

Also i have never seen people writing configuration files in TS.

why CommonJS ? because jest is essentially running on top of node. node supports Javascript files in CommonJS format. Node has started supporting es modules as well recently! This is a big thing!

-1

You can create a global.d.ts file at the root of your project.

Then you can define global variables as seen below. In my case, it was a NestJS application, but you can define anything.

declare global {
  namespace NodeJS {
    interface Global {
      app: INestApplication;
    }
  }
}

This is another example for client project where we define window properties like innerWidth;

declare namespace NodeJS {
    interface Global {
        innerWidth: number;
        dispatchEvent: Function;
    }
}
  • 1
    The need is to be able to set these variables, not just declare types. The question id basically how to have a environment.ts for Jest. – Kai Sellgren Feb 24 '20 at 18:32
-1

Inside your .d.ts definition file:

type MyGlobalFunctionType = (name: string) => void

Add members to the browser's window context:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

Same for NodeJS:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}

Now you declare the root variable

declare const myGlobalFunction: MyGlobalFunctionType;

Then in a regular .ts file, but imported as side-effect, you actually implement it:

global/* or window */.myGlobalFunction = function (name: string) {
  console.log("Hey !", name);
};

And finally use it elsewhere :

global/* or window */.myGlobalFunction("Ayush");

myGlobalFunction("Ayush");
  • Thank you for the hacky solution to achieve function sharing across tests. The question is about how to write an environment using TypeScript. I.e. setupFile but global. – McTrafik Apr 28 '20 at 20:21