在 jest globalSetup 中创建连接时未找到 Typeorm 连接 "default"

Typeorm Connection "default" was not found when connection is created in jest globalSetup

我遇到了与 #5164 and this question 类似的问题。考虑以下工作测试代码:

// AccountResolver.test.ts
describe('Account entity', () => {
  it('add account', async () => {
    await createConnections()
    const defaultConnection = getConnection('default')

    const actual = await callGraphql(
      `mutation {
        addAccount(options: {
          accountIdentifier: "7csdcd8-8a5f-49c3-ab9a-0198d42dd253"
          name: "Jake, Bob (Braine-l’Alleud) JAM"
          userName: "Bob.Marley@contoso.com"
        }) {
          accountIdentifier
          name
          userName
        }
      }`
    )
    expect(actual.data).toMatchObject({
      data: {
        addAccount: {
          accountIdentifier: '7csdcd8-8a5f-49c3-ab9a-0198d42dd253',
          name: 'Jake, Bob (Braine-l’Alleud) JAM',
          userName: 'Bob.Marley@contoso.com',
        },
      },
    })

    await defaultConnection.query(`DELETE FROM Account`)
    await defaultConnection.close()
  })
})

创建连接和关闭连接的代码应该在所有测试之前和所有测试完成之后执行,这就是我们将其添加到 globalSetup.tsglobalTeardown.ts:[=27 的原因=]

// globalSetup.ts
require('ts-node/register')
import { createConnections } from 'typeorm'

module.exports = async () => {
  // console.log('jest setup')
  await createConnections()
}
// globalTeardown.ts
require('ts-node/register')
import { getConnection } from 'typeorm'

module.exports = async () => {
  const defaultConnection = getConnection('default')
  await defaultConnection.close()
}
// AccountResolver.test.ts
describe('Account entity', () => {
  it('add account', async () => {
    const defaultConnection = getConnection('default')
    await defaultConnection.query(`DELETE FROM Account`)

    const actual = await callGraphql(
      `mutation {
        addAccount(options: {
          accountIdentifier: "7csdcd8-8a5f-49c3-ab9a-0198d42dd253"
          name: "Jake, Bob (Braine-l’Alleud) JAM"
          userName: "Bob.Marley@contoso.com"
        }) {
          accountIdentifier
          name
          userName
        }
      }`
    )
    expect(actual.data).toMatchObject({
      data: {
        addAccount: {
          accountIdentifier: '7csdcd8-8a5f-49c3-ab9a-0198d42dd253',
          name: 'Jake, Bob (Braine-l’Alleud) JAM',
          userName: 'Bob.Marley@contoso.com',
        },
      },
    })
  })
})

从两个文件中省略行 require('ts-node/register') 会引发此错误:

T:\Test\src\it-portal\entity\Account.ts:1 import { ^^^^^^ SyntaxError: Cannot use import statement outside a module

require 行保留在抛出中:

FAIL src/resolvers/AccountResolver.test.ts × add account (31 ms) ● Account entity › add account ConnectionNotFoundError: Connection "default" was not found.Account entity

版本

    "jest": "^26.0.1",
    "ts-jest": "^26.1.0",
    "ts-node-dev": "^1.0.0-pre.44",
    "typescript": "^3.9.5"

配置

// jest.config.js
module.exports = {
  preset: 'ts-jest',
  globalSetup: './src/test-utils/config/globalSetup.ts',
  globalTeardown: './src/test-utils/config/globalTeardown.ts',
  setupFiles: ['./src/test-utils/config/setupFiles.ts'],
  moduleDirectories: ['node_modules', 'src'],
  globals: {
    'ts-jest': {
      tsConfig: 'tsconfig.json',
      diagnostics: {
        warnOnly: true,
      },
    },
  },
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80,
    },
  },
  coverageReporters: ['json', 'lcov', 'text', 'clover'],
}

感谢您指出我的错误。由于我是新手,所以我尝试使用谷歌搜索,但如果这是我不了解该工具或其中的错误,则无法真正找到答案。发现了类似的问题 here with a PR.

测试似乎 运行 在一个完全隔离的环境中,他们无法访问在 globalSetup 中建立的连接。

解决方法

到目前为止我发现的唯一解决方法是将以下代码添加到每个测试文件中:

beforeAll(async () => {
  await createConnections()
})

afterAll(async () => {
  const defaultConnection = getConnection('default')
  await defaultConnection.close()
})

require('ts-node/register') 不应出现在 .ts 文件中。它们已经被 TypeScript 编译器处理。

这不是 globalSetupglobalTeardown 的目的。它们 运行 在 Jest 父进程中并被评估一次,而每个测试套件 运行 在子进程中。

这可以通过在 setupFilesAfterEnv 选项中提供通用设置来实现:

// jest.setup.ts
...
beforeAll(async () => {
  await createConnections()
})

afterAll(async () => {
  const defaultConnection = getConnection('default')
  await defaultConnection.close()
})

由于 Jest 并行测试 运行,这将导致多个数据库连接。如果由于连接限制而不希望这样做,则需要使用 Jest runInBand 选项。

所有测试的设置并不可取,因为并非所有测试套件都需要数据库连接,而它们将无条件地占用时间并占用数据库连接池。在这种情况下,可以在使用数据库的测试中直接导入 jest.setup.ts 而不是 setupFilesAfterEnv,无需在每个套件中指定 beforeAllafterAll