nx: `nx test` (jest) cannot resolve tsconfig paths after migration to nx 14.x

Current Behavior

After migrating to nx 14, all my tests that import modules from aliased paths (from my libs) fail. The app builds fine and VSCode shows no issues with the module resolution, but when running tests, jest is no longer able to resolve my path aliases:

image image

Expected Behavior

The tests should pass.

Steps to Reproduce

nx migrate latest on my main branch here:

https://github.com/hevans90/idleverse

Then nx test to run my default project’s testing suite with the failing tests.

OR, check out this branch and nx test:

https://github.com/hevans90/idleverse/tree/build/nx-14


This issue may not be prioritized if details are not provided to help us reproduce the issue.

Failure Logs

Environment

Node : 16.13.2 OS : darwin x64 yarn : 1.22.18

nx : 14.2.2 @nrwl/angular : Not Found @nrwl/cypress : 14.2.2 @nrwl/detox : Not Found @nrwl/devkit : 14.2.2 @nrwl/eslint-plugin-nx : 14.2.2 @nrwl/express : Not Found @nrwl/jest : 14.2.2 @nrwl/js : 14.2.2 @nrwl/linter : 14.2.2 @nrwl/nest : Not Found @nrwl/next : Not Found @nrwl/node : 14.2.2 @nrwl/nx-cloud : 14.0.8 @nrwl/nx-plugin : Not Found @nrwl/react : 14.2.2 @nrwl/react-native : Not Found @nrwl/schematics : Not Found @nrwl/storybook : 14.2.2 @nrwl/web : 14.2.2 @nrwl/workspace : 14.2.2 typescript : 4.7.3

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 17 (4 by maintainers)

Most upvoted comments

@jonwalstedt thanks for the diff, it looks like it was when I changed the nxPreset. Looking at your root jest.preset.js it doesn’t have the updated version @hevans90

You’ll want to add .default to the nxPreset import.

- const nxPreset = require('@nrwl/jest/preset');
+ const nxPreset = require('@nrwl/jest/preset').default;

module.exports = { ...nxPreset };

This should have been fixed in v14.1.5 migration for you. You can try rerunning that migration to see if it’s added as you’re preset is the default so there isn’t a reason it shouldn’t work. Or just manually make that change. This was causing the @nrwl/jest/plugins/resolver to not resolve the module names.

Hello @barbados-clemens , I work with @christophechevalier . I didn’t succeed to make a Stackblitz project reproducing the error, so I created a small project on github, available at this address. If you have any questions or problems do not hesitate to contact us.

That did the trick, thanks @barbados-clemens

Guys I managed to write an isolated test and I think I found some interesting things…

deptest-imports.ts

export interface DepTestInterface {
	endpoint?:string,
	userId?:number, 
	permissions?:string[],
}

export class DepTestClass {
	endpoint?:string
	userId?:number
	permissions?:string[]
}

deptest-interface.ts

export interface InterfaceFromInterfaceOnlyModule {
	endpoint?:string,
	userId?:number, 
	permissions?:string[],
}
export const DUMMY = null;

deptest.spec.ts


import { DepTestClass, DepTestInterface } from './deptest-imports';
import { InterfaceFromInterfaceOnlyModule , DUMMY } from './deptest-interface';

export function MyDecorator():MethodDecorator {
	return <T>(target,propertyKey,descriptor:TypedPropertyDescriptor<T>) => {}
}

export interface DepTestInlineInterface {
	endpoint?:string, // endpoint used to fetch user data from
	userId?:number, // type defines 
	permissions?:string[],
}

class X {
	// All fine ->
	static noDecorator1(state:any):DepTestInterface {return state.tokenData||null}
	static noDecorator2(state:any):InterfaceFromInterfaceOnlyModule {return state.tokenData||null}
	@MyDecorator()	static test2(state:any):number {return state.tokenData?.userId||null}
	@MyDecorator()	static test3(state:any):DepTestInlineInterface {return state.tokenData||null}
	// from imported module, still fine! ->
	@MyDecorator()	static test4(state:any):DepTestClass {return state.tokenData||null}
	@MyDecorator()	static test5(state:any):DepTestInterface {return state.tokenData||null}
	// errors ->
	@MyDecorator()	static test6(state:any):InterfaceFromInterfaceOnlyModule {return state.tokenData||null}
}

describe('test', () => {
	it('should work', () => { expect(true).toBe(true) });
});

So far, executing that test with jest 28 + ts-node fails reliably with same error: ReferenceError: deptest_interface_1 is not defined


EDIT: Created a new repo for reproduction. Issue only happens when jest-preset-angular is used for transformations. Repo here: https://github.com/jbjhjm/jest28-bug

It contains the same test suite 4 times:

  • src/tsjest - without nx, with ts-jest
  • src/ngdevkit - without nx, with jest-preset-angular
  • lib/test-tsjest - with nx, with ts-jest
  • lib/test-ngdevkit - with nx, with jest-preset-angular

I’m concluding following circumstances lead to the error:

  • Import a interface from a module that contains nothing but interfaces
  • Use it on a method that is being decorated
  • Have emitDecoratorMetadata enabled
  • use jest-preset-angular

Interestingly, only the last static function declaration errors, all of those before are fine. So this means it will only happen if a module exports only types. As soon as something else is exported and the module actually “exists”, the error is gone. You’ll see the test contains an unused “DUMMY” import. As soon as this is being used anywhere, the ReferenceError will disappear because the imported module is not type-only anymore.


Edit:

Summing up, this is not a nx issue. It seems that some implementation within jest-preset-angular causes this.

See https://github.com/thymikee/jest-preset-angular/issues/1810 https://github.com/thymikee/jest-preset-angular/issues/1199

Thanks for your PR @barbados-clemens , this solves the problem 😃

thanks for the reproduce-able @jcabannes and @christophechevalier

I was able to get the tests passing by setting emitDecoratorMetadata": false in the project level tsconfig.spec.json where the error is happening.

Assuming you don’t need reflection at test time this should be find to do. If you do need reflection at test time, then this could be an issue with angular devkit as noted in this issue from ngxs

Here is a PR against your reproduce-able showing it working. https://github.com/jcabannes/nx-angular-ngxs-jest/pull/1

Jest 28 yes.

"devDependencies": {
  "jest": "28.1.0",
  "jest-environment-jsdom": "28.1.0",
  "jest-preset-angular": "12.2.2",
  "ts-jest": "28.0.3",
}

I tried to upgrade the version of Jest to use 29.0.3 but I have compatibility issues with ts-jest which does not accept a version greater than or equal to 29.0.0. So I kept my current versions.

Stay tuned please, we might ask you again to review the code that reproduces our issue on Stackblitz soon.

is this with jest 28 @christophechevalier? this looks an error @FrozenPandaz ran into, which is basically ts-jest/jest-preset-angular was returning “different” transpiled code causing a null ref error since an import wasn’t being included. I think we are still trying to debug this ourselves, but doesn’t look to be directly an nx issue but maybe a transformer/downstream dep.

but any reproduceable would be helpful. we haven’t had much luck trying to track it down exactly where it’s happening.