Angular-builders: run ngcc when using ng test to run test with ivy

Created on 12 Feb 2020  路  7Comments  路  Source: just-jeb/angular-builders

Describe the solution you'd like
When running ng test with

"test": {
          "builder": "@angular-builders/jest:run",
          "options": {
          }
 ```
inside `angular.json`, it should run `ngcc` beforehand as `angular-cli` already does (see: https://github.com/angular/angular-cli/pull/15044#issue-296489062). Otherwise, tests are not running with `ivy`, which should be the default for angular 9.
As this might break existing tests, an `options` flag like `"enableIvy": false` could still be added in order to run them the old way. Or just use the configuration that's already existing in `tsconfig.spec.ts` which usually points to `tsconfig.ts` that has `"enableIvy": false` already defined.

**Describe alternatives you've considered**
The only way I could make it work is by defining a `scripts` inside `package.json`.

{
"scripts": {
"test": "ngcc && ng test"
}
}
`` and then execute it withnpm run test. It would still be great to just run it withng test`

jest enhancement

Most helpful comment

Here are my findings:

  • ngcc transforms libraries, typically node_modules (js files and dts), to make them Ivy compatible. It is necessary, especially if you want to have meaningful error messages when your test fails.
  • For node_modules it's enough to run ngcc only once, for example in postinstall hook to ensure compatibility.
  • There is a very specific use case when you need to run ngcc on modules other than node_modules - when you have a monorepo with libraries and you reference the production bundles of these libraries (dist folders) from your app's tsconfig.
  • Angular CLI commands (build, serve, karma) use ngtools/webpack and as part of Webpack compilation they run ngcc_processor on each non-relative module, which essentially handles the case of monorepo with libraries. It also eliminates the need to run ngcc for the whole node_modules and only runs it for the files that are part of the compilation.

Conclusion:
Running ngcc as a postinstall hook might be a viable workaround for 95% of projects, so we have to include it in the documentation and the migration guide.
However, the only solution that will handle all the use cases properly is adding a custom Jest transformer that will apply ngcc_processor from ngtools/webpack to all the non-relative modules similarly to Angular CLI.
I seriously doubt though that this transformer should be implemented here and not in jest-preset-angular.

All 7 comments

I agree, this should be a part of the builder. Thanks for the investigation. Would you like to make a PR?

Let me give it a try. I'm currently struggling with finding out how the angular team runs ngcc before they run karma. I'm completely new to that code so I need some time there.

Also, I wonder, maybe for the sake of compatibility we should first look for the flag in tsconfig.spec.json in angularCompilerOptions and only then in builder options. What do you think?

In my opinion, we should just check for the flag in tsconfig.spec.json. Having 2 places to configure it makes it a bit repetitive. We either want to run the app with ivy, then the tests should also run it, or we don't, and then we have to anyway set a flag in our tsconfig. And usually, tsconfig.spec.json extends from tsconfig.json where it's configured.

Here are my findings:

  • ngcc transforms libraries, typically node_modules (js files and dts), to make them Ivy compatible. It is necessary, especially if you want to have meaningful error messages when your test fails.
  • For node_modules it's enough to run ngcc only once, for example in postinstall hook to ensure compatibility.
  • There is a very specific use case when you need to run ngcc on modules other than node_modules - when you have a monorepo with libraries and you reference the production bundles of these libraries (dist folders) from your app's tsconfig.
  • Angular CLI commands (build, serve, karma) use ngtools/webpack and as part of Webpack compilation they run ngcc_processor on each non-relative module, which essentially handles the case of monorepo with libraries. It also eliminates the need to run ngcc for the whole node_modules and only runs it for the files that are part of the compilation.

Conclusion:
Running ngcc as a postinstall hook might be a viable workaround for 95% of projects, so we have to include it in the documentation and the migration guide.
However, the only solution that will handle all the use cases properly is adding a custom Jest transformer that will apply ngcc_processor from ngtools/webpack to all the non-relative modules similarly to Angular CLI.
I seriously doubt though that this transformer should be implemented here and not in jest-preset-angular.

So, the only way, for now, is the running ngcc manually before running the tests (in postinstall, for example)? But this is a problem for our CI to execute ngcc for packages of the whole monorepo on every test run because of our CI workers install all packages from zero every time and ngcc in additional takes as much as 10 minutes in each build.

Unfortunately, currently this is the only way. A few things you can do:

  1. Cache node_modules on CI workers
  2. Identify the modules that require ngcc run and run it on them specifically (instead of the whole node_modules folder).
  3. Watch this issue to see whether there will be some solution. Here is some more info.
Was this page helpful?
0 / 5 - 0 ratings