Umar Waliyullah
Umar Waliyullah

Reputation: 529

jest issue with typescript react components

I'm currently having an issue with Jest and Typescript inside a Lerna mono repo.

Inside the test file, I've imported the component import { Doctor } from '../src'; and the test step is as follows:

it('should be selectable by class "btn-doctor"', function() {
    expect(shallow(<Doctor/>).is('.btn-doctor')).toBe(true);
  });

<Doctor /> is underlined as warning; saying: 'Doctor' refers to a value, but is being used as a type here. Did you mean 'typeof Doctor'?ts(2749)

I think the issue is related to the configuration but i did not find anything in the official docs for Typescript and Jest.

The issue can be reproduced in this repo https://github.com/umarmw/lopital-sdk when running lerna run test

lerna ERR! npm run test stderr:
FAIL __tests__/doctor.test.ts
  ● Test suite failed to run

    __tests__/doctor.test.ts:14:21 - error TS2749: 'Doctor' refers to a value, but is being used as a type here. Did you mean 'typeof Doctor'?

    14     expect(shallow(<Doctor/>).is('.btn-doctor')).toBe(true);
                           ~~~~~~
    __tests__/doctor.test.ts:18:19 - error TS2749: 'Doctor' refers to a value, but is being used as a type here. Did you mean 'typeof Doctor'?

    18     expect(mount(<Doctor title="MO" />).find('.btn-doctor').length).toBe(1);
                         ~~~~~~
    __tests__/doctor.test.ts:18:26 - error TS2304: Cannot find name 'title'.

    18     expect(mount(<Doctor title="MO" />).find('.btn-doctor').length).toBe(1);

The current config files are as follows:

tsconfig.json

{
  "compilerOptions": {
    "target": "es6", // Specify ECMAScript target version
    "sourceMap": true, //   Generates corresponding .map file.
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ], // List of library files to be included in the compilation.
    "allowJs": false, // Allow JavaScript files to be compiled.
    "skipLibCheck": true, // Skip type checking of all declaration files (*.d.ts).
    "esModuleInterop": true, // Emit __importStar and __importDefault helpers for runtime babel ecosystem compatibility and enable --allowSyntheticDefaultImports for typesystem compatibility.
    "allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.
    "strict": true, // Enable all strict type checking options.
    "forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased references to the same file.
    "noImplicitAny": false, //  Raise error on expressions and declarations with an implied any type.
    "noLib": false, // Do not include the default library file (lib.d.ts).
    "emitDecoratorMetadata": true, // Emit design-type metadata for decorated declarations in source.
    "experimentalDecorators": true, // Enables experimental support for ES decorators.
    "module": "commonjs", // Specify module code generation: "None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015" or "ESNext".
    // "moduleResolution": "node",
    // "resolveJsonModule": true,
    "jsx": "react", // Support JSX in .tsx files: "react", "preserve", "react-native". See JSX.
    "declaration": true, //     Generates corresponding .d.ts file.
  },
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

jest.config.js

module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  globals: {
    "ts-jest": {
      extends: './babel.config.js',
      tsConfig: {
        // allow js in typescript
        allowJs: true,
      },
    },
  },
  verbose: true,
  moduleFileExtensions: ['ts', 'tsx', 'js'],
  notify: true,
  notifyMode: 'always',
  testMatch: ['**/__tests__/*.+(ts|tsx|js)', '**/*.test.+(ts|tsx|js)'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  // testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
  testPathIgnorePatterns: [
    '/node_modules/',
    '(/__tests__/.*|(\\.|/)(test|spec))\\.d\.ts$'
  ],
  snapshotSerializers: ['enzyme-to-json/serializer'],
  // setupFilesAfterEnv: ['<rootDir>../setupTests.js'],
}

babel.config.js

module.exports = {
    presets: [
      '@babel/preset-react',
      '@babel/preset-typescript',
      [
        '@babel/preset-env',
        {
          targets: {node: 'current'}
        }
      ],
    ],
    "plugins": [
      [
        "@babel/plugin-proposal-class-properties",
        {
          "loose": true
        }
      ]
    ]
  }

Any idea?

Upvotes: 0

Views: 2743

Answers (2)

Nigel Greenway
Nigel Greenway

Reputation: 383

It looks like you've not used the correct file extension here. Was your test named doctor.test.ts instead of doctor.test.tsx?

When testing React components you need to ensure you use (j|t)sx extension.

Upvotes: 1

Estus Flask
Estus Flask

Reputation: 222498

The error means that JSX syntax isn't recognized by TypeScript compiler and is parsed as a generic.

Since tsconfig.json has "jsx": "react", this means that it wasn't picked up by ts-jest for some reason. The reason is that it was overridden by tsConfig option. A common way to provide a config for tests is to extend another config

tsconfig.test.json

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "allowJs": true
  }
}

And specify it for ts-jest:

"tsConfig": "tsconfig.test.json"

Also, ts-jest doesn't have extends option, and even if it had, it wouldn't accept Babel config. There is babelConfig option for that. Since ts-jest transforms TypeScript and JSX, @babel/preset-react and @babel/preset-typescript may be unneeded in Babel config.

Upvotes: 1

Related Questions