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

Exposing the built-in jest config #25434

Open
danny12321 opened this issue Jun 23, 2023 · 21 comments
Open

Exposing the built-in jest config #25434

danny12321 opened this issue Jun 23, 2023 · 21 comments

Comments

@danny12321
Copy link

Command

config

Description

Expose the jest config used by angular so third party apps can use it. For example: StrykerJS needs this config to run mutation testing on angular project.

Describe the solution you'd like

It would be nice to have something simular as npx ng generate config karma but than for jest.

Describe alternatives you've considered

I tried reverse engineer the config but it was quite complex and may be prone to change in the future which increases the potential of errors with new releases.

@dgp1130
Copy link
Collaborator

dgp1130 commented Jun 27, 2023

it was quite complex and may be prone to change in the future which increases the potential of errors with new releases.

This is exactly why the Jest config is not exposed right now. We've talked about this a good amount on the team to understand the trade-offs being made here. The challenge is that Angular CLI has to make a lot of assumptions about Jest's setup and configuration to provide a reliable experience and for us as developers to effectively reason about what your Jest execution actually looks like and how we can improve it. This is easy to do when we control that configuration and can specify it exactly. When we start allowing user-specific configurations, it becomes very easy for users to break that configuration and run into confusing edge cases.

One of the primary goals of the Angular CLI is to solve these kinds of tooling and configuration problems so users don't have to deal with them as much as possible. We typically try to enable common web development use cases directly and provide a holistic experience as much as we can, rather than implementing a minimal core and asking users to fill in the blanks. To that end, one area we're experimenting with here is trying to see how far we can go without needing to expose the Jest configuration. Is it possible for Angular CLI to support most common testing use cases through other means without having to expose the Jest config?

As one example, I expect some users might think "I want to modify the Jest configuration so I can measure code coverage". That's certainly one approach, but code coverage is a pretty common task I would much rather just support code coverage in Angular CLI directly and say "Just use that". Let Angular CLI handle the Jest configuration for you and solve the problem more directly. We don't yet have support for code coverage in the current Jest implementation, but it is something we're hoping to add following this mindset.

Jest support is still experimental, and I think the answer to the above question remains to be seen. What I think would be helpful here is understanding everyone's motivations for modifying the Jest configuration. Mutation testing is one such use case. I'm not terribly familiar with it and will need to do more research to make sure this kind of approach would be the right way of integrating it. But I would love to hear from the rest of the community about what problems you all are trying to solve. If we can collect enough use cases here, I think it will greatly help to answer the above question and understand whether or not exposing the Jest config is truly the best path forward for the Angular ecosystem.

@nicojs
Copy link
Contributor

nicojs commented Jul 5, 2023

@dgp1130, thanks for your response.

Believe me when I say: we understand. I think using something like npx ng generate config jest is a suboptimal approach. I would rather have something like import jestConfig from '@angular-devkit/build-angular/src/builders/jest/config.mjs'. That way, we have the best of both worlds: a great user experience and a way for plugin creators to get at the jest config.

An alternative:

import { createJestConfig } from '@angular-devkit/build-angular';

const projectName = 'app';
const jestConfig = await createJestConfig(projectName);

@nicojs
Copy link
Contributor

nicojs commented Sep 22, 2023

@dgp1130 would you agree with this approach? I would be happy to implement this in a PR 👍

@johncrim
Copy link

johncrim commented Sep 29, 2023

@dgp1130 - I agree with the intent of automating/hiding the jest config. I've certainly found it to be brittle when working with Angular, and particularly when upgrading to ESM. I think there's a lot of value in wrapping/hiding it in most cases. The question is whether completely hiding it without providing an escape hatch is sufficient in 100% of cases.

Let me try to add a little value by inventorying what we've had to configure in jest.config.js and in karma.conf.js. (I'm including karma just b/c Angular does support the config file, and it's worth considering why it's needed):

