Skip to content

Commit

Permalink
docs(devs-infra): update docs for possible issues in Angular 13 (#1153)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahnpnl authored Nov 9, 2021
1 parent db874ae commit 0ab958d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 64 deletions.
37 changes: 30 additions & 7 deletions website/docs/guides/angular-13+.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = {

there are no migration steps required

- If one is not having `preset: 'jest-preset-angular'` in Jest config, the config needs to be updated with new values for
- If one is **NOT** having `preset: 'jest-preset-angular'` in Jest config, the config needs to be updated with new values for
`resolver`, `transformIgnorePatterns` and `transform`:

```js
Expand All @@ -45,14 +45,37 @@ module.exports = {
};
```

:::important
Angular 13 libraries are also built automatically into ESM package format. Therefore, the Angular libraries should also
be added to `transformIgnorePatterns` to avoid Jest error `SyntaxError: Cannot use import statement outside a module`,
## Potential issues with Angular 13 ESM package format and workaround

Example config:
### Cannot import locale data from `@angular/common/locales` or any deep import paths

- Angular 13 ESM package format makes Jest resolution not able to resolve the correct locale files. Even though we introduced
`ng-jest-resolver` as a part of the preset, this resolver won't work for all scenarios. One might get Jest error like

```
Cannot find module '@angular/common/locales/xx' from 'src/app/app.component.spec.ts'
```

To fix this issue, one needs to define
`moduleNameMapper` to instruct Jest where to find the files, e.g.

```js
transformIgnorePatterns: ['node_modules/(?!@angular|my-ng-library-a|my-ng-library-b)'];
// jest.config.js
module.exports = {
// ...other options
moduleNameMapper: {
'@angular/common/locales/(.*)$': '<rootDir>/node_modules/@angular/common/locales/$1.mjs',
},
};
```

:::
- Another alternative solution is extending the default [resolver](https://github.com/thymikee/jest-preset-angular/blob/main/src/resolvers/ng-jest-resolver.ts)
of this preset to instruct Jest where to find the files.

### Usage with Angular libraries which are built with Angular CLI 13

Besides, the changes in Angular packages themselves, **Angular** libraries which are built with **Angular CLI 13** also introduce
ESM package format. Similar to Angular packages, Jest doesn't understand `.mjs` files which are in these new format
libraries in Jest **CommonJS** mode.

To fix this issue, one should follow our [troubleshooting instruction](troubleshooting.md#unexpected-token-importexportother)
72 changes: 15 additions & 57 deletions website/docs/guides/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,71 +65,29 @@ Reference: https://github.com/angular/material2/issues/7101

### Unexpected token [import|export|other]

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.

#### Adjust your `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/setup-jest';
^^^^^^
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
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:

```
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"module": "commonjs",
"types": [
"jest",
"jsdom",
"node"
]
},
"include": [
"**/*.d.ts"
]
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
```

#### Adjust your `transformIgnorePatterns` whitelist:

```json5
{
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`.

### Observable ... is not a function

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:
To fix the issue, one needs to adjust `transformIgnorePatterns` whitelist:

```js
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';
// 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`.

### Allow vendor libraries like jQuery, etc...

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:
Expand Down

0 comments on commit 0ab958d

Please sign in to comment.