typia icon indicating copy to clipboard operation
typia copied to clipboard

How to make Typia and Jest work together?

Open alexcupertme opened this issue 7 months ago • 2 comments

Question

Typia and Jest does not work when using both. Althrough, generally Typia is working in my project. What i am doing wrong?

jest --forceExit --detectOpenHandles --runInBand -c jest.config.unit.js I am getting

 FAIL  src/common/http/http.service.spec.ts (9.528 s)
  HttpService
    ✓ should be defined (6 ms)
    ✕ should call axios with correct parameters (3 ms)
    ✕ should handle FormData correctly (4 ms)
    ✓ should handle AxiosError correctly (7 ms)
    ✓ should handle other errors correctly (16 ms)
    ✓ should handle ENOTFOUND error correctly (18 ms)

  ● HttpService › should call axios with correct parameters

    Unknown error occurred: Error on typia.assertEquals(): no transform has been configured.

    Read and follow https://typia.io/docs/setup please.

    If you've already completed the setup, it means there's a bug in your code. Run `tsc` command so that check what is wrong with your code.

      105 |         );
      106 |       }
    > 107 |       throw new InternalException(
          |             ^
      108 |         `Unknown error occurred: ${(error as { message: string }).message}`,
      109 |         {
      110 |           cause: error,

      at HttpService.sendRequest (src/common/http/http.service.ts:107:13)
      at Object.<anonymous> (src/common/http/http.service.spec.ts:94:22)

    Cause:
    Error on typia.assertEquals(): no transform has been configured.

    Read and follow https://typia.io/docs/setup please.

    If you've already completed the setup, it means there's a bug in your code. Run `tsc` command so that check what is wrong with your code.

      70 |       statusText = response.statusText;
      71 |
    > 72 |       typia.assertEquals<Response>(response.data); // TODO: resolve with jest
         |             ^
      73 |       return response.data;
      74 |     } catch (error) {
      75 |       if (isAxiosError(error)) {

      at NoTransformConfigurationError (node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/typia/src/transformers/NoTransformConfigurationError.ts:5:9)
      at Object.assertEquals (node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/typia/src/module.ts:346:32)
      at HttpService.sendRequest (src/common/http/http.service.ts:72:13)
      at Object.<anonymous> (src/common/http/http.service.spec.ts:94:22)

Here is my setup:

  • jest.unit.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  ...require('./jest.config'),
  testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)', '!**/__test.e2e__/*'],
};
  • jest.config.js
let prettierPath;

try {
  // for work with jest snapshot
  prettierPath = require.resolve('jest-prettier');
} catch { }

/** @type {import('ts-jest').JestConfigWithTsJest} */
let config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testMatch: [
    '**/?(*.)+(spec|test).[jt]s?(x)',
    '**/?(*.)+(spec|test).e2e.[jt]s?(x)',
  ],
  setupFiles: ['dotenv/config'],
  transform: {
    '^.+\\.tsx?$': ['ts-jest', {
      tsconfig: 'tsconfig.json',
    }],
  },
};
if (prettierPath) {
  config.prettierPath = prettierPath;
}

module.exports = config;
  • package.json deps:
  "dependencies": {
    "@mikro-orm/core": "^6.4.12",
    "@mikro-orm/migrations": "^6.4.13",
    "@mikro-orm/nestjs": "^6.1.1",
    "@mikro-orm/postgresql": "^6.4.12",
    "@mikro-orm/reflection": "^6.4.12",
    "@nest-middlewares/compression": "^10.0.0",
    "@nestjs/cli": "^10.4.8",
    "@nestjs/common": "^10.4.15",
    "@nestjs/core": "^10.4.15",
    "@nestjs/microservices": "10.0.0",
    "@nestjs/platform-express": "^10.4.12",
    "@nestjs/platform-socket.io": "^11.0.20",
    "@nestjs/schedule": "^4.1.2",
    "@nestjs/schematics": "^10.2.3",
    "@nestjs/swagger": "^7.4.2",
    "@nestjs/websockets": "^11.0.20",
    "@stylistic/eslint-plugin": "^4.2.0",
    "@typescript-eslint/eslint-plugin": "^8.31.0",
    "@typescript-eslint/parser": "^8.31.0",
    "aws-sdk": "^2.1692.0",
    "axios": "^1.7.9",
    "axios-retry": "^4.5.0",
    "body-parser": "1.x.x",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.14.1",
    "compression": "^1.7.5",
    "date-fns": "^4.1.0",
    "dotenv": "^16.4.7",
    "eslint": "^9.25.1",
    "eslint-plugin-deprecation": "^3.0.0",
    "express": "^4.21.2",
    "form-data": "^4.0.1",
    "got": "^14.4.5",
    "graphlib": "^2.1.8",
    "handlebars": "^4.7.8",
    "inline-css": "^4.0.3",
    "jest": "^29.7.0",
    "lodash": "^4.17.21",
    "mime-types": "^2.1.35",
    "multer": "1.4.5-lts.1",
    "pg": "^8.14.0",
    "ping": "^0.4.4",
    "pluralize": "^8.0.0",
    "property-validator": "^1.0.2",
    "qs": "^6.13.1",
    "reflect-metadata": "^0.2.2",
    "request-ip": "^3.3.0",
    "rimraf": "^6.0.1",
    "rxjs": "^7.8.1",
    "sass": "^1.86.0",
    "socket.io": "^4.8.1",
    "tmp": "^0.2.3",
    "ts-jest": "^29.2.6",
    "ts-morph": "^25.0.1",
    "typia": "^9.1.1",
    "uuid": "^11.1.0",
    "ws": "^8.18.1"
  },
  "devDependencies": {
    "@dagrejs/graphlib-dot": "^1.0.2",
    "@mikro-orm/cli": "^6.4.12",
    "@nestjs/testing": "^10.4.15",
    "@rsdk/cli": "^5.3.0",
    "@rsdk/cli.cmd.autodoc": "^5.3.0",
    "@rsdk/cli.cmd.start": "^5.4.0",
    "@rsdk/prettier-config": "^5.3.0",
    "@rsdk/testing": "^5.7.0",
    "@rsdk/tsconfig": "^5.3.0",
    "@swc/cli": "^0.5.2",
    "@swc/core": "^1.10.4",
    "@tsconfig/node-lts": "^22.0.1",
    "@types/compression": "^1.7.5",
    "@types/express": "^5.0.0",
    "@types/graphlib": "^2.1.12",
    "@types/jest": "^29.5.14",
    "@types/lodash": "^4.17.16",
    "@types/multer": "^1.4.12",
    "@types/node": "^22.13.10",
    "@types/ping": "^0.4.4",
    "@types/pluralize": "^0.0.33",
    "@types/request-ip": "^0.0.41",
    "@types/tmp": "^0.2.6",
    "@types/ws": "^8.18.1",
    "eslint-formatter-codeframe": "^7.32.1",
    "eslint-import-resolver-typescript": "^4.3.4",
    "eslint-plugin-import": "^2.31.0",
    "eslint-plugin-import-x": "^4.11.0",
    "eslint-plugin-prettier": "^5.2.6",
    "eslint-plugin-simple-import-sort": "^12.1.1",
    "eslint-plugin-unicorn": "^56.0.1",
    "husky": "^9.1.7",
    "patch-package": "^8.0.0",
    "pino-pretty": "^13.0.0",
    "postinstall-postinstall": "^2.1.0",
    "prettier": "^3.4.2",
    "ts-node": "^10.9.2",
    "ts-patch": "^3.3.0",
    "tsconfig-paths": "^4.2.0",
    "ttypescript": "^1.5.15",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.31.0"
  },
  • tsconfig.json:
{
  "extends": "@ext/tsconfig/base.json",
  "ts-node": {
    "require": [
      "tsconfig-paths/register"
    ],
    "compilerHost": true,
    "transpileOnly": true
  },
  "include": [
    "./src/**/*.ts",
    "ormconfig.ts",
  ],
  "compilerOptions": {
    "declaration": true,
    "outDir": "dist",
    "target": "ES2022",
    "strictNullChecks": true,
    "exactOptionalPropertyTypes": true,
    "strictPropertyInitialization": true,
    "strict": true,
    "useDefineForClassFields": false,
    "baseUrl": ".",
    "paths": {
      "#/*": [
        "./src/*"
      ],
      "#mc/*": [
        "src/common/mc/*"
      ],
      "#mc-common/*": [
        "src/common/mc-common/*"
      ]
    },
    "plugins": [
      {
        "transform": "typia/lib/transform"
      }
    ]
  }
}
  • @ext/tsconfig/base.json:
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Default",
  "extends": "@tsconfig/node-lts/tsconfig.json",
  "compilerOptions": {
    "moduleResolution": "node10",
    "module": "commonjs",
    "declaration": true,
    "removeComments": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ES2022",
    "esModuleInterop": true,
    "sourceMap": true,
    "incremental": false,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "strict": true,
    // since it duplicates the eslint rule, and it is impossible to disable it in a targeted manner
    "noUnusedLocals": false,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noImplicitOverride": true,
    "allowUnusedLabels": false,
    "allowUnreachableCode": false,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictNullChecks": true,
    "strictPropertyInitialization": true,
    "useUnknownInCatchVariables": true,
    "noImplicitThis": true
  }
}