karma.conf.js settings:

  • plugins (reporters, coverage plugins, browser launchers)
  • Reporter settings
  • Launcher settings
  • log level
  • single run
  • restart on file change

jest.config.js settings:

  • Things presumably handled by the builder:
    • roots
    • testMatch glob pattern
    • transform
  • testPathIgnorePatterns
  • moduleDirectories
  • moduleFileExtensions
  • moduleNameMapper - Fixup all the packages that don't have correct node ESM packaging
  • setupFilesAfterEnv

Things that we've needed to pass to jest on the command-line:

  • environment variables
  • switches like coverage and reporter parameters
  • Run test on single file or path pattern
  • Debug watch

Hope that helps.

@dgp1130
Copy link
Collaborator

dgp1130 commented Oct 11, 2023

@nicojs, that's definitely an approach to consider, but I think it still has the same challenges of exposing the underlying implementation details (albeit in a more constrained and less accessible capacity). For example, one aspect we're experimenting with right now is pre-building tests with esbuild prior to passing them through to Jest. This means Jest is operating on pure JavaScript files and performs no transformations whatsoever. If a user then tries to add a custom transform expecting TypeScript files, it's not going to find anything. Future changes to aspects of the build process become observable to custom plugins and break them in a hard to anticipate way. Basically any change is a potential breaking change and it becomes increasingly difficult to do anything with the system outside of major versions.

There is potentially some API design here which could minimize that risk such as allowing customization of specific pieces of the Jest config as managed by Angular. A strawman example for this might look like:

import { runJest } from '@angular-devkit/build-angular';

runJest(['**/*.spec.ts'], {
  // Override specific, supported pieces of the Jest config.
  moduleNameMapper: { /* ... */ },
});

That's definitely not perfect either, but it's an approach to consider which might serve as a useful middle ground for supplying some constraints to the system without being completely closed off to extensions.

At this stage though I think the most helpful thing would just be to understand use cases for modifying the Jest config and if/how it would make sense for Angular CLI to meet those needs (whether that includes exposing the Jest config or addressing the problem through a different means).

@nicojs
Copy link
Contributor

nicojs commented Oct 14, 2023

Hi @dgp1130 🙋‍♂️, thanks for the help 🙏

Wouldn't it be possible to run esbuild using the jest transformer API?

If running esbuild from a jest transformer API is not possible, then a drop-in replacement for jest would be nice to work with. However, I would like to point you to a new programmatic API I've been working on. Preferably, it would use that API:
jestjs/jest#14062

So something like this:

import {createJest} from '@angular-devkit/build-angular';

const jest = await createJest();
jest.globalConfig = {
  ...jest.globalConfig,
  // Override specific, supported pieces of the Jest config.
  collectCoverage: false,
};
const {results} = await jest.run();
console.log(`run success, ${result.numPassedTests} passed tests.`);

@dgp1130
Copy link
Collaborator

dgp1130 commented Oct 17, 2023

Wouldn't it be possible to run esbuild using the jest transformer API?

Possibly, though Angular's build process is a lot more complicated than just running esbuild. Angular CLI includes a complete build system for orchestrating work like this, and I think we would rather decouple the building and testing parts of the infrastructure as much as possible so Jest doesn't need to have knowledge of Angular's build processes. That does lead to some performance questions as I mentioned and we're still trying to figure out if that is quite the right approach, but it's something we're at least hoping to experiment with.

As for the programmatic API, technically we can't easily use that right now anyways just because we are using native ESM and need to spawn a Node process with --experimental-vm-modules. Angular CLI won't have that flag (unless users remember to pass it when running ng test) so we need to spawn a second Node process just to set the flag. As a result, running Jest as a separate Node process with --expeirmental-vm-modules is the best place to do that.

We could avoid that and fork the Angular CLI process instead, but the Jest programmatic API would need to be useful enough to make that desirable. Overriding the config is something we could already do even when running Jest as a separate process, so I'm not sure how useful it would be in this particular case. Structured test result data would be nice, but we'd probably rather rely on Jest's built-in reporter instead of trying to build our own on top of a generic test result data structure. Are there specific features planned for this which might be useful for Angular?

