What steps are involved in setting up a Typescript-based custom Jest environment?

Currently, I am attempting to develop an extension based on jest-node-environment as a CustomTestEnvironment. However, I encountered an error when trying to execute jest:

● Test suite failed to run

    ~/git/my-application/tests/environment/custom-test-environment.ts:1
    import NodeEnvironment from 'jest-environment-node';
    ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      at runTestInternal (../node_modules/jest-runner/build/runTest.js:226:5)

It seems that the issue stems from the file not being recognized as TypeScript or properly transpiled. Even with the latest version of jest 26.0.1, the error persists.

Discussions on the jest GitHub revealed that the fix was intended for Jest 26 but deferred to Jest 27. https://github.com/facebook/jest/pull/8751

Although there are online examples suggesting a workaround, my attempts have been unsuccessful.

import NodeEnvironment from "jest-environment-node";
import {LocalObject} from "./object/local-object.helper";

export class CustomTestEnvironment extends NodeEnvironment {

    public async setup(): Promise<void> {
        await super.setup();
        this.global.localObject = LocalObject.init()
    }

    public async teardown(): Promise<void> {
        LocalObject.teardown(this.global.localObject)
        await super.teardown();
    }
}

The purpose of the LocalObject is to encapsulate a test utility with complex initialization and cleanup processes meant to provide test data and trigger component testing.

When attempting to switch the imports to require statements -

const NodeEnvironment = require("jest-environment-node");
const {LocalObject} =  require("./object/local-object.helper");

A new error emerges -

SyntaxError: Unexpected token 'export'

Further adjustments like using module.exports or altering syntax lead to different errors, indicating a persistent TypeScript recognition issue.

Is there any viable solution to utilize this as a TypeScript file? Since the LocalObject is defined in TypeScript, maintaining its integrity is crucial for proper usage within test files.

Alternatively, is it feasible to implement similar setup/teardown logic in the setupFilesAfterEnv section after tests execution? I only observed they are executed before tests. Thank you.

Answer №1

UPDATE: The latest release of Jest, version 27, now includes support for CustomEnvironment in typescript. If you are using an older version of Jest, it is recommended to update to Jest 27. More information can be found at https://jestjs.io/blog/2021/05/25/jest-27#features-coming-with-breaking-changes

Modules used in the following configuration options are now transformed like the rest of your code, which may lead to breaking changes if you relied on them being loaded as-is:

  • testEnvironment
  • runner
  • testRunner
  • snapshotResolver

Alternatively, for older versions of Jest, you can follow the workaround detailed below.


Note that this feature is not supported in Jest 26 and is expected to be included in Jest 27. More details can be found at https://github.com/facebook/jest/pull/8751#issuecomment-699049851

For now, a solution is to utilize setupFilesAfterEnv in the jest.config file. Refer to https://jestjs.io/docs/en/configuration#setupfilesafterenv-array for more information.

With this approach, you can organize your setup and teardown operations within beforeAll() and afterAll() blocks. This method is similar to using the Node Environment and is compatible with typescript.

//jest.setup.ts
import {LocalObject} from "./object/local-object.helper";

let localObject: LocalObject;