alexcupertme avatar Apr 30 '25 08:04 alexcupertme

Update: solved! Problem was not in my setup, but due to using typia with generics. Even though this error

    Unknown error occurred: Error on typia.assertEquals(): no transform has been configured.

    Read and follow https://typia.io/docs/setup please.

is misleading because it was definetely not a transform configuration. @samchon

If it is a real issue, i can help make a PR

alexcupertme avatar May 04 '25 12:05 alexcupertme

I may be running into a similar issue. I was interested in exploring Typia for it's faster json serialization, but am encountering the same error. Could you expand on what you mean by "due to using typia with generics"?

I don't have anything fancy here, I'm swapping a k => stringify(k) with k => typia.json.stringify(k), which I had hoped would work out of the box. Even if I'm explicit about the type of k, it's still the same error. Like you, I suspect it's a small misconfiguration, but I'm at a loss as to what/where it is.

Thanks!

bstein-lattice avatar Jun 04 '25 18:06 bstein-lattice

@bstein-lattice Hi! By that i meant that you cannot use typia with polymorphism generic parameters, something like this:


function identity<T>(value: T): T {
  typia.assertEquals<T>(value) // This line will fail in runtime
  return value;
}

alexcupertme avatar Jun 17 '25 15:06 alexcupertme

Ah, that's definitely a use case I'd like to have, though in this particular case I think it was not generic. Maybe I just wasn't explicit enough in my type declaration.