@nicojs
Copy link
Contributor

nicojs commented Oct 18, 2023

As for the programmatic API, technically we can't easily use that right now anyways just because we are using native ESM and need to spawn a Node process with --experimental-vm-modules.

This would be fine for StrykerJS, since Stryker spawns a separate process for a test runner anyway. So we can already pass --experimental-vm-modules that way.

As a result, running Jest as a separate Node process with --experimental-vm-modules is the best place to do that.

Yes, that is what we're planning to do.

We could avoid that and fork the Angular CLI process instead, but the Jest programmatic API would need to be useful enough to make that desirable.

If I understand this correctly, you're opting to do Angular work with just the normal jest CLI, but with a build step before running the tests, is that correct? This would put Angular back in the camp that says: "let's not recreate our build pipeline in our test pipeline". I would love that 😻! That would mean that Stryker would work with a simple --buildCommand (something like ng build --test). We could run jest as we would normally.

@dgp1130
Copy link
Collaborator

dgp1130 commented Oct 25, 2023

If I understand this correctly, you're opting to do Angular work with just the normal jest CLI, but with a build step before running the tests, is that correct? This would put Angular back in the camp that says: "let's not recreate our build pipeline in our test pipeline". I would love that 😻!

That's the idea. It's still TBD if this will actually work out in practice given performance and maintainability concerns, but it's what we're trying.

That would mean that Stryker would work with a simple --buildCommand (something like ng build --test). We could run jest as we would normally.

I would love to support something like this, though unfortunately it's not quite that simple. I think it's worth considering adding this kind of functionality, but that's a separate question from the Jest configuration. I created #26132 to track that specific feature request.

@swebber-upngo
Copy link

I'm currently working with angular-builders/jest and jest-preset-angular and would like to convert to built in runner if possible. Here are the things we are configuring in jest.config.js:

  • transform: pug -> we will be removing this as we convert to new angular control syntax with html. Not needed, but I can see where other transforms may be desired
  • testEnvironmentOptions.url -> we have some tests that create full URLs. This setting was necessary to eliminate surprise base domains.
  • cacheDirectory -> We run our entire local dev environment inside docker and we need this for performance
  • moduleNameMapper -> We have custom tsconfig paths and this is required to make Jest obey them. Ideally, this would be built in to your solution and not require custom config

@a-boertien
Copy link

I recently upgraded a project to A16 and wanted to move to Jest with the built in runner.
I also found myself having to use angular-builders/jest and jest-preset-angular

The blocker I ran into was that the built in runner doesn't handle SCSS @use -- some relationship to #25131 ?