beforeAll(async () => {
  //Initialize environment or seed data to DB
  localObject = await LocalObject.init()
}


afterAll(async () => {
  //Teardown or clean up actions performed during environment setup
  await localObject.teardown()
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to employ data binding for extracting a user-input value and performing multiplication operations with the enclosed {{ ...}} tags

My API response includes the price of a product, which is represented as {{price}} I have a system where I can add or reduce the number of products: <div class="number-input"> <h2>Price: {{price }}</h2> <button oncli ...

React Native: Implementing scroll-based header animations in ScrollView

Currently, I am working on implementing an animated header with ScrollView on the screen. In this implementation, I need to set my view based on the Y position of the ScrollView during scrolling. This is how it's done: const onScroll = ({ nativeEvent: ...

Troubleshooting intersecting objects in THREE.js

Having trouble detecting intersections of extruded objects in THREE.js. The objects are created from a 2D geometry as shown below: var geoShape = new THREE.Shape(vertexes); var geometry = new THREE.ExtrudeGeometry(geoShape, { bevelEnabled: false, amount: ...

Encountering an error stating that 'coordinates should consist of an array with two or more positions'

Utilizing turf.js to generate a line depicting the path of an individual while their location is tracked. An array of coordinate arrays resembling Turf.js (lineString) is causing this error: Uncaught Error: coordinates must be an array of two or more posi ...

How to disable or enable a submit button in jQuery 1.8

Recently, I upgraded from jquery version 1.5.2 to 1.9 and encountered an issue with my disabled buttons not functioning properly. The buttons should become enabled after the form fields are filled out, allowing the user to either remove or save the infor ...

Boundaries on Maps: A guide to verifying addresses within a boundary

User provides address on the website. If the address falls within the defined boundary, it is marked as "Eligible". If outside the boundary, labeled as "Ineligible". Are there any existing widgets or code snippets available to achieve this functio ...

Encountering a no-loops/no-loops eslint error in node.js code while attempting to utilize the for and for-of loops

While working on my nodejs application, I have encountered an issue with es-lint giving linting errors for using 'for' and 'for-of' loops. The error message states error loops are not allowed no-loops/no-loops. Below is the snippet of c ...

Is there a way to implement field validation in a Vue wizard form?

Trying to implement form validation using Joi in a Vue wizard form, but not sure how to set it up correctly. The objective is to control the fields before progressing to the next and final page using the next() method. I want to keep the simplicity of th ...

Browser tries to interpret Javascript code as a file organization system

Encountering an issue while trying to load my website. When I open index.html in my browser, I receive a problem loading page message. This response is puzzling as it does not indicate a file loading error. Here's a snippet of the response: Firefox c ...

Deciphering the Syntax of React Functional Components

Seeking guidance as a ReactJS novice working through the react docs. I've hit a snag trying to understand and implement an example provided in the documentation. Can anyone please lend a hand in helping me spot my mistake?https://i.sstatic.net/DwlXp.p ...

Is getElementById in JavaScript reliable for multiple calls?

I am attempting to create a table cell that transforms into a textbox upon clicking, allowing for input to be entered and then displayed in the cell. Below is my JavaScript function: $(".cellConsigne").click(function () { var numId = this.id.substrin ...

Steps for deactivating jQuery slider control until radio button is selected:

Looking to deactivate the operation of jQuery UI sliders until a radio button is selected. Despite my efforts, I have been unsuccessful in achieving this task and could use some guidance. For reference, here is a link to the code: http://jsfiddle.net/nlem3 ...

limit the data types of values within an object using Typescript

When working with typescript, how can I define the type signature for a plain old javascript object that allows any key, but restricts the values to strings only? For example, {a:"foo"} and {b:"bar"} are considered valid values, while {a:[1,2,3]} and {b:3} ...

Is there a way to access URL parameters in the back-end using Node.js?

How can I extract querystring parameters email, job, and source from the following URL? I want to use these parameters in my service class: @Injectable() export class TesteService{ constructor(){} async fetchDataFromUrl(urlSite: URL){ ...

Can you identify the issue with my database file?

Here is the content from my database.js file: const MongoClient = require('mongodb').MongoClient; const db = function(){ return MongoClient.connect('mongodb://localhost:27017/users', (err, database) => { if (err) return co ...

npm ERROR: Unable to install the package named "<packageName>" because it conflicts with an existing package of the same name

Currently, I am attempting to incorporate the jsonfile package into my project. However, I am encountering a couple of errors: An issue arises when attempting to install a package with the same name as another package within the same directory. (Despite ...

The webpage fails to return to its original position after the script has been executed

My website has a sticky div that stays at the top when scrolling down, but does not return to its original position when scrolling back up. Check out this example function fixDiv() { var $div = $("#navwrap"); if ($(window).scrollTop() > $div.data("top ...

A guide on utilizing getStaticProps to map a collection obtained from Strapi within a Next.js component

I'm currently following a tutorial on YouTube that teaches how to create a basic blog using Next.js and Strapi. The code snippet below is used to fetch post data from Strapi, but it's not working as expected because the .map function can only be ...

When utilizing RxJS, the process of filtering Observable data may not function as expected if the filtering is carried out within a separate function rather than directly within the subscribe

While attempting to filter data from an external source using the RxJS filter on Observables, I encountered an issue where all records were returned instead of just the ones meeting the filtering criteria. This problem occurred when the code was within a l ...

Link a timestamp to a datetime-local input using ng-model

My challenge is to display an <input type="datetime-local> field using the ng-model attribute to represent a timestamp: <input type="datetime-local" ng-model="object.value"> This is being achieved with: $scope.object.value = 1433109600000; ...