How come ts-jest in jest is affecting my JavaScript files?

As a newcomer to using jest with ts-jest, I am facing an error that I can't quite comprehend:

$ jest
 FAIL  src/lib/Core/Storage/JsonStorage.test.ts
  ● Test suite failed to run

    Jest encountered an unexpected token

    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

    By default "node_modules" folder is ignored by transformers.

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
     • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/configuration
    For information about custom transformations, see:
    https://jestjs.io/docs/code-transformation

    Details:

    /app/src/lib/Core/Storage/JsonStorage.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import fs from 'fs/promises'
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import fs from 'fs/promises'
    > 2 | import JsonStorage from './JsonStorage'
        | ^
      3 | import type IStorage from './IStorage'
      4 |
      5 | jest.mock('fs/promises')

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1495:14)
      at Object.<anonymous> (src/lib/Core/Storage/JsonStorage.test.ts:2:1)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.235 s
Ran all test suites.

Presented below is the test I intend to carry out:

import fs from 'fs/promises'
import JsonStorage from './JsonStorage'
import type IStorage from './IStorage'

jest.mock('fs/promises')

describe('JsonStorage', () => {
  let storage: IStorage<object>

  beforeEach(() => {
    storage = new JsonStorage('')

    jest.resetAllMocks()
  })

  test('Storage json object to file', async () => {
    fs.writeFile = jest.fn()

    const data = {
      one: 'one',
      two: 'two',
    }
    const pathname = './mokefile.json'
    const json = '{"one":"one","two":"two"}'

    await storage.save(pathname, data)

    expect(fs.writeFile).toHaveBeenCalled()
    expect(fs.writeFile).toHaveBeenCalledWith(pathname, json, 'utf8')
  })
})

Below is the code I am testing:

import fs from 'fs/promises'
import type IStorage from './IStorage'

export default class JsonStorage<T = object> implements IStorage<T> {
  constructor(private _space: string) {}

  async save(pathname: string, data: T) {
    const json = JSON.stringify(data, null, this._space)

    await fs.writeFile(pathname, json, 'utf8')
  }
}

My tsconfig:

{
  "extends": "@tsconfig/node18/tsconfig.json",
  "compilerOptions": {
    "module": "es2022",
    "moduleResolution": "node",
    "baseUrl": ".",
    "paths": {
      "@App/*": ["./src/lib/*"],
      "@config/*": ["./src/config/*"]
    },
    "allowUnreachableCode": false,
    "allowUnusedLabels": false,
    "alwaysStrict": true,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitAny": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noPropertyAccessFromIndexSignature": false,
    "noUncheckedIndexedAccess": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "useUnknownInCatchVariables": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "watchOptions": {
    "watchFile": "useFsEvents",
    "watchDirectory": "useFsEvents",
    "fallbackPolling": "dynamicPriority",
    "synchronousWatchDirectory": true,
    "excludeDirectories": ["node_modules"]
  },
  "include": ["src", "bin", "index.ts"],
  "exclude": ["node_modules", "./**/*.test.ts"]
}

My jest.config.ts:

import { type JestConfigWithTsJest, pathsToModuleNameMapper } from 'ts-jest'
import { compilerOptions } from './tsconfig.json'

type ModuleNameMapper = Required<JestConfigWithTsJest>['moduleNameMapper']

const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths) as ModuleNameMapper

const jestConfig: JestConfigWithTsJest = {
  testEnvironment: 'node',
  preset: 'ts-jest/presets/default-esm',
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        useESM: true,
        isolatedModules: true,
        tsconfig: 'tsconfig.jest.json',
      },
    ],
  },
  transformIgnorePatterns: [
    '^.+\\.jsx?$',
  ],
  modulePaths: [compilerOptions.baseUrl],
  moduleNameMapper,
}

export default jestConfig

I am aware that tsc compiles files to the same location as the .ts files, leading to an error term -

/app/src/lib/Core/Storage/JsonStorage.js:1
, suggesting that it is imported into the test js file instead of the necessary TypeScript file. It seems that jest is not recognizing the ts files, and I am looking for a way to direct it to use the ts version without the need for babel:

module.exports = {
  // other config options...
  transform: {
    "^.+\\.tsx?$": "ts-jest",
    // add this line:
    "^.+\\.jsx?$": "babel-jest"
  }
};

I prefer not to involve babel and need to work with my ts files. How can I instruct jest to use the ts files instead of js?

Answer №1

To tackle this issue, I successfully resolved it by reordering the loading sequence of modules using browser extensions:

import { compilerOptions } from './tsconfig.json'

type ModuleNameMapper = Required<JestConfigWithTsJest>['moduleNameMapper']

const moduleNameMapper = pathsToModuleNameMapper(compilerOptions.paths) as ModuleNameMapper

const jestConfig: JestConfigWithTsJest = {
  ...
  // This particular line requires modification, as it currently states ["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"]
  moduleFileExtensions: ['ts', 'js', 'json', 'node'],
  ...
}

export default jestConfig

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

Utilize Firebase for Playwright to efficiently implement 'State Reuse' and 'Authentication Reuse'

