Skip to content
This repository has been archived by the owner on Feb 19, 2021. It is now read-only.

"SyntaxError: Unexpected token import" with create-react-app-ts #40

Closed
mthmulders opened this issue Apr 3, 2018 · 20 comments
Closed

"SyntaxError: Unexpected token import" with create-react-app-ts #40

mthmulders opened this issue Apr 3, 2018 · 20 comments

Comments

@mthmulders
Copy link
Collaborator

Currently trying out Stryker on my Jest + TypeScript React application. Work is on the feature/mutation-testing branch. I've added a work-around for #38, but now I'm facing a new issue.

The configuration seems fine and Stryker attempts its initial test run. Every test suite fails with this message:

    /Users/maarten/Projects/hyperion-web/.stryker-tmp/sandbox8787577/build/dist/__tests__/apiSpec.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import * as fetchMock from 'fetch-mock';
                                                                                            ^^^^^^
    
    SyntaxError: Unexpected token import
    
    at new Script (vm.js:51:7)
        at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:118:7)

I'm using create-react-app-ts, which uses ts-jest under the hood. This hooks into Jest using a preprocessor which invokes tsc to transpile the Typescript code to JavaScript first.

I've tried the following in stryker.conf.js:

  • project: 'default',
  • project: 'react',
  • no project at all
@nicojs
Copy link
Member

nicojs commented Apr 3, 2018

Hmm interesting. How does the discovering of ts-jest work? Is it looking for node_modules/*-jest modules and loading those on the fly? That would explain it (node_modules are currently not symlinked in sandboxes).

We've had some issues reported on the stryker main repo about jest not loading plugins:

Could you take a look and try to add ts-jest to your testing sandbox (add it to the files array)?

@mthmulders
Copy link
Collaborator Author

How does the discovering of ts-jest work? Is it looking for node_modules/*-jest modules and loading those on the fly?

Well, react-scripts-ts creates a Jest configuration that holds a transform option. This has (among others) '^.+\\.tsx?$': resolve('config/jest/typescriptTransform.js'). Now typescriptTransform.js loads and exports ts-jest/preprocessor.

So I think I should not only add **/node_modules/ts-jest/dist/preprocessor.js to the files array, but also **/node_modules/react-scripts-ts/scripts/utils/createJestConfig.js and **/node_modules/react-scripts-ts/config/jest/typescriptTransform.js.

But when I do that, I get this:

[2018-04-03 19:09:43.717] [ERROR] StrykerCli - an error occurred Error: Could not find file: '/Users/maarten/Projects/hyperion-web/node_modules/react-scripts-ts/scripts/utils/createJestConfig.js'.
    at getValidSourceFile (/Users/maarten/Projects/hyperion-web/node_modules/typescript/lib/typescript.js:95642:23)
    at Object.getSemanticDiagnostics (/Users/maarten/Projects/hyperion-web/node_modules/typescript/lib/typescript.js:95824:36)
    at /Users/maarten/Projects/hyperion-web/node_modules/stryker-typescript/src/transpiler/TranspilingLanguageService.js:54:92
    at arrayMap (/Users/maarten/Projects/hyperion-web/node_modules/lodash.flatmap/index.js:140:21)
    at map (/Users/maarten/Projects/hyperion-web/node_modules/lodash.flatmap/index.js:1928:10)
    at flatMap (/Users/maarten/Projects/hyperion-web/node_modules/lodash.flatmap/index.js:1881:22)
    at TranspilingLanguageService.getSemanticDiagnostics (/Users/maarten/Projects/hyperion-web/node_modules/stryker-typescript/src/transpiler/TranspilingLanguageService.js:54:22)
    at TypescriptTranspiler.transpileAndResult (/Users/maarten/Projects/hyperion-web/node_modules/stryker-typescript/src/TypescriptTranspiler.js:27:42)
    at TypescriptTranspiler.transpile (/Users/maarten/Projects/hyperion-web/node_modules/stryker-typescript/src/TypescriptTranspiler.js:23:37)
    at TranspilerFacade.<anonymous> (/Users/maarten/Projects/hyperion-web/node_modules/stryker/src/transpiler/TranspilerFacade.js:32:62)
    at step (/Users/maarten/Projects/hyperion-web/node_modules/tslib/tslib.js:133:27)
    at Object.next (/Users/maarten/Projects/hyperion-web/node_modules/tslib/tslib.js:114:57)
    at /Users/maarten/Projects/hyperion-web/node_modules/tslib/tslib.js:107:75
    at new Promise (<anonymous>)
    at Object.__awaiter (/Users/maarten/Projects/hyperion-web/node_modules/tslib/tslib.js:103:16)
    at TranspilerFacade.performTranspileChain (/Users/maarten/Projects/hyperion-web/node_modules/stryker/src/transpiler/TranspilerFacade.js:25:24)

While find . -name "createJestConfig.js" yields:

./node_modules/react-scripts-ts/scripts/utils/createJestConfig.js

@nicojs
Copy link
Member

nicojs commented Apr 3, 2018

Ok, could you try node_modules/ts-jest/**/*.js (instead of **/node_modules/ts-jest/dist/preprocessor.js) and the same thing for react-scripts-ts?

@mthmulders
Copy link
Collaborator Author

Well, that doesn't make a big difference. Only notable difference is that this time, it's node_modules/react-scripts-ts/bin/react-scripts-ts.js that cannot be found. Again, this file does exist on disk...

@simondel
Copy link
Member

simondel commented Apr 6, 2018

This should be fixed when we implement stryker-mutator/stryker-js#672

So I'll close this issue for now.

@simondel simondel closed this as completed Apr 6, 2018
@simondel simondel removed the backlog label Apr 6, 2018
@mthmulders
Copy link
Collaborator Author

Still no luck... After upgrading to Stryker 0.22.0 (which has symlinkNodeModules: true by default) and removing the files option from stryker.conf.js, I'm back at the original message:

[2018-04-11 13:51:02.007] [ERROR] InitialTestExecutor - One or more tests resulted in an error:
    ● Test suite failed to run

    /home/circleci/project/.stryker-tmp/sandbox991748/build/dist/__tests__/apiSpec.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import * as fetchMock from 'fetch-mock';
                                                                                            ^^^^^^
    
    SyntaxError: Unexpected token import
    
    at ScriptTransformer._transformAndBuildScript (../../node_modules/jest-runtime/build/ScriptTransformer.js:289:17)
        at <anonymous>

@mthmulders mthmulders reopened this Apr 11, 2018
@nicojs
Copy link
Member

nicojs commented Apr 11, 2018

could you try out the jest command from your sandbox directory? In this example: /home/circleci/project/.stryker-tmp/sandbox991748

@mthmulders
Copy link
Collaborator Author

A few more observations...

When I run jest in the sandbox, it fails with the same error messages.

When I look at .stryker-tmp/sandbox991748/build/dist/__tests__/apiSpec.js, it contains the transpiled TypeScript code (I see var instead of const in the original TS code). The preceding ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){ is not there in my original TS code.

When I run Stryker with debug logging, it spits out the configuration. Here's a funny thing: the Jest configuration doesn't quite look like what I'd expect:

{
    "jest":{
        "project":"default",
        "config":{
            "collectCoverage":false,
            "verbose":false,
            "bail":false
        }
    }
}

I'd expect a different Jest configuration because createJestConfig() (from create-react-app-ts) defines a lot more options.

See the CI build for detailed logging.

@nicojs
Copy link
Member

nicojs commented Apr 12, 2018

When I run jest in the sandbox, it fails with the same error messages.

I finally understand what the problem is. You're normal test setup does not use jest directly. Instead, it uses react-scripts test or something right? Can you validate that? Could you verify that that command does work in the sandbox?

The preceding ({"Object.":function(module,exports,require,__dirname,__filename,global,jest){ is not there in my original TS code.

This is actually the nodejs wrapper for all modules.

@mthmulders
Copy link
Collaborator Author

My package.json has:

"test": "react-scripts-ts test --env=jsdom --coverage"

So indeed, it doesn't run Jest directly. The test command is implemented here.

Running ./node_modules/react-scripts-ts/bin/react-scripts-ts.js test --env=jsdom --coverage in the sandbox locally gives:

No tests found
In /Users/maarten/Projects/hyperion-web/.stryker-tmp/sandbox7201869
62 files checked.
testMatch: /Users/maarten/Projects/hyperion-web/.stryker-tmp/sandbox7201869/src/**/__tests__/**/*.ts?(x),/Users/maarten/Projects/hyperion-web/.stryker-tmp/sandbox7201869/src/**/?(*.)(spec|test).ts?(x) - 0 matches
testPathIgnorePatterns: /node_modules/ - 62 matches
Pattern: "" - 0 matches

Note that the testMatch gives 0 matches, though...

@nicojs
Copy link
Member

nicojs commented Apr 12, 2018

I think the next problem is the typescript code. You mentioned that you had transpiled code in your sandbox. That shouldn't be the case right? As jest is handling the transpiling of typescript in your use case. So you should remove the transpilers: [ 'typescript' ] from your stryker.conf.js file and try again.

@mthmulders
Copy link
Collaborator Author

I removed transpilers: ['typescript'] - now Stryker doesn't crash anymore, and it says

[2018-04-12 10:31:39.129] [WARN] InitialTestExecutor - No tests were executed. Stryker will exit prematurely. Please check your configuration.
[2018-04-12 10:31:39.337] [INFO] Stryker - 345 Mutant(s) generated

The sandbox looks different than it used to do. Before, it would contain a src/ and a dist/ folder (as can be seen in the CircleCI log), now it only contains src/.

But the good news is that Stryker now generates mutants! I'm not sure what it mutated: transpiled JavaScript or (original) TypeScript? I think it would make more sense to have Stryker take care of transpiling TypeScript, so it can also generate the mutants in the TypeScript code?

(Logging)

@nicojs
Copy link
Member

nicojs commented Apr 12, 2018

I'm not sure what it mutated: transpiled JavaScript or (original) TypeScript?

Well, that didn't change. Stryker should always mutate your source code. That's why you configured the mutator: 'typescript' in your stryker config.

I think it would make more sense to have Stryker take care of transpiling TypeScript, so it can also generate the mutants in the TypeScript code?

In that case I would expect you to also transpile using typescript in your regular workflow (instead of letting Jest take care of that)

@mthmulders
Copy link
Collaborator Author

After a lot of digging around (thank @nicojs!) I found the root cause: Stryker doesn't invoke the aforementioned createJestConfig().

I did some prototyping locally to make Stryker invoke that functions, and it seems to work. I'll polish it a bit and submit a PR.

@mthmulders
Copy link
Collaborator Author

Polishing in progress... But I had some issues getting the integration test to work.

Turned out that I ran into Jest #5401, which can be solved by upgrading Jest. See e.g. this comment, suggesting that it might be caused by having multiple versions of Jest lying around. Indeed, I turned out to have Jest 20.x (from the Runner itself) as well as 22.x (from CRAT).

So I'm wondering if it'd be OK if we upgraded Jest to 22.x in the course of this issue? Or maybe we should have a separate issue for it?

@simondel
Copy link
Member

How easy is it to upgrade to a newer jest version as a user? If it's easy, I would prefer we drop support for older jest versions. Else we'll have yet another version-dependant switch in our code.

@mthmulders
Copy link
Collaborator Author

How easy is it to upgrade to a newer jest version as a user?

Generally speaking, it is rather easy. But when you are a create-react-app user (in whatever flavour), it is not supported to manually upgrade Jest. Instead, you are supposed to take Jest upgrades as they come to you through an upgrade of create-react-app user (in whatever flavour).

@nicojs
Copy link
Member

nicojs commented Apr 25, 2018

react-scripts is currently on "jest": "22.1.2",: https://github.com/facebook/create-react-app/blob/next/packages/react-scripts/package.json#L52

@mthmulders what other flavors are there? I think create-react-app-ts also uses react-scripts right? I would say drop the support for <22.x and add a BREACKING CHANGE notice to the squashed commit message.

@mthmulders
Copy link
Collaborator Author

I'm not aware of other flavours. But that is not to say there are none ;-). create-react-app-ts has its own version of react-scripts named react-scripts-ts.

For this issue, it would make stuff a whole lot easier if we just require Stryker users to be on Jest 22 or higher. Jest versions come out pretty frequently, as do create-react-app(-ts) versions. In my small experience, upgrading create-react-app(-ts) is usually not a big problem.

@mthmulders
Copy link
Collaborator Author

I can confirm this no longer happens in version 0.7.0. Thanks a lot for the support 👍

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

No branches or pull requests

3 participants