0

我正在使用 jest 测试我的 Node.js API。此 API 是用于管理任务的 Express 应用程序。它具有注册/登录功能,仅允许经过身份验证的用户使用该应用程序。它有一个用于注册新用户的端点,并且存在许多端点,它们使用快速中间件通过 JWT 验证用户身份验证。我jose-node-cjs-runtime@^3.15.5安装了用于 JWT 生成和验证的包。

如果我使用devscript运行项目env-cmd -f ./config/dev.env nodemon src/index.js,则没有问题并且运行良好。我正在尝试使用 jest 测试文件来测试用户注册,该文件使用superagent包来测试端点。我正在使用测试脚本env-cmd -f ./config/test.env jest --watch来运行测试。此命令显示以下错误并且测试失败:

 FAIL  tests/user.test.js
  ● Test suite failed to run

    Cannot find module 'jose-node-cjs-runtime/jwt/sign' from 'src/models/user.js'

    Require stack:
      src/models/user.js
      src/routers/user.js
      src/app.js
      tests/user.test.js

      3 | const bcrypt = require('bcryptjs');
      4 | // library for signing jwt
    > 5 | const { SignJWT } = require('jose-node-cjs-runtime/jwt/sign');
        |                     ^
      6 | // library for generating symmetric key for jwt
      7 | const { createSecretKey } = require('crypto');
      8 | // task model

      at Resolver.resolveModule (node_modules/jest-resolve/build/resolver.js:313:11)
      at Object.<anonymous> (src/models/user.js:5:21)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        3.385 s
Ran all test suites related to changed files.

我无法弄清楚为什么会导致此错误。请帮助我找到解决方案。

我使用的是 Node.js 版本 16.7.0 并收到此错误。我今天升级了我的 Node.js 版本。我当前的 Node.js 版本是 16.9.0。升级 Node.js 版本后,我也收到此错误。以下是项目的 package.json 文件内容:

{
  "name": "task-manager",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "engines": {
    "node": ">=16.7.0"
  },
  "scripts": {
    "start": "node src/index.js",
    "dev": "env-cmd -f ./config/dev.env nodemon src/index.js",
    "test": "env-cmd -f ./config/test.env jest --watch"
  },
  "jest": {
    "testEnvironment": "node",
    "roots": [
      "<rootDir>"
    ],
    "modulePaths": [
      "<rootDir>"
    ],
    "moduleDirectories": [
      "node_modules"
    ]
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@sendgrid/mail": "^7.4.6",
    "bcryptjs": "^2.4.3",
    "express": "^4.17.1",
    "jose-node-cjs-runtime": "^3.15.5",
    "mongodb": "^4.1.1",
    "mongoose": "^6.0.2",
    "multer": "^1.4.3",
    "sharp": "^0.29.0",
    "validator": "^13.6.0"
  },
  "devDependencies": {
    "env-cmd": "^10.1.0",
    "jest": "^27.1.0",
    "nodemon": "^2.0.12",
    "supertest": "^6.1.6"
  }
}

以下是内容src/models/user.js

const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
// library for signing jwt
const { SignJWT } = require('jose-node-cjs-runtime/jwt/sign');
// library for generating symmetric key for jwt
const { createSecretKey } = require('crypto');
// task model
const Task = require('./task');
...

内容src/tests/user.test.js

const request = require('supertest');
const app = require('../src/app');

describe('user route', () => {
  test('should signup a new user', async () => {
    await request(app)
      .post('/users')
      .send({
        name: '__test_name__',
        email: '__test_email__',
        password: '__test_password__',
      })
      .expect(201);
  });
});
4

3 回答 3

1

我在 jest github repo 中提出了一个问题。该问题已通过评论关闭:

该模块使用尚不支持的导出: #9771

所以我通读了已经记录在类似问题上的评论,发现这个有用的评论可以用作解决方法,直到 jest 原生支持此功能。

我发现jose-node-cjs-runtime模块exports字段如下所示:

"./jwt/sign": "./dist/node/cjs/jwt/sign.js",
"./jwt/verify": "./dist/node/cjs/jwt/verify.js",

所以我更新了jest配置package.json如下:

"jest": {
  "testEnvironment": "node",
  "moduleNameMapper": {
    "^jose-node-cjs-runtime/(.*)$": "jose-node-cjs-runtime/dist/node/cjs/$1"
  }
}

之后运行测试我没有遇到任何问题。

于 2021-09-14T08:43:35.437 回答
1

您可以使用此解决方法中的解析器。

我有一个jose用于各种工具测试存储库。

显然,如果您使用 ts-jest 或 ESM 测试文件或类似文件,您的设置可能会有所不同。但是此时您应该熟悉不同的玩笑魔术选项。

> jest --resolver='./temporary_resolver.js' 'jest.test.*'

 PASS  ./jest.test.js
  ✓ it works in .js (3 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.367 s, estimated 1 s
Ran all test suites matching /jest.test.*/i.
// temporary workaround while we wait for https://github.com/facebook/jest/issues/9771

const resolver = require('enhanced-resolve').create.sync({
  conditionNames: ['require'],
  extensions: ['.js', '.json', '.node', '.ts']
})

module.exports = function (request, options) {
  return resolver(options.basedir, request)
}
const { generateSecret } = require("jose/util/generate_secret");

test('it works in .js', async () => {
  expect(typeof generateSecret).toBe('function');
  expect(await generateSecret('HS256')).toBeTruthy();
});

底线 - 关于制作 jest 需要 jose 模块的 cjs 分发并使用导出映射。请注意,ESM 仍然不受本机支持,exports 映射也不支持,这两者在节点的所有 LTS 版本中都稳定了一年多。

于 2021-09-14T10:16:41.013 回答
0

我认为您缺少 jest 的配置,可以在 此处找到

主要是找moduleirectories,可以添加相对路径和绝对路径。

确保包含在根数组、modulePaths 数组和 moduleDirectories 数组中的 node_modules 中,除非您有充分的理由排除它们。这是 jest config 的示例,您可以将其包含在package.json文件中

 "jest": {
  "roots": [
    "<rootDir>",
    "/homeDir/yourLocalDir/path/"
  ],
  "modulePaths": [
    "<rootDir>",
    "/homeDir/yourLocalDir/otherDir/path"
  ],
  "moduleDirectories": [
    "node_modules"
  ],
"testPathIgnorePatterns": ["/node_modules/(?!MODULE_NAME_HERE).+\\.js$"]
}
于 2021-09-14T06:15:55.663 回答