Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
jest-preset-angular
Advanced tools
jest-preset-angular is a Jest preset configuration for Angular projects. It simplifies the setup and configuration of Jest for testing Angular applications, providing necessary configurations, transformers, and environment settings.
Setup and Configuration
This feature provides a preset configuration for Jest, making it easier to set up Jest in Angular projects. The code sample shows how to configure Jest to use jest-preset-angular in the Jest configuration file.
module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'] };
Transformers
jest-preset-angular includes transformers to handle TypeScript and Angular templates. The code sample demonstrates how to configure Jest to use ts-jest for transforming TypeScript and HTML files.
module.exports = { transform: { '^.+\.(ts|html)$': 'ts-jest' } };
Global Mocks
jest-preset-angular provides global mocks for common Angular dependencies, such as Angular's testing utilities. The code sample shows how to import jest-preset-angular to include these global mocks in your tests.
import 'jest-preset-angular';
Karma is a test runner for JavaScript that works well with Angular. Unlike jest-preset-angular, which is a Jest preset, Karma is a standalone test runner that can be configured to work with various testing frameworks, including Jasmine and Mocha.
angular-testing-library is a set of utilities for testing Angular components. It focuses on testing user interactions and component behavior, similar to jest-preset-angular, but it is not a Jest preset and can be used with different test runners.
ng-mocks is a library for creating mocks of Angular components, directives, and services. It complements jest-preset-angular by providing additional mocking capabilities, but it is not a preset configuration for Jest.
A preset of Jest configuration for Angular projects.
This is a part of the article: Testing Angular faster with Jest.
ChangeDetectionStrategy.OnPush
is usedInstall using yarn
:
yarn add -D jest jest-preset-angular
Or npm
:
npm install -D jest jest-preset-angular
In your project root, create setup-jest.ts
file with following contents:
import 'jest-preset-angular';
import './jest-global-mocks'; // browser mocks globally available for every test
Note: feel free to copy the jest-global-mocks.ts
file from the test app directory and save it next to the setup-jest.ts
file.
Add the following section:
jest.config.js
// jest.config.js
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts']
}
package.json
{
"jest": {
"preset": "jest-preset-angular",
"setupFilesAfterEnv": ["<rootDir>/setup-jest.ts"]
}
}
jest-preset-angular
provides util script ngcc-jest-processor
which can help to run ngcc
before running tests.
ngcc-jest-processor
will compile any Angular format packages to umd
format which is compatible with CommonJS
that
Jest is using.
Add to the top of your root jest.config.js
:
require('jest-preset-angular/ngcc-jest-processor');
module.exports = {
// jest config options
}
By Angular CLI defaults you'll have a src/test.ts
file which will be picked up by jest. To circumvent this you can either rename it to src/karmaTest.ts
or hide it from jest by adding <rootDir>/src/test.ts
to jest testPathIgnorePatterns
option.
const customTransformers = require('./build/transformers');
const snapshotSerializers = require('./build/serializers');
module.exports = {
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.html$',
astTransformers: {
before: customTransformers,
},
},
},
testEnvironment: 'jsdom',
transform: {
'^.+\\.(ts|js|html)$': 'jest-preset-angular',
},
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1',
'^app/(.*)$': '<rootDir>/src/app/$1',
'^assets/(.*)$': '<rootDir>/src/assets/$1',
'^environments/(.*)$': '<rootDir>/src/environments/$1',
},
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
snapshotSerializers,
};
<rootDir>
is a special syntax for root of your project (here by default it's project's root /)
we're using some "globals"
to pass information about where our tsconfig.json file is that we'd like to be able to transform HTML files through ts-jest
"transform"
– run every TS, JS, or HTML file through so called preprocessor (we'll get there); this lets Jest understand non-JS syntax
"testMatch"
– we want to run Jest on files that matches this glob
"moduleFileExtensions"
– our modules are TypeScript and JavaScript files
"moduleNameMapper"
– if you're using absolute imports here's how to tell Jest where to look for them; uses regex
"setupFilesAfterEnv"
– this is the heart of our config, in this file we'll setup and patch environment within tests are running
"transformIgnorePatterns"
– unfortunately some modules (like @ngrx) are released as TypeScript files, not pure JavaScript; in such cases we cannot ignore them (all node_modules are ignored by default), so they can be transformed through TS compiler like any other module in our project.
"snapshotSerializers"
- array of serializers which will be applied to snapshot the code. Note: by default angular
adds some angular-specific attributes to the code (like ng-reflect-*
, ng-version="*"
, _ngcontent-c*
etc).
This package provides serializer to remove such attributes. This makes snapshots cleaner and more human-readable.
To remove such specific attributes use AngularNoNgAttributesSnapshotSerializer
serializer.
You need to add AngularNoNgAttributesSnapshotSerializer
serializer manually (see test
app configuration).
Jest doesn't run in browser nor through dev server. It uses jsdom to abstract browser environment. So we have to cheat a little and inline our templates and get rid of styles (we're not testing CSS) because otherwise Angular will try to make XHR call for our templates and fail miserably.
If you look at setup-jest.ts
, what we're doing here is we're adding globals required by Angular. With the included jest-zone-patch we also make sure Jest test methods run in Zone context. Then we initialize the Angular testing environment like normal.
Since version 1.1.0 it's possible to snapshot test your Angular components. Please note it's still under active development and may be a subject of change. You can lookup test app for details
Example:
calc-component.spec.ts
// some initialization code
test('renders markup to snapshot', () => {
const fixture = TestBed.createComponent(AppComponent);
expect(fixture).toMatchSnapshot();
});
__snapshots__/calc-component.spec.ts.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CalcComponent should snap 1`] = `
<app-calc
prop1={[Function Number]}
>
<p
class="a-default-class"
ng-reflect-klass="a-default-class"
ng-reflect-ng-class="[object Object]"
>
calc works!
</p>
</app-calc>
`;
You will immediately notice, that your snapshot files contain a lot of white spaces and blank lines. This is not an issue with Jest, rather with Angular. It can be mitigated via Angular compiler by setting preserveWhitespaces: false
By default it's set to
true
Angular 7.x, although it may change to be set tofalse
in upcoming versions (if that occurs, you can stop reading right here, because your issue has been already solved)
Your TestBed
setup should look like following:
describe('Component snapshot tests', ()=>{
// you need to turn TS checking because it's an private API
const compilerConfig = {preserveWhitespaces: false} as any
beforeEach(() => {
TestBed.configureCompiler(compilerConfig)
.configureTestingModule({...});
});
})
This is indeed very repetitive, so you can extract this in a helper function:
// test-config.helper.ts
import { TestBed } from '@angular/core/testing';
type CompilerOptions = Partial<{
providers: any[];
useJit: boolean;
preserveWhitespaces: boolean;
}>;
export type ConfigureFn = (testBed: typeof TestBed) => void;
export const configureTests = (
configure: ConfigureFn,
compilerOptions: CompilerOptions = {}
) => {
const compilerConfig: CompilerOptions = {
preserveWhitespaces: false,
...compilerOptions,
};
const configuredTestBed = TestBed.configureCompiler(compilerConfig);
configure(configuredTestBed);
return configuredTestBed.compileComponents().then(() => configuredTestBed);
};
And setup your test with that function like following:
// foo.component.spec.ts
import { async, ComponentFixture } from '@angular/core/testing'
import { configureTests, ConfigureFn } from '../test-config.helper'
import { AppComponent } from './foo.component';
describe('Component snapshots', () => {
let fixture: ComponentFixture<FooComponent>;
let component: FooComponent;
beforeEach(
async(() => {
const configure: ConfigureFn = testBed => {
testBed.configureTestingModule({
declarations: [FooComponent],
schemas: [NO_ERRORS_SCHEMA],
});
};
configureTests(configure).then(testBed => {
fixture = testBed.createComponent(FooComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
})
);
it(`should create snapshots without blank lines/white spaces`, () => {
expect(fixture).toMatchSnapshot();
});
})
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
:
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.
ChangeDetectionStrategy.OnPush
is usedThis 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
Object.defineProperty(document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
Reference: https://github.com/angular/material2/issues/7101
TypeScript supports absolute imports. The preset (starting from v3.0.0) by default understands absolute imports referring to src
, app
, assets
and environments
directory, so instead:
import MyComponent from '../../src/app/my.component';
import MyStuff from '../../src/testing/my.stuff';
you can use:
import MyComponent from 'app/my.component';
import MyStuff from 'src/testing/my.stuff';
However, if your directory structure differ from that provided by angular-cli
you can adjust moduleNameMapper
in Jest config:
{
"jest": {
"moduleNameMapper": {
"app/(.*)": "<rootDir>/src/to/app/$1", // override default, why not
"testing/(.*)": "<rootDir>/app/testing/$1" // add new mapping
}
}
}
Override globals
object in Jest config:
{
"jest": {
"globals": {
"ts-jest": {
"tsconfig": "<rootDir>/tsconfig.custom.json",
"stringifyContentPathRegex": "\\.html$",
"astTransformers": {
"before": [
"jest-preset-angular/build/InlineFilesTransformer",
"jest-preset-angular/build/StripStylesTransformer"
]
}
}
}
}
}
If you choose to overide globals
in order to point at a specific tsconfig, you will need to add the astTransformers
to the globals.ts-jest
section too, otherwise you will get parse errors on any html templates.
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.
tsconfig.spec.json
:Since Angular released v6, the default tsconfig.json
and tsconfig.spec.json
have been changed. Therefore, jest
will throw an error
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import 'jest-preset-angular';
^^^^^^
SyntaxError: Unexpected token import
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
What you need to do is adjust your tsconfig.spec.json
to add the option "module": "commonjs",
A default tsconfig.spec.json
after modifying will look like this
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"module": "commonjs",
"types": [
"jest",
"jsdom",
"node"
]
},
"include": [
"**/*.d.ts"
]
transformIgnorePatterns
whitelist:{
"jest": {
"transformIgnorePatterns": [
"node_modules/(?!@ngrx|angular2-ui-switch|ng-dynamic)"
]
}
}
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 @ngrx
, angular2-ui-switch
and ng-dynamic
will be transformed, even though they're node_modules
.
compilerOptions
{
"compilerOptions": {
"allowJs": true
}
}
This tells ts-jest
(a preprocessor this preset using to transform TS files) to treat JS files the same as TS ones.
babel-jest
Some vendors publish their sources without transpiling. You need to say jest to transpile such files manually since typescript
(and thus ts-jest
used by this preset) do not transpile them.
Install dependencies required by the official Jest documentation for Babel integration.
Install @babel/preset-env
and add babel.config.js
(or modify existing if needed) with the following content:
module.exports = function(api) {
api.cache(true);
const presets = ['@babel/preset-env'];
const plugins = [];
return {
presets,
plugins,
};
};
Note: do not use a .babelrc
file otherwise the packages that you specify in the next step will not be picked up. CF Babel documentation and the comment You want to compile node_modules? babel.config.js is for you!
.
module.exports = {
transform: {
"^.+\\.(ts|html)$": "ts-jest",
"^.+\\.js$": "babel-jest"
},
}
Note: This fix is only relevant to Angular v5 and lower.
Since v1.0 this preset doesn't import whole rxjs
library by default for variety of reasons. This may result in breaking your tests that relied on this behavior. It may however become cumbersome to include e.g. rxjs/add/operator/map
or rxjs/add/operator/do
for every test, so as a workaround you can include common operators or other necessary imports in your setup-jest.ts
file:
import 'jest-preset-angular/setup-jest';
// common rxjs imports
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
// ...
import './jestGlobalMocks';
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:
window.$ = require('path/to/jquery');
or
import $ from 'jquery';
global.$ = global.jQuery = $;
The same declaration can be applied to other vendor libraries.
Reference: https://github.com/facebook/jest/issues/708
Jest v26 by default uses JSDOM 16 to support Node 10+.
If you need a different JSDOM version than the one that ships with Jest, you can install a jsdom environment
package, e.g. jest-environment-jsdom-sixteen
and edit your Jest config like so:
{
"testEnvironment": "jest-environment-jsdom-sixteen"
}
If you use JSDOM v11 or lower, you might have to mock localStorage
or sessionStorage
on your own or using some third-party library by loading it in setupFilesAfterEnv
.
Reference: https://jestjs.io/docs/en/configuration.html#testenvironment-string, https://github.com/jsdom/jsdom/blob/master/Changelog.md#1200
jest-preset-angular is MIT licensed.
9.0.0-next.4 (2020-12-18)
cacheFS
from jest to reduce file system reading (#679) (f5d9d4b)skipLibCheck: true
if not defined in tsconfig (#678) (0df3ce1)skipLibCheck
is not defined in tsconfig, jest-preset-angular
will set it to true
. If one wants to have it as false
, one can set explicitly in tsconfig.FAQs
Jest preset configuration for Angular projects
The npm package jest-preset-angular receives a total of 226,780 weekly downloads. As such, jest-preset-angular popularity was classified as popular.
We found that jest-preset-angular demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.