Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can I use "synthetic default imports" in TypeScript with Wallaby and Jest? #1181

Closed
chris-nissen opened this issue Jun 1, 2017 · 2 comments
Labels

Comments

@chris-nissen
Copy link

I'm finding that my tests won't work in Wallaby if I use module imports like import React from 'react';. I have to use import * as React from 'react';. The former does work when I run the tests in Jest. Is there a way I can tweak my config to make this work?

Wallaby.js configuration file

module.exports = function (wallaby) {
   return {
      files: [
	      { pattern: 'package.json', instrument: false }, // since Jest config is in there
	      { pattern: 'ClientApp/**/*.ts?(x)' },
	      { pattern: 'ClientApp/**/*.spec.ts?(x)', ignore: true },
          { pattern: 'ClientApp/**/*.snap' }
      ],

      filesWithNoCoverageCalculated: [
	      'ClientApp/configureStore.ts',
	      'ClientApp/boot-client.tsx',
	      'ClientApp/boot-server.tsx'
      ],

      tests: [
	      { pattern: 'ClientApp/**/*.spec.ts?(x)' }
      ],

      testFramework: 'jest',
      env: {
         // Required for Jest running
         type: 'node',
         runner: 'node'
      },

      hints: {
         ignoreCoverage: / exclude from coverage /
      },

      debug: true
   };
};

tsconfig

{
  "compilerOptions": {
    "baseUrl": ".",
    "moduleResolution": "node",
    "target": "es5",
    "jsx": "react",
    "experimentalDecorators": true,
    "sourceMap": true,
    "skipDefaultLibCheck": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "allowSyntheticDefaultImports": true,
    "noEmit": true, // So that VS doesn't write .js files when it compiles the TS files
    "lib": [ "es6", "dom" ],
    "paths": {
      "*": [
        "ClientApp/*"
      ],
      // Fix "Duplicate identifier" errors caused by multiple dependencies fetching their own copies of type definitions.
      // We tell TypeScript which type definitions module to treat as the canonical one (instead of combining all of them).
      "history": [ "./node_modules/@types/history/index" ],
      "redux": [ "./node_modules/@types/redux/index" ],
      "react": [ "./node_modules/@types/react/index" ]
    },
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "exclude": [
    "bin",
    "node_modules"
  ]
}

Jest config in package.json

 "jest": {
      "testResultsProcessor": "./node_modules/jest-junit-reporter",
      "transform": {
         ".(ts|tsx)": "./node_modules/ts-jest/preprocessor.js"
      },
      "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js|jsx)$",
      "moduleDirectories": [
         "node_modules",
         "./ClientApp"
      ],
      "moduleFileExtensions": [
         "ts",
         "tsx",
         "js",
         "jsx"
      ],
      "globals": {
         "__TS_CONFIG__": {
            "allowSyntheticDefaultImports": true,
            "module": "commonjs",
            "jsx": "react",
            "baseUrl": ".",
            "moduleResolution": "node",
            "typeRoots": [
               "./node_modules/@types"
            ],
            "paths": {
               "*": [
                  "*",
                  "ClientApp/*"
               ]
            }
         }
      }
   }

Code editor or IDE name and version

Visual Studio 2017

@ArtemGovorov
Copy link
Member

ArtemGovorov commented Jun 2, 2017

This one is interesting.

In TypeScript compiler itself, the allowSyntheticDefaultImports option doesn't change the compilation result. It means that no matter what you set it to, the compiled code looks exactly the same, and this import: import React from 'react'; will not work for you after a pure TypeScript compilation.

However, ts-jest forces TypeScript compilation to use es2015 modules (even though you have them configured to be commonjs which is the default), and then later it runs Babel transformation on top of the compiled TypeScript result. It is the babel's transform-es2015-modules-commonjs plugin that compiles the import React from 'react'; to a working ES5/CommonJs code.

Note you'll obviously need to setup a similar babel compilation for your production build, otherwise your app's tests with Jest/Wallaby will work, but your prod build will not work if it's only using TypeScript compiler.

If you don't mind this magic from ts-jest and the double compilation just for the sake of being able to import things like this, then you may configure wallaby in a similar way:

Here's how the change may look like:

module.exports = function (wallaby) {
  return {
    ...
    compilers: {
      '**/*.ts?(x)': wallaby.compilers.typeScript({
        module: 'es2015'
      })
    },
    preprocessors: {
      '**/*.js': file => require('babel-core').transform(
        file.content,
        {sourceMap: true, plugins: ['transform-es2015-modules-commonjs']})
    },
   ...
  }
};

Hope it makes sense.

@chris-nissen
Copy link
Author

Thanks, Artem! I confirmed that your suggested changes solved the problem, and that the production build didn't work, as you said.

On a previous project, we were running the Typescript through Babel so having "allowSyntheticDefaultImports" didn't cause us a problem and solved some issues for us importing certain modules. This time I'd like to see if I can get away without Babel, so I think I'll turn that flag off for now and use the longer import style.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants