0

我在一个 Spfx 项目中工作。
我有自己的 Logger 类,它是 @pnp/logging/Logger 的包装器。

import * as pnpLogging from '@pnp/logging';
export class Logger {
    public static debug(message: string, notify = false, caller: string = null): void {
        pnpLogging.Logger.log( ... )
    }

该记录器随后用于各种其他类、组件和挂钩。

import { Logger } from "./logging";
Logger.debug('some debug message);

在为这些其他类之一创建测试时,jest 在导入 @pnp/logging 时会引发不受支持的异常。

office-ui-fabric-react通过使用他们的 commonjs 库,我能够克服这个问题。

"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1",

但是,我在@pnp/logging 中看不到这个选项。
我也试图嘲笑它,但没有成功。

import { nameof } from './utils';
const mockedPnpLogger = { error: (message) => { } };
jest.mock('@pnp/logging', () => ({
  ...jest.requireActual('@pnp/logging') as any,
  Logger: mockedPnpLogger
}));   
describe('utils', () => { ... }

但这仍然会引发导出错误

SyntaxError: Unexpected token 'export'

  3 | const mockedPnpLogger = { error: (message) => { } };
  4 | jest.mock('@pnp/logging', () => ({
> 5 |     ...jest.requireActual('@pnp/logging') as any,
    |             ^
  6 |     Logger: mockedPnpLogger
  7 | }));
  8 |

我现在有点迷失了选择。任何人都有一些见识或可以帮助我朝正确的方向发展?

完整的错误信息

Jest encountered an unexpected token

Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

By default "node_modules" folder is ignored by transformers.

Here's what you can do:
 • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
 • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
 • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
 • If you need a custom transformation specify a "transform" option in your config.
 • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation

Details:

C:\Development\Projects\Skan\Applications\FuhrPark\src\client\node_modules\@pnp\logging\index.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export * from "./logger.js";
                                                                                  ^^^^^^

SyntaxError: Unexpected token 'export'

> 1 | import * as pnpLogging from '@pnp/logging';

笑话配置

"jest": {
    "moduleFileExtensions": [
        "ts",
        "tsx",
        "js"
    ],
    "moduleDirectories": [
        "node_modules"
    ],
    "moduleNameMapper": {
        "\\.(css|less|scss|sass)$": "identity-obj-proxy",
        "office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1",
        "^@fuhrpark/(.*)": "<rootDir>/src/webparts/fuhrpark/$1",
        "^@shared/(.*)": "<rootDir>/src/shared/$1"
    },
    "transform": {
        "^.+\\.(ts|tsx)$": "ts-jest"
    },
    "transformIgnorePatterns": [
        "node_modules/(?!office-ui-fabric-react)"
    ],
    "testMatch": [
        "**/src/**/*.tests.+(ts|tsx)"
    ],
    "setupFiles": [
        "<rootDir>/src/webparts/fuhrpark/tests/tests-setup.ts"
    ],
    "testEnvironment": "node",
    "collectCoverage": true,
    "coverageReporters": [
        "json",
        "lcov",
        "text",
        "cobertura"
    ],
    "coverageDirectory": "<rootDir>/test-results",
    "reporters": [
        "default",
        "jest-junit"
    ],
    "coverageThreshold": {
        "global": {
            "branches": 0,
            "functions": 0,
            "lines": 0,
            "statements": 0
        }
    }
},
"jest-junit": {
    "output": "./test-results/summary-jest-junit.xml"
}

打字稿配置

{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-4.2/includes/tsconfig-web.json",
  "compilerOptions": {
    "target": "es5",
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "react",
    "declaration": true,
    "sourceMap": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "outDir": "lib",
    "inlineSources": false,
    "strictNullChecks": false,
    "noUnusedLocals": false,
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "typeRoots": [
      "./node_modules/@types",
      "./node_modules/@microsoft"
    ],
    "types": [
      "webpack-env",
      "jest",
      "node"
    ],
    "lib": [
      "es6",
      "dom",
      "es2015.collection",
      "es2015.promise"
    ],
    "baseUrl": "src",
    "paths": {
      "@fuhrpark/*": [
        "webparts/fuhrpark/*"
      ],
      "@shared/*": [
        "shared/*"
      ]
    }
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx"
  ]
}
4

1 回答 1

0

我将 web 对象上的 get 方法包装在一个函数中,最后通过创建下面的模拟来正确处理它。我的包装器使用 .then 模式,这是模拟中双重承诺解决的原因。

重要的是,模拟不能在它/测试或描述中,它必须位于顶层,如文档中所述

我还在相同的模拟中模拟了 sp.setup 函数,否则会引发错误。因此 - 你需要根据我的发现设置一个双倍。我已经尝试过 ts-sinon/ts-mockito 等,但没有什么能带我一路走来。


jest.mock('@pnp/sp', () => {
    return {
        __esModule: true,
        sp: {
            setup: jest.fn(),
            web: {
                get: () => Promise.resolve(Promise.resolve({ Title: 'Contoso Web Title' }))
            }
        }
    };
});

编辑:添加一个包含“选择”的示例 - 这也必须被模拟/存根

jest.mock('@pnp/sp', () => {
    return {
        __esModule: true,
        sp: {
            setup: jest.fn(),
            web: {
                select: () => {
                    return {
                        get: () => Promise.resolve(Promise.resolve({ Title: 'Contoso Web Title' }))
                    };
                }
            }
        }
    };
});
于 2022-02-13T12:03:16.950 回答