In my testing environment, I want to eliminate the need for repeated login actions in each test run. My approach involves implementing 'Re-use state' and 'Re-use Authentication', but I've encountered a challenge with Firebase using ...

Adding a component to a page in Angular 4: A step-by-step guide

Currently engaged in a project that involves creating a mobile application design within a web application. I'm wondering how to display my Component object on a page using ViewChild? I have a list of PageComponents, below is the PageComponent class ...

The Angular template loads and renders even before the dynamic data is fetched

I'm encountering a frustrating issue where the page loads before the data is retrieved. When I log the names in $(document).ready(), everything appears correct without any errors in the console. However, the displayed html remains empty and only shows ...

Angular 8 fails to retain data upon page refresh

I have a property called "isAdmin" which is a boolean. It determines whether the user is logged in as an admin or a regular user. I'm using .net core 2.2 for the backend and Postgre for the database. Everything works fine, but when I refresh the page, ...

Guide on utilizing external namespaces to define types in TypeScript and TSX

In my current project, I am working with scripts from Google and Facebook (as well as other external scripts like Intercom) in TypeScript by loading them through a script tag. However, I have encountered issues with most of them because I do not have acces ...

Is there a specific type that is narrower in scope when based on a string parameter?

tgmlDoc.createElement(tagName) typically returns objects of type any. I am looking to refine the return type in the function below in order to simplify the rest of my code. Is there a way to accomplish this? My attempt is shown below, but unfortunately, ...

MQTT Broker specialized in Typescript

I'm looking to create a MQTT Broker using TypeScript and Angular. I've attempted a few examples, but I keep encountering the following error: Uncaught TypeError: http.createServer is not a function Here's a simple example of what I'm c ...

The Enigmatic Essence of TypeScript

I recently conducted a test using the TypeScript code below. When I ran console.log(this.userList);, the output remained the same both times. Is there something incorrect in my code? import { Component } from '@angular/core'; @Component({ sel ...

What is the most effective method for locating and modifying the initial instance of an element within a group?

In my Javascript/Typescript collection, I have the following items: [ {"order":1,"step":"abc:","status":true}, {"order":2,"step":"xyz","status":true}, {"order":3,"step":"dec","status":false}, {"order":4,"step":"pqr","status":false}, {"order":5,"step":" ...

The 'eventKey' argument does not match the 'string' parameter. This is because 'null' cannot be assigned to type 'string'

Encountering an issue while invoking a TypeScript function within a React Project. const handleLanguageChange = React.useCallback((eventKey: eventKey) => { setLanguage(eventKey); if(eventKey == "DE") setCurre ...

Whenever I attempt to execute yarn build within next.js, an error always seems to occur

When attempting to compile my next.js project using the yarn build command, an error consistently occurs: Error: Export encountered errors on following paths: /settings at D:\web3\futnft\frontend\node_modules\next\ ...

Exploring Angular: Looping through an Array of Objects

How can I extract and display values from a JSON object in a loop without using the keyValue pipe? Specifically, I am trying to access the "student2" data and display the name associated with it. Any suggestions on how to achieve this? Thank you for any h ...

The component 'Form' cannot be utilized in JSX because its return type, 'ReactNode', is not a valid JSX element

I'm facing an issue with my Next.js application written in TypeScript after updating react-bootstrap. After the update, I am encountering the following error when attempting to use the Form component from react-bootstrap: react-bootstrap: ^2.10.3 @typ ...

Utilize properties when selecting options in Storybook

Here is the interface I have specified: interface PropOptions{ type: 'dog' | 'cat' | 'mouse' | 'turtle' | 'rabbit' } export default PropOptions; Although the list of allowed string values is quite exte ...

Retrieve all the characteristics accessible of a particular course

I am facing a situation where I have the following class structure: class A { id: number propertyA: string constructor(id: number) { this.id = id } } let a = new A(3) console.log(SomeFunction(a)) // expected output = ['id', ' ...

What is the best way to swap out one component for another in a design?

I am working with a component that has the selector 'app-view', and I need to replace a specific part of the template: <div> content </div> The part that needs to be replaced will be substituted with another component: selector: &a ...

Issue: Module '/Users/MYNAME/Desktop/Projects/MYPROJECTNAME' not found

I am currently in the process of compiling Node using TypeScript, and I'm still getting acquainted with it. An issue I encountered was that my /src files were not being updated when I made changes and restarted the server. To troubleshoot, I decided ...

Issue TS2365: The operation of addition cannot be performed between an array of numbers and the value -1000

I'm encountering an error in my ng serve logs despite the function functioning properly with no issues. However, I am concerned as this may pose a problem when building for production. How can I resolve this error? uuidv4() { return ([1e7]+-1e3+- ...

Encountering difficulties accessing props while invoking a component in React

In my project, I've created a component called FilterSliders using Material UI. Within this component, I passed a prop named {classes.title} by destructuring the props with const { classes }: any = this.props;. However, when I try to access this prop ...

Typescript React Union type

I have developed a Card component with two different variants: Wrapper and Dashboard. Each variant comes with its own set of props. export type DashboardProps = { variant: CardVariant.Dashboard, primaryText: string, secondaryText: string, icon: Ove ...