bstein-lattice avatar Jun 17 '25 21:06 bstein-lattice

Is there an update on this ? I am getting Error on typia.is(): no transform has been configured. even on my pre-built TS code. I did npx typia setup on both my normal tsconfig.ts and tsconfig.jest.ts, and do npm run compile-tests && jest --forceExit --verbose but it just doesn't work ?

nikita-fuchs avatar Jul 31 '25 10:07 nikita-fuchs

for all that have that strange error, in my case Error on typia.is(): no transform has been configured. latest version caused that 9.7.*. So downgrade to 9.6.0 and running npx typia setup again helped. Also, it might require to downgrade typescript for some reason its a peer dependency of typia

Gordiievskyi avatar Sep 03 '25 21:09 Gordiievskyi

I started facing this error today when I cleaned out package-lock.json and node_modules directory and re-ran

  1. npm install in my typia project, followed by
  2. npm test
[Error: Error on typia.misc.assertClone(): no transform has been configured.·
    Read and follow https://typia.io/docs/setup please.·
    If you've already completed the setup, it means there's a bug in your code. Run `tsc` command so that check what is wrong with your code.]

I had not made any changes to my jest based test cases which were working without throwing these errors, earlier.

Also, tsc builds without errors. And finally, I checked each of my assertClone calls and made sure I was not using generics in any of the places.

I noticed my setup was using typia version 9.7.2 and typescript version 5.9.3

I experimented with various versions of both typia and typescript and concluded that I can choose either typia 9.6.x or 9.7.x as long as I was also using typescript 5.9.2 or 5.8.x So, as long as I am not running typescript 5.9.3, I don't get the error when executing tests.

I am also using jest 29.7.0, ts-jest 29.4.4, ts-loader 9.5.4, ts-node 10.9.2 and ts-patch 3.3.0.

Let me know if you need any other details about my setup.

To move past this, I've downgraded typescript and pinned it to "5.9.2" in my package.json and using the latest version of typia (i.e. 9.7.2)

PS: Thank you @samchon for the awesome typia project. I love being able to keep my type definitions in pure typescript!

anvad avatar Oct 03 '25 01:10 anvad

After spending several hours, I found my issue. It was due to isolatedModules. So I fixed it by creating:

tsconfig.jest.json:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "isolatedModules": false
  }
}

and in jest config:

"transform": {
      "^.+\\.ts$": ["ts-jest", {
        "tsconfig": "tsconfig.jest.json",
       // "compiler": "ts-patch/compiler", enable if needed
      }]
    },

hannanstd avatar Oct 06 '25 22:10 hannanstd

Another approach that works for me:

  1. Run typia generation manually, something like:
npx typia generate --input tests --output tests-transpiled --project tsconfig.tests.json
  1. With the generated output, run your jest tests. All typia magic will be applied to your code by this point and Jest will just run it.

nikita-fuchs avatar Oct 07 '25 08:10 nikita-fuchs