Skip to content

Commit 7f7d0f4

Browse files
committed
feat: Jest 24 (#224)
This is a PoC. Jest 24 works without any changes from our side. It added some defaults to TS but we use slightly different ones (e.g. no `.tsx`). However, until `ts-jest` updates, we'll likely need to hold off with the upgrade, because of peer dep warnings. Fixes #223
1 parent 00468eb commit 7f7d0f4

File tree

9 files changed

+2307
-1917
lines changed

9 files changed

+2307
-1917
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
2-
InlineHtmlStripStylesTransformer.js
2+
InlineHtmlStripStylesTransformer.js
3+
*.log

README.md

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# jest-preset-angular
2+
23
[![CircleCI Build Status](https://circleci.com/gh/thymikee/jest-preset-angular.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/thymikee/jest-preset-angular)
34
[![NPM version](https://img.shields.io/npm/v/jest-preset-angular.svg)](https://www.npmjs.com/package/jest-preset-angular)
45

56
A preset of [Jest](http://facebook.github.io/jest) configuration for [Angular](https://angular.io/) projects.
67

78
This is a part of the article: [Testing Angular faster with Jest](https://www.xfive.co/blog/testing-angular-faster-jest/).
89

9-
*Note: This preset does not suport AngularJS (1.x). If you want to set up Jest with AngularJS, please see [this blog post](https://medium.com/aya-experience/testing-an-angularjs-app-with-jest-3029a613251).*
10+
_Note: This preset does not suport AngularJS (1.x). If you want to set up Jest with AngularJS, please see [this blog post](https://medium.com/aya-experience/testing-an-angularjs-app-with-jest-3029a613251)._
1011

1112
## Installation
1213

@@ -25,66 +26,62 @@ import 'jest-preset-angular';
2526
import './jestGlobalMocks'; // browser mocks globally available for every test
2627
```
2728

28-
*Note: feel free to copy the `jestGlobalMocks.ts` file from the example directory and save it next to the `setupJest.ts` file.*
29+
_Note: feel free to copy the `jestGlobalMocks.ts` file from the example directory and save it next to the `setupJest.ts` file._
2930

3031
...and include this in your `package.json`:
3132

3233
```json
3334
{
3435
"jest": {
3536
"preset": "jest-preset-angular",
36-
"setupTestFrameworkScriptFile": "<rootDir>/src/setupJest.ts"
37+
"setupFilesAfterEnv": ["<rootDir>/src/setupJest.ts"]
3738
}
3839
}
3940
```
4041

41-
## Exposed [configuration](https://github.com/thymikee/jest-preset-angular/blob/master/jest-preset.json)
42-
```json
43-
{
44-
"globals": {
45-
"ts-jest": {
46-
"tsConfig": "<rootDir>/src/tsconfig.spec.json",
47-
"stringifyContentPathRegex": "\\.html$",
48-
"astTransformers": [
49-
"jest-preset-angular/InlineHtmlStripStylesTransformer"
50-
]
51-
}
42+
## Exposed [configuration](https://github.com/thymikee/jest-preset-angular/blob/master/jest-preset.js)
43+
44+
```js
45+
module.exports = {
46+
globals: {
47+
'ts-jest': {
48+
tsConfig: '<rootDir>/src/tsconfig.spec.json',
49+
stringifyContentPathRegex: '\\.html$',
50+
astTransformers: [require.resolve('./InlineHtmlStripStylesTransformer')],
51+
},
5252
},
53-
"transform": {
54-
"^.+\\.(ts|js|html)$": "ts-jest"
53+
transform: {
54+
'^.+\\.(ts|js|html)$': 'ts-jest',
5555
},
56-
"testMatch": [
57-
"**/__tests__/**/*.+(ts|js)?(x)",
58-
"**/?(*.)+(spec|test).+(ts|js)?(x)"
59-
],
60-
"moduleFileExtensions": ["js", "json", "jsx", "node", "ts", "tsx", "html"],
61-
"moduleNameMapper": {
62-
"^src/(.*)$": "<rootDir>/src/$1",
63-
"^app/(.*)$": "<rootDir>/src/app/$1",
64-
"^assets/(.*)$": "<rootDir>/src/assets/$1",
65-
"^environments/(.*)$": "<rootDir>/src/environments/$1"
56+
testEnvironment: 'jest-environment-jsdom-thirteen',
57+
moduleFileExtensions: ['ts', 'html', 'js', 'json'],
58+
moduleNameMapper: {
59+
'^src/(.*)$': '<rootDir>/src/$1',
60+
'^app/(.*)$': '<rootDir>/src/app/$1',
61+
'^assets/(.*)$': '<rootDir>/src/assets/$1',
62+
'^environments/(.*)$': '<rootDir>/src/environments/$1',
6663
},
67-
"transformIgnorePatterns": [
68-
"node_modules/(?!@ngrx)"
64+
transformIgnorePatterns: ['node_modules/(?!@ngrx)'],
65+
snapshotSerializers: [
66+
'jest-preset-angular/AngularSnapshotSerializer.js',
67+
'jest-preset-angular/HTMLCommentSerializer.js',
6968
],
70-
"snapshotSerializers": [
71-
"jest-preset-angular/AngularSnapshotSerializer.js",
72-
"jest-preset-angular/HTMLCommentSerializer.js"
73-
]
74-
}
69+
};
7570
```
7671

7772
### Brief explanation of config
78-
* `<rootDir>` is a special syntax for root of your project (here by default it's project's root /)
79-
* 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
80-
* `"transform"` – run every TS, JS, or HTML file through so called *preprocessor* (we'll get there); this lets Jest understand non-JS syntax
81-
* `"testMatch"` – we want to run Jest on files that matches this glob
82-
* `"moduleFileExtensions"` – our modules are TypeScript and JavaScript files
83-
* `"moduleNameMapper"` – if you're using absolute imports here's how to tell Jest where to look for them; uses regex
84-
* `"setupTestFrameworkScriptFile"` – this is the heart of our config, in this file we'll setup and patch environment within tests are running
85-
* `"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.
73+
74+
- `<rootDir>` is a special syntax for root of your project (here by default it's project's root /)
75+
- 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
76+
- `"transform"` – run every TS, JS, or HTML file through so called _preprocessor_ (we'll get there); this lets Jest understand non-JS syntax
77+
- `"testMatch"` – we want to run Jest on files that matches this glob
78+
- `"moduleFileExtensions"` – our modules are TypeScript and JavaScript files
79+
- `"moduleNameMapper"` – if you're using absolute imports here's how to tell Jest where to look for them; uses regex
80+
- `"setupFilesAfterEnv"` – this is the heart of our config, in this file we'll setup and patch environment within tests are running
81+
- `"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.
8682

8783
## [AST Transformer](https://github.com/thymikee/jest-preset-angular/blob/master/src/InlineHtmlStripStylesTransformer.ts)
84+
8885
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.
8986

9087
## Angular testing environment setup
@@ -98,6 +95,7 @@ If you look at your `src/test.ts` (or similar bootstrapping test file) file you'
9895
Example:
9996

10097
`calc-component.spec.ts`
98+
10199
```ts
102100
// some initialization code
103101
test('renders markup to snapshot', () => {
@@ -107,6 +105,7 @@ test('renders markup to snapshot', () => {
107105
```
108106

109107
`__snapshots__/calc-component.spec.ts.snap`
108+
110109
```js
111110
// Jest Snapshot v1, https://goo.gl/fbAQLP
112111

@@ -152,27 +151,30 @@ This is indeed very repetitive, so you can extract this in a helper function:
152151
```ts
153152
// test-config.helper.ts
154153

155-
import { TestBed } from '@angular/core/testing'
154+
import { TestBed } from '@angular/core/testing';
156155

157156
type CompilerOptions = Partial<{
158-
providers: any[]
159-
useJit: boolean
160-
preserveWhitespaces: boolean
161-
}>
162-
export type ConfigureFn = (testBed: typeof TestBed) => void
163-
164-
export const configureTests = (configure: ConfigureFn, compilerOptions: CompilerOptions = {}) => {
157+
providers: any[];
158+
useJit: boolean;
159+
preserveWhitespaces: boolean;
160+
}>;
161+
export type ConfigureFn = (testBed: typeof TestBed) => void;
162+
163+
export const configureTests = (
164+
configure: ConfigureFn,
165+
compilerOptions: CompilerOptions = {}
166+
) => {
165167
const compilerConfig: CompilerOptions = {
166168
preserveWhitespaces: false,
167169
...compilerOptions,
168-
}
170+
};
169171

170-
const configuredTestBed = TestBed.configureCompiler(compilerConfig)
172+
const configuredTestBed = TestBed.configureCompiler(compilerConfig);
171173

172-
configure(configuredTestBed)
174+
configure(configuredTestBed);
173175

174-
return configuredTestBed.compileComponents().then(() => configuredTestBed)
175-
}
176+
return configuredTestBed.compileComponents().then(() => configuredTestBed);
177+
};
176178
```
177179

178180
And setup your test with that function like following:
@@ -228,18 +230,17 @@ To mitigate this, you need to wrap your component under test, into some containe
228230

229231
```ts
230232
// override change detection strategy
231-
beforeEach(
232-
async(() => {
233-
TestBed.configureTestingModule({ declarations: [PizzaItemComponent] })
234-
.overrideComponent(PizzaItemComponent, {
235-
set: { changeDetection: ChangeDetectionStrategy.Default },
236-
})
237-
.compileComponents();
238-
})
239-
);
233+
beforeEach(async(() => {
234+
TestBed.configureTestingModule({ declarations: [PizzaItemComponent] })
235+
.overrideComponent(PizzaItemComponent, {
236+
set: { changeDetection: ChangeDetectionStrategy.Default },
237+
})
238+
.compileComponents();
239+
}));
240240
```
241241

242242
### The animation trigger "transformMenu" has failed
243+
243244
JSDOM missing transform property when using Angular Material, there is a workaround for it.
244245

245246
Add this to your `jestGlobalMocks` file
@@ -254,6 +255,7 @@ Object.defineProperty(document.body.style, 'transform', {
254255
},
255256
});
256257
```
258+
257259
Reference: https://github.com/angular/material2/issues/7101
258260

259261
### Absolute imports
@@ -293,7 +295,7 @@ Override `globals` object in Jest config:
293295
{
294296
"jest": {
295297
"globals": {
296-
"ts-jest": {
298+
"ts-jest": {
297299
"tsConfigFile": "src/tsconfig.custom.json"
298300
},
299301
"__TRANSFORM_HTML__": true
@@ -309,7 +311,9 @@ If you choose to overide `globals` in order to point at a specific tsconfig, you
309311
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.
310312

311313
#### Adjust your `tsconfig.spec.json`:
314+
312315
Since Angular released v6, the default `tsconfig.json` and `tsconfig.spec.json` have been changed. Therefore, `jest` will throw an error
316+
313317
```
314318
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import 'jest-preset-angular';
315319
^^^^^^
@@ -320,6 +324,7 @@ Since Angular released v6, the default `tsconfig.json` and `tsconfig.spec.json`
320324
What you need to do is adjust your `tsconfig.spec.json` to add the option `"module": "commonjs",`
321325

322326
A default `tsconfig.spec.json` after modifying will look like this
327+
323328
```
324329
{
325330
"extends": "../tsconfig.json",
@@ -353,19 +358,23 @@ A default `tsconfig.spec.json` after modifying will look like this
353358
}
354359
}
355360
```
361+
356362
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 transforemed, even though they're `node_modules`.
357363

358364
#### Allow JS files in your TS `compilerOptions`
365+
359366
```json
360367
{
361368
"compilerOptions": {
362369
"allowJs": true
363370
}
364371
}
365372
```
373+
366374
This tells `ts-jest` (a preprocessor this preset using to transform TS files) to treat JS files the same as TS ones.
367375

368376
#### Transpile js files through `babel-jest`
377+
369378
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.
370379

371380
1. Install `@babel/preset-env` and add `babel.config.js` (or modify existing if needed) with the following content:
@@ -387,6 +396,7 @@ module.exports = function(api) {
387396
*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](https://babeljs.io/docs/en/configuration#what-s-your-use-case) and the comment `You want to compile node_modules? babel.config.js is for you!`*.
388397

389398
2. Update Jest configuration (by default TypeScript process untranspiled JS files which is source of the problem):
399+
390400
```js
391401
{
392402
"jest": {
@@ -445,4 +455,3 @@ By default we use JSDOM v13, which requires Node v8+. If you want to use Node in
445455
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`.
446456

447457
Reference: https://jestjs.io/docs/en/configuration.html#testenvironment-string, https://github.com/jsdom/jsdom/blob/master/Changelog.md#1200
448-

example/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232
"@angular-devkit/build-angular": "^0.7.3",
3333
"@angular/cli": "^6.1.3",
3434
"@angular/compiler-cli": "6.1.2",
35-
"@types/jest": "^23.3.14",
35+
"@types/jest": "^24.0.0",
3636
"@types/node": "^10.5.8",
3737
"codelyzer": "^4.4.3",
38-
"jest": "^23.5.0",
38+
"jest": "^24.0.0",
3939
"jest-preset-angular": "file:../",
4040
"protractor": "^5.4.0",
4141
"ts-node": "^7.0.1",
@@ -48,6 +48,8 @@
4848
"\\.(jpg|jpeg|png)$": "<rootDir>/__mocks__/image.js",
4949
"^@lib/(.*)$": "<rootDir>/src/lib/$1"
5050
},
51-
"setupTestFrameworkScriptFile": "<rootDir>/src/setupJest.ts"
51+
"setupFilesAfterEnv": [
52+
"<rootDir>/src/setupJest.ts"
53+
]
5254
}
5355
}

0 commit comments

Comments
 (0)