(I'm also using moduleNameMapper, which given the previous comment, also seems like it would be an issue?)

@johncrim
Copy link

I would love to use the ng jest runner as well, but as of Sept (and I don't believe there have been any updates since) there are a lot of gaps between what the current ng jest runner can do and what is needed to use it in production - see my list above.

Right now jest-preset-angular is incompatible with typescript 5, and typescript 5 is required by ng 17.

dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Jan 11, 2024
Currently with Jest we're experimenting with whether or not Angular CLI can meet user needs without exposing the underlying configuration file. See angular#25434 (comment) for more context.

Jest was incorrectly picking up custom configurations, even though they exist outside Jest's root directory. This commit fixes that behavior so Jest does not see user configurations and does not apply them.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Jan 11, 2024
Currently with Jest we're experimenting with whether or not Angular CLI can meet user needs without exposing the underlying configuration file. See angular#25434 (comment) for more context.

Jest was incorrectly picking up custom configurations, even though they exist outside Jest's root directory. This commit fixes that behavior so Jest does not see user configurations and does not apply them. Ideally we would throw an error if a Jest configuration is found to be more clear that it isn't doing what developers expect. However they may use a Jest config to run other projects in the same workspace outside of Angular CLI and we don't want to prevent that. A warning seems like the best trade off of notifying users that a custom config isn't supported while also not preventing unrelated Jest usage in the same workspace.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Jan 11, 2024
Currently with Jest we're experimenting with whether or not Angular CLI can meet user needs without exposing the underlying configuration file. See angular#25434 (comment) for more context.

Jest was incorrectly picking up custom configurations, even though they exist outside Jest's root directory. This commit fixes that behavior so Jest does not see user configurations and does not apply them. Ideally we would throw an error if a Jest configuration is found to be more clear that it isn't doing what developers expect. However they may use a Jest config to run other projects in the same workspace outside of Angular CLI and we don't want to prevent that. A warning seems like the best trade off of notifying users that a custom config isn't supported while also not preventing unrelated Jest usage in the same workspace.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Jan 11, 2024
Currently with Jest we're experimenting with whether or not Angular CLI can meet user needs without exposing the underlying configuration file. See angular#25434 (comment) for more context.

Jest was incorrectly picking up custom configurations, even though they exist outside Jest's root directory. This commit fixes that behavior so Jest does not see user configurations and does not apply them. Ideally we would throw an error if a Jest configuration is found to be more clear that it isn't doing what developers expect. However they may use a Jest config to run other projects in the same workspace outside of Angular CLI and we don't want to prevent that. A warning seems like the best trade off of notifying users that a custom config isn't supported while also not preventing unrelated Jest usage in the same workspace.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Jan 11, 2024
…file and warn if one is found

Currently with Jest we're experimenting with whether or not Angular CLI can meet user needs without exposing the underlying configuration file. See angular#25434 (comment) for more context.

Jest was incorrectly picking up custom configurations, even though they exist outside Jest's root directory. This commit fixes that behavior so Jest does not see user configurations and does not apply them. Ideally we would throw an error if a Jest configuration is found to be more clear that it isn't doing what developers expect. However they may use a Jest config to run other projects in the same workspace outside of Angular CLI and we don't want to prevent that. A warning seems like the best trade off of notifying users that a custom config isn't supported while also not preventing unrelated Jest usage in the same workspace.
@nicojs
Copy link
Contributor

nicojs commented Feb 16, 2024

For anyone interested in jest support for angular. I've found and documented a way to debug jest tests, see #27117.

I've also found a way to run StrykerJS with an Angular project using the experimental jest support: see https://stryker-mutator.io/docs/stryker-js/guides/angular/#angular-with-experimental-jest-support.

I would still love to resolve this issue, though.

@vypsim
Copy link

vypsim commented Feb 16, 2024

Adding our use case to this, we need a way to generate jest-junit reports for integration with the build pipeline. The package has ~5M weekly downloads, so I assume that would be a common requirement.

@PhOder
Copy link

PhOder commented Feb 17, 2024

Hi there and first of all thanks for adding native jest support!

This might have been implicitly mentioned above already in this list as setupFilesAfterEnv but I'd like to add this still:

We're using Testing Library Angular and its custom DOM matchers jest-dom. Usually I'd add custom matchers in a setup-jest.js file.

@tsteuwer-accesso
Copy link

tsteuwer-accesso commented Mar 18, 2024

Hello. Thanks for adding Jest support. It's a really great to see you guys supporting other options besides Karma and Jasmine.

I'd like to also note that this is currently not working if you use any sort of @layer in your CSS. That's because Jest uses jsdom which uses cssom and cssom doesn't support @layers or @support at the moment.

We need access to disable CSS parsing errors but we can't because we can't use our own jest.config.js. We'd like to use PrimeNG but we can't due to this such as jsdom/jsdom#2177 (comment)

primefaces/primeng#14085 - PrimeNG issue which references...
jsdom/jsdom#2026 - JSDom which references...
NV/CSSOM#109 (comment) - CSSOM

I'd say this is pretty big issue because we use @supports all the time and I'd argue a lot of enterprise companies use it. UPDATE 1 Looks like they do support @supports now. But layers don't work.

UPDATE 2 - It looks like it doesn't support most @ properties like @container either. So this is a bigger issue than I thought as CSSOM is no longer maintained and there's no mention of JSDOM using a different CSS parser.

@dsteindo
Copy link

Hello,

I stumbled accross this issue as I did an upgrade of an existing project to Angular 18 and noticed that Karma has a deprecation notice, see https://github.com/karma-runner/karma.

When I tried moving to jest many of the existing tests failed and many jasmine matchers (e.g. toBeTrue, toHaveBeenCalledOnceWith ...) did not work anymore, for this I usually go with jest-extended, see https://github.com/jest-community/jest-extended

Following the guide https://jest-extended.jestcommunity.dev/docs/getting-started/setup I added this to my package.json

"jest": {
  "setupFilesAfterEnv": ["jest-extended/all"]
}

Then I got a warning which linked me to this issue.

Personally I find it awesome that jest gets native support by angular but the limitations make it really difficult to migrate for us.

Also we seem to have issues with tests that utilize Angular Materials in some way.

I hope this issue gets more visibility and might get some resolution as it would be a dream to get jest working with "ng test" without having to rewrite all tests, just because we can't extend the configuration ...

@dgp1130
Copy link
Collaborator

dgp1130 commented Jun 11, 2024

I hope this issue gets more visibility and might get some resolution as it would be a dream to get jest working with "ng test" without having to rewrite all tests

Web Test Runner is intended to be the migration target from Karma as that will allow us to drop Jasmine in basically unchanged and should be much easier to migrate to. Jest is intended as an option for new apps to consider or existing apps who are willing to spend to a non-trivial amount of effort updating their tests and think that's worth the investment.

@dsteindo
Copy link

dsteindo commented Jun 11, 2024

It might also be that I have issues grasping what actually needs to be done to migrate an existing project to Web Test Runner.

For now I followed these guide https://blog.angular.dev/moving-angular-cli-to-jest-and-web-test-runner-ef85ef69ceca

So maybe for me to understand is that we should no longer use ng test and switch to npm test as descibed here https://medium.com/@ayushgrwl365/jesting-your-angular-app-simplifying-unit-testing-with-jest-324f5bb9e2df
^ this article also explains a way how I can use setupFilesAfterEnv in some capacity

there is also this article: which I find even harder to understand:
https://medium.com/@rathoreaparna678/moving-angular-cli-to-jest-and-web-test-runner-d2966e1c5802

I definetly have to try out more things as the goal would be to be able to use jest-extended in an angular project,

It also might just be that much of the information on the internet might conflict and there are many articles but rarely a github repo or something is linked to see it in action.

Update: I got it working what I wanted and created a github repository ...

---> https://github.com/dsteindo/jest-extended-angular

@dgp1130
Copy link
Collaborator

dgp1130 commented Jun 11, 2024

Both Web Test Runner and Jest support are still experimental and in-progress. We're not at the stage of authoring comprehensive docs yet, so it does take some effort to figure out. I wouldn't recommend moving a production Angular application to them just yet, and the Karma team has committed to maintaining support until Angular is able to support a move off of it, so there's no urgent need for you to do anything about this today. But do feel free to experiment with WTR or Jest and report any issues or limitations you notice.

So maybe for me to understand is that we should no longer use ng test and switch to npm test as descibed here https://medium.com/@ayushgrwl365/jesting-your-angular-app-simplifying-unit-testing-with-jest-324f5bb9e2df ^ this article also explains a way how I can use setupFilesAfterEnv in some capacity

That's using jest-preset-angular, which is a different project. This issue is talking about the @angular-devkit/build-angular:jest builder directly supported in the CLI. You should be able to use ng test just fine with it.

@ManuelRauber
Copy link

For my current project, the experimental jest support works great.

There's only one thing I miss: the option to specify reporters or at least use the default reporter (or the mentioned junit-reporter).

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

No branches or pull requests