【问题标题】:Typeorm Connection "default" was not found when connection is created in jest globalSetup在 jest globalSetup 中创建连接时,找不到 Typeorm 连接“默认”
【发布时间】:2020-06-20 01:22:15
【问题描述】:

我遇到了与#5164this 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的原因:

// 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 进口 { ^^^^^^ SyntaxError: 不能在模块外使用 import 语句

在 throws 中保留 require 行:

FAIL src/resolvers/AccountResolver.test.ts × 添加账户 (31 ms) ● 账户实体 › 添加账户 ConnectionNotFoundError: Connection 未找到“默认”。帐户实体

版本

    "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'],
}

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

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

解决方法

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

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

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

【问题讨论】:

    标签: javascript typescript jestjs typeorm ts-jest


    【解决方案1】:

    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

    【讨论】:

    • 这确实有效。但据我了解,它在每个测试文件之前和每个测试文件之后执行。有没有办法让代码在所有测试文件之前和所有测试文件之后只执行一个,并且仍然能够使用测试文件中的数据库连接?
    • 是的,它针对每个文件执行。正如我所提到的,文件在不同的进程中运行。 Node进程可以交换数据的方式有限,数据库连接对象不能在多个进程之间共享。这不是 Jest 特有的。不,除了让测试在单个进程中运行之外别无他法(例如,将所有测试套件导入一个 index.test.js 文件中)。
    • 感谢您的澄清。接受你的回答。
    • @EstusFlask 可以为每个测试创建一个单独的数据库。我正在尝试使用 sqlite 的内存数据库。但是我不断收到默认值已经存在的错误
    • @Elias 请参阅有关 runInBand 的备注。然后可以在 before/afterEach 中设置 dbs。
    猜你喜欢
    • 2018-09-22
    • 1970-01-01
    • 2020-02-13
    • 2019-09-08
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 2018-11-12
    • 2020-11-25
    相关资源
    最近更新 更多