简体   繁体   中英

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

I'm having a similar problem as in #5164 and this question . Consider the following working test code:

// 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()
  })
})

The code to create a connection and close it should be executed before all tests and after all tests are done, that's why we've added it to globalSetup.ts and globalTeardown.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',
        },
      },
    })
  })
})

Omitting the line require('ts-node/register') from both files throws this error:

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

Keeping the require line in throws:

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

Version

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

Config

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

Thank you for pointing out my mistakes. As I'm new I tried googling but couldn't really find an answer if this is me not understanding the tool or a bug in the too. Found a similar issue here with a PR .

It seems like the tests are running in a fully isolated environment where they can't access the connection set up within globalSetup .

Workaround

The only workaround I have found thus far is to add the following code to every test file:

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

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

require('ts-node/register') shouldn't present in.ts files. They are already processed by TypeScript compiler.

This is not what globalSetup and globalTeardown are for. They run in Jest parent process and are evaluated once, while each test suite runs in child processes.

This can be achieved by providing a common setup in setupFilesAfterEnv option:

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

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

Since Jest tests run in parallel, this will result in multiple database connections. If this is not desirable because of connection limit, Jest runInBand option needs to be used.

A setup for all tests not desirable because not all test suites need database connection, while they will unconditionally take time and occupy database connection pool. In this case jest.setup.ts can be imported directly in tests that use a database instead of setupFilesAfterEnv , no need to specify beforeAll and afterAll in each suite.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM