ZachJW34 / nx-plus

Collection of Nx Community Plugins
MIT License
302 stars 51 forks source link

nx test: Jest unit tests are failing to run in any test that has been imported from other libraries #245

Open marimendez88 opened 2 years ago

marimendez88 commented 2 years ago

Current Behavior

An NX - Ionic and Vue workspace fails to run tests, many solutions tested and any seems to fix the issue:

This is the error message:

  ● 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

Solutions tested:

Related Issues:

https://github.com/nrwl/nx/issues/8323 https://github.com/nrwl/nx/issues/7844 https://github.com/nrwl/nx/issues/8354 https://github.com/nrwl/nx/issues/9825 https://github.com/ionic-team/ionic-framework/issues/25223

Investigation made:

Expected Behavior

Steps to Reproduce

Here you can find a minimal repository to reproduce the issue:

https://github.com/marimendez88/of-jest-issue

  1. Create empty workspace: Run npx create-nx-workspace@^13.0.0
  2. select → apps option
  3. Install testing dependencies: npm install @nrwl/cypress@^13.0.0 @nrwl/jest@^13.0.0 @nrwl/linter@^13.0.0 --save-dev
  4. Install nx vue plugin : npm install @nx-plus/vue --save-dev
  5. Creating sample app: nx g @nx-plus/vue:app sample-app
  6. Install ionic npm i @ionic/vue npm i @ionic/vue-router
  7. Update main.ts under sample-app to use ionic
  8. Creating sample lib nx g @nx-plus/vue:lib sample-lib
  9. Create a header test component under sample-lib
  10. Import the header component into the sample app to use it
  11. Successfully served and components are shown as expected
  12. Run a test, error happens.

Failure Logs

This is the error message:

  ● 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:

    /of-jest-issue/apps/sample-app/src/components/HelloWorld.vue:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { defineComponent } from 'vue';
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

      1 | import { shallowMount } from '@vue/test-utils';
    > 2 | import HelloWorld from '../../src/components/HelloWorld.vue';
        | ^
      3 |
      4 | describe('HelloWorld.vue', () => {
      5 |   it('renders props.msg when passed', () => {

      at Runtime.createScriptFromCode (../../node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (tests/unit/example.spec.ts:2:1)

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

Environment

 >  NX   Report complete - copy this into the issue template

   Node : 14.17.1
   OS   : darwin x64
   npm  : 6.14.13

   nx : 13.10.3
   @nrwl/angular : Not Found
   @nrwl/cypress : 13.10.3
   @nrwl/detox : Not Found
   @nrwl/devkit : 13.10.3
   @nrwl/eslint-plugin-nx : 13.10.3
   @nrwl/express : Not Found
   @nrwl/jest : 13.10.3
   @nrwl/js : Not Found
   @nrwl/linter : 13.10.3
   @nrwl/nest : Not Found
   @nrwl/next : Not Found
   @nrwl/node : Not Found
   @nrwl/nx-cloud : Not Found
   @nrwl/nx-plugin : Not Found
   @nrwl/react : Not Found
   @nrwl/react-native : Not Found
   @nrwl/schematics : Not Found
   @nrwl/storybook : Not Found
   @nrwl/web : Not Found
   @nrwl/workspace : 13.10.3
   typescript : 4.6.4
   rxjs : 6.6.7
   ---------------------------------------
   Community plugins:
     @nx-plus/vue: 13.0.1
gregveres commented 2 years ago

I ran into this when I first tried to test .vue files. I believe it is babel and TS running in the wrong order. I think babel is running first and then the input that TS gets is no longer a TS file.

I do have a project in my solution that is running tests against Vue files. I wish I had written down what I did to get it working.

I am also running into this now with another situation where I have a portion of the app that imports the language strings from Vuetify so that I can switch languages. This is a pure TS file with no other Vue in sight and I am getting the same error from Jest.

I have tried to make my config for this new library match the config of the libarary that can test Vue files but nothing has worked.

If I find a solution, I will post back here.

 ● 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:

    C:\Users\Greg\source\repos\SquashSpider\SquashSpider\SkyCourt.UI\skycourt\node_modules\vuetify\src\locale\en.ts:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export default {
                                                                                      ^^^^^^

    SyntaxError: Unexpected token 'export'

      24 | import 'dayjs/locale/en';
      25 | import 'dayjs/locale/fr';
    > 26 | import * as en from 'vuetify/src/locale/en';
         | ^
      27 | import * as fr from 'vuetify/src/locale/fr';
      28 | import { useI18n } from '@skycourt/common/store';
      29 | import appDataEmptySet from '../../__json__/app/appNotLoggedIn.json';

      at Runtime.createScriptFromCode (../../../node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (src/lib/app/app.ts:26:1)
      at Object.<anonymous> (src/lib/app/app.spec.ts:20:1)
gregveres commented 2 years ago

Looking at your nx report, how did you get setup with 13.10.3? I found that 13.10 failes to apply the patch for .vue files. Maybe that is the issue for you.

Try moving Nx to 13.9.7, which is the last version of 13.9 that works with Nx-Plus/vue.

gregveres commented 2 years ago

This doesn't help your problem (I cloned your reporoduction repo and tried), but for my problem I finally found a solution. I am putting it here because the symptoms of my problem were exactly the same message from jest.

My problem was that i was importing a TS file from node_modules and jest was choking on the import of that TS file with exactly the same message above. I finally found a fix for it by putting this statement into my jest.config.js file in the library that I was testing.

  transformIgnorePatterns: ['<rootDir>/node_modules/'],

Then I also had to add a compiler flag to this library's tsconfig.spec.json file to allow JS files.

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"],
    "jsx": "preserve",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true
  },
  "include": [
    "**/*.test.ts",
    "**/*.spec.ts",
    "**/*.test.tsx",
    "**/*.spec.tsx",
    "**/*.d.ts"
  ]
}

The first time I ran the tests it seemed to take forever (45 seconds to run 3 fairly simple test files), but after that it runs quickly. I am going to assume that this negatively affects performance and therefore only put it in the libs that require it.

BTW, I also found that the @nrwl/jest/preset always sets the jest environment to jsdom. This is a heavy environment and I have some libraries that are TS model code only. For those, I will look into setting this to node to see if there is an improvement in performance.

Ricardo385 commented 2 years ago

Hey @gregveres! Thanks for your time and help. I did step by step your possible solution but got no success, I got stuck in the same issue. For your issue, it seems that your problem was inside node_modules, ours is from the project, I wonder if that's the reason that the transformIgnorePatterns that you gave us didn’t work. Also, do you set the allowJS = true in the tsconfig.spec.json of the project or in the global? Thanks in advance!

gregveres commented 2 years ago

Hi @Ricardo385 Sorry I couldn't help more. I did clone your demo repo to try some things, but i couldn't get it working.

For my case, I am making progress on converting to Nx now. I have 1 app and 43 libraries so far. I expect to end up with 4 apps and over 200 libraries. I am disappointed that I need so many libraries, but from what I have seen, you need a library for every component that you are going to dynamically load using the Vue Router. The router will end up pulling in everything in the library.

Here are my steps for creating a new library. I use the Nx extension in VS Code to create an @nx-plus/vue:library. I add bable support (All my code is in Typescript). I create a buildable library I don't know what skipFormat is so I leave it unchecked. the same for skipTsConfig. I think I always want the @ aliases added.

Then I start modifying the files that were created. I delete these files: lib/HelloWorld.vue Test/* (my tests live beside my code, so I don't want the Test/ directory the tsx shim file (I don't use tsx files and this file gives me a lint error)

Then I modify these files in the project: .eslintrc: The first line is an extends command. I leave the relative path to .eslintrc.json, but I delete the other templates because I include them in the .eslintrc.json file. I find this annoying and wish that the generated .eslintrc.json file didn't include these templates. By including them at the project level, they wipe out my global overrides that were set in the global .eslintrc.json file

jest.config.js I have to add the transformIgnorePatterns statement listed above I also add a setupFilesAfterEnv with a relative path to my global jest setup files. I will likely request a change to this package to put that in there all the time. It is just a better way to consistently setup your jest environment across all of your projects.

tsconfig.spec.json Here is where I have to add the "allowJs": true. To directly answer your question, this is at the project level. I would love to have it setup globally so I don't have to change it on every new project, but that's not how the config files are setup by this plugin and I haven't explored my options yet. I am trying to get this task completed.

I am running into an infinite loop in jest when it is processing my TS files that happens randomly. So at this point my unit tests randomly fail. Well, randomly is a bit less random. Out of the 35 unit test projects, at least 5 will fail each run, but it will be a different set of 5 each time. I then execute the command again and they will all pass. I have to try and track that down too. I will first try to upgrade to jest 28 to see if that fixes it.

marimendez88 commented 2 years ago

Hey, Just wanted to let you know I found a workaround, is working pretty well so far, let's see how it goes in the next weeks when I start creating new tests ;) I just posted what I did here:

https://www.marimendez88.dev/posts/nx-vue-jest-support and medium: https://medium.com/@marimendez88/nx-vue-jest-support-666156038122