Jest errors with solutions
Tags: jest, react, tdd, errors
Published: 2023-07-20 12:22:22

> You may find example SPFx solution on [GitHub](https://github.com/kkazala/jestTestSPFxWebPart)

## 1. Parsing error: "parserOptions.project"

```bs
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: test\components\HelloWorld.test.tsx.
The file must be included in at least one of the projects provided.
```

### Solution

Add `.eslintignore` file to the root of your project:

#### _.eslintignore_
```
.eslintrc.js

**/test/*.ts
**/test/*.tsx

*.test.ts
*.test.tsx
```

## 2. Property 'toBeInTheDocument' does not exist...

```bs
error TS2339: Property 'toBeInTheDocument' does not exist on type 'JestMatchers<HTMLElement>'.
```
### Solution

Add `import '@testing-library/jest-dom';`

#### _HelloWorld.test.tsx_
```tsx
import '@testing-library/jest-dom';
import { RenderResult, render } from '@testing-library/react';
import React from "react";
import HelloWorld from "../../src/webparts/helloWorld/components/HelloWorld";

describe("HelloWorld.tsx", () => {
    it("should render correctly", async () => {

        let helloWorld: RenderResult =  render(<HelloWorld  description="" isDarkTheme={false} environmentMessage="" hasTeamsContext={false} userDisplayName="" />);
        expect(helloWorld.getByTestId('helloWorld')).toBeInTheDocument();

    });
});
```

## 3. Cannot read properties of undefined (reading 'createElement')

```bs
    TypeError: Cannot read properties of undefined (reading 'createElement')

       7 |     it("should render correctly", async () => {
       8 |
    >  9 |         let helloWorld: RenderResult =  render(<HelloWorld  description="" isDarkTheme={false} environmentMessage="" hasTeamsContext={false} userDisplayName="" />);
         |                                                ^
      10 |         expect(helloWorld.getByTestId('helloWorld')).toBeInTheDocument();
      11 |
      12 |     });
```

### Solution

Add `"esModuleInterop": true,` to `compilerOptions` in `tsconfig.json`

#### _tsconfig.json_
```json
{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-4.5/includes/tsconfig-web.json",
  "compilerOptions": {
    "target": "es5",
    "esModuleInterop": true,
    //...
}
```

## 4. SyntaxError: Invalid or unexpected token
```bs
    Details:

C:\GitHub\Archive\spfx1.17.4_pnpm\src\webparts\helloWorld\components\HelloWorld.module.scss:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){@import '~@fluentui/react/dist/sass/References.scss';
                                                                                      ^
    SyntaxError: Invalid or unexpected token

      1 | import { escape } from '@microsoft/sp-lodash-subset';
      2 | import * as React from 'react';
    > 3 | import styles from './HelloWorld.module.scss';
```

### Solution

Add `"\\.(css|scss)": "identity-obj-proxy"` to `moduleNameMapper` in `package.json`

#### _package.json_
```json
{
  //...
  "jest": {
    "moduleNameMapper": {
      "\\.(css|scss)": "identity-obj-proxy"
    }
}
```

## 5. SyntaxError: Invalid or unexpected token

```bs

    Details:

    C:\GitHub\Archive\spfx1.17.4_pnpm\src\webparts\helloWorld\assets\welcome-light.png:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){�PNG


    SyntaxError: Invalid or unexpected token

      18 |       <section className={`${styles.helloWorld} ${hasTeamsContext ? styles.teams : ''}`} data-testid="helloWorld" >
      19 |         <div className={styles.welcome}>
    > 20 |           <img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
```

### Solution
Media files aren't being mocked. 

Create `assetsTransformer.js` in the root of your project.

#### _assetsTransformer.js_
```js
const path = require('path');

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};
```

Add `"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetsTransformer.js"` to `moduleNameMapper` in `package.json`

#### _package.json_
```json
{
  //...
  "jest": {
    "moduleNameMapper": {
      //...
      "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)": "<rootDir>/assetsTransformer.js"
    }
}
```

> Credit where credit is due: [github issue#2663](https://github.com/jestjs/jest/issues/2663#issuecomment-317109798)

## 6. Cannot find module 'HelloWorldWebPartStrings' from 'src/webparts/helloWorld/components/HelloWorld.tsx'

```bs
Cannot find module 'HelloWorldWebPartStrings' from 'src/webparts/helloWorld/components/HelloWorld.tsx'

    Require stack:
      src/webparts/helloWorld/components/HelloWorld.tsx
      test/components/HelloWorld.test.tsx

      1 | import { escape } from '@microsoft/sp-lodash-subset';
    > 2 | import strings from 'HelloWorldWebPartStrings';
```

### Solution

Add `"HelloWorldWebPartStrings": "<rootDir>/src/webparts/helloWorld/loc/myStrings.d.ts"` to `moduleNameMapper` in `package.json`

#### _package.json_
```json
{
  //...
  "jest": {
    "moduleNameMapper": {
      //...
      "HelloWorldWebPartStrings": "identity-obj-proxy"
    }
}
```
And mock your strings as a constant:

#### _HelloWorld.test.tsx_
```tsx
jest.mock('HelloWorldWebPartStrings', () => {
    return {
        PropertyPaneDescription: "Description",
        //...
    }
    { virtual: true }
})
```
Source: [surajit09's answer](https://github.com/Voitanos/jest-preset-spfx-react16/issues/7#issuecomment-595693970)

## 7. The icon "info" was used but not registered. 

This is just a warning you may see when testing react components using fluent ui icons. Annoying nevertheless.

### Solution
In your `test.tsx` file add the following:

```tsx
import { setIconOptions } from '@fluentui/react/lib/Styling';

// Suppress icon warnings.
setIconOptions({
  disableWarnings: true
});
```

Source: [Disabling warnings/test scenarios](https://github.com/microsoft/fluentui/wiki/Using-icons#test-scenarios)

> You may find example SPFx solution on [GitHub](https://github.com/kkazala/jestTestSPFxWebPart)

## 8. Cannot use import statement outside a module

If you are getting errors similar to 
```bash
 \node_modules\@pnp\azidjsclient\index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { PnPClientStorage, getHashCode } from "@pnp/core/index.js";
                                                                                      ^^^^^^
    SyntaxError: Cannot use import statement outside a module

      2 | import { DefaultAzureCredential } from "@azure/identity";
      3 | import { setLogLevel } from "@azure/logger";
    > 4 | import { AzureIdentity } from "@pnp/azidjsclient";
```

you need to enable support for ECMAScript Modules (ESM), as described [here](https://jestjs.io/docs/ecmascript-modules)

### Solution

1. On Windows, install cross-env: `npm i cross-env --save-dev` 
2. Update your `test` script in `package.json`. **Replace** `"test": "jest"` with  `"test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest"`

```json
"scripts": {
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest"
},
```

## 9. Must use import to load ES Module

After completing the step above, you may now see another error:

```bash
Err: Must use import to load ES Module: \node_modules\@pnp\azidjsclient\index.js

      2 | import { DefaultAzureCredential } from "@azure/identity";
      3 | import { setLogLevel } from "@azure/logger";
    > 4 | import { AzureIdentity } from "@pnp/azidjsclient";
```

### Solution

Add additional configuration to your `package.json`:

```json
"jest": {
  "transform": {
    "^.+\\.(ts|tsx)?$": ["ts-jest", { "useESM": true }]
  },
  "extensionsToTreatAsEsm": [
    ".ts"
  ]
}
```