id | title |
---|---|
troubleshooting |
Troubleshooting |
You can check Jest troubleshooting guide
Problems may arise if you're using custom builds (this preset is tailored for angular-cli
as firstly priority). Please be advised that every entry in default configuration may be overridden to best suite your app's needs.
With Angular 8 and higher, a change to the way the Angular CLI works may be causing your metadata to be lost. You can update your tsconfig.spec.json
to include the emitDecoratorMetadata
compiler option:
"compilerOptions": {
"emitDecoratorMetadata": true
In general, this is related to Angular's reflection and also depends on a reflection library, as e. g. included in core-js
. We use our own minimal reflection that satisfy Angular's current requirements, but in case these change, you can install core-js
and import the reflection library in your setup-jest.ts
:
// setup-jest.ts
require('core-js/es/reflect');
require('core-js/proposals/reflect-metadata');
Note that this might also be related to other issues with the dependency injection and parameter type reflection.
This issue is not related to Jest, it's a known Angular bug
To mitigate this, you need to wrap your component under test, into some container component with default change detection strategy (ChangeDetectionStrategy.Default
) and pass props through it, or overwrite change detection strategy within TestBed
setup, if it's not critical for the test.
// override change detection strategy
beforeEach(async(() => {
TestBed.configureTestingModule({ declarations: [PizzaItemComponent] })
.overrideComponent(PizzaItemComponent, {
set: { changeDetection: ChangeDetectionStrategy.Default },
})
.compileComponents();
}));
The currently used JSDOM version handles this, but older versions used before v7 of this preset was missing transform property. To patch it for Angular Material, use this workaround.
Add this to your jestGlobalMocks
file
// jestGlobalMocks.ts
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
Reference: angular/components#7101
This means, that a file is not transformed through TypeScript
compiler, e.g. because it is a JS
file with TS
syntax, or
it is published to npm as uncompiled source files. Here's what you can do. A typical Jest error is like this:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
To fix the issue, one needs to adjust transformIgnorePatterns
whitelist:
// jest.config.js
module.exports = {
// ...other options
transformIgnorePatterns: ['node_modules/(?!@angular|@ngrx)'],
};
By default, Jest doesn't transform node_modules
, because they should be valid JavaScript files. However, it happens that
library authors assume that you'll compile their sources. So you have to tell this to Jest explicitly.
Above snippet means that @angular
, @ngrx
will be transformed, even though they're node_modules
.
If the dependency causing the issue is a sub dependency of a node_modules
packages or a module designed to be used with nodeJS, a custom resolver could be required to fix the issue. See below for more information.
The same like normal Jest configuration, you can load jQuery in your Jest setup file. For example your Jest setup file is setup-jest.ts
you can declare jQuery:
// setup-jest.ts
window.$ = require('path/to/jquery');
or
// setup-jest.ts
import $ from 'jquery';
global.$ = global.jQuery = $;
The same declaration can be applied to other vendor libraries.
Reference: jestjs/jest#708
This issue happens because Jest uses Babel
behind the screen to create coverage reporter. To fix this issue, one can do the following:
- Install
babel-jest
,@babel/core
and@babel/preset-env
- Create a
.babelrc
at the same place where Jest config file locates and define the necessaryBabel
plugins. For example
{
// this plugin will fix issue with class inheritance
"plugins": ["@babel/plugin-transform-classes"]
}
- Define the usage of
Babel
in Jest config viats-jest
option, for example
// jest.config.js
module.exports = {
globals: {
'ts-jest': {
//...
babelConfig: true
}
}
}
This can happen in two identified cases.
When using a javascript SDK/Library in Angular, some javascript methods could fail to be properly rendered in tests. Some examples are the firebase
and firebase/compat
SDK.
A typical error could appear as:
TypeError: Cannot read properties of undefined (reading 'FacebookAuthProvider')
import firebase from 'firebase/compat/app';
> export const facebookAuthProvider = new firebase.auth.FacebookAuthProvider();
Some nested dependency tree could trigger some errors while running the tests because some bundles (especially ESM ones) could be somehow errored. An example is the @angular/fire
package which uses the @firebase/firestore
package.
A typical error could appear as:
node_modules\@angular\fire\node_modules\@firebase\firestore\dist\index.esm2017.js:12705
function (t, e) {
^^^^^^^^
SyntaxError: Function statements require a function name
In these cases, a transformIgnorePatterns
whitelisting could not fix the issue. The solution here is to use a custom resolver
. You may or may not need to remove entries from transformIgnorePatterns
whitelisting.
Here is an example of a resolver which would fix firebase
related packages.
// jest.resolver.js
module.exports = (path, options) => {
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: (pkg) => {
const pkgNamesToTarget = new Set([
'rxjs',
'@firebase/auth',
'@firebase/storage',
'@firebase/functions',
'@firebase/database',
'@firebase/auth-compat',
'@firebase/database-compat',
'@firebase/app-compat',
'@firebase/firestore',
'@firebase/firestore-compat',
'@firebase/messaging',
'@firebase/util',
'firebase',
]);
if (pkgNamesToTarget.has(pkg.name)) {
// console.log('>>>', pkg.name)
delete pkg['exports'];
delete pkg['module'];
}
return pkg;
},
});
};
// jest.config.js
module.exports = {
resolver: '<rootDir>/src/jest.resolver.js',
};
Please use Angular inject instead of @Inject.
This is because jest-preset-angular
has caveat when working with class constructor and decorator.