e2e 테스트를 하다가 발생한 에러

ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... Error: DataSource with name "default" has already added.

 

검색을 하여 찾은 아래의 링크를 따라 해결

https://github.com/Aliheym/typeorm-transactional/issues/10

 

Error when running E2E tests with Nest.js · Issue #10 · Aliheym/typeorm-transactional

Hi there, thanks for the package! It really is super useful. My issue is that we can't run our E2E tests with it as of now. We get the console error Error: DataSource with name "default" has alread...

github.com

 

두가지 해결 방식

방식 1. getDataSourceByName('default') 추가

import { addTransactionalDataSource, getDataSourceByName } from 'typeorm-transactional';

// ...

TypeOrmModule.forRootAsync({
    dataSourceFactory: async (options) => {
      return getDataSourceByName('default') || addTransactionalDataSource(new DataSource(options));
    },
  });

 

방식 2. deleteDataSourceByName('default') 추가

import { addTransactionalDataSource, deleteDataSourceByName } from 'typeorm-transactional';

// ...

TypeOrmModule.forRootAsync({
    dataSourceFactory: async (options) => {
      deleteDataSourceByName('default');

      return addTransactionalDataSource(new DataSource(options));
    },
  });

 

각 방식에서 사용된 코드의 의미???

import { DataSource, EntityManager, Repository } from 'typeorm';
...
export type DataSourceName = string | 'default';
const dataSources = new Map<DataSourceName, DataSource>();

export const getDataSourceByName = (name: DataSourceName) => dataSources.get(name);
export const deleteDataSourceByName = (name: DataSourceName) => dataSources.delete(name);

 

 

방식 1 을 선택하여   getDataSourceByName('default') 코드를 추가하여 해결

//변경 전
 async dataSourceFactory(options) {
    if (!options) {
      throw new Error('Invalid options passed');
    }
    return addTransactionalDataSource(new DataSource(options));
  },
  
// 변경 후
 async dataSourceFactory(options) {
    if (!options) {
      throw new Error('Invalid options passed');
    }
    return getDataSourceByName('default') || addTransactionalDataSource(new DataSource(options));
  },

 

 

이렇게 하니 귀찮은 일이 발생했다.

1. 앞의 테스트에서 내가 생성한 유저를 다시 생성하려면 이미 있는 e-mail 이라는 문구가 발생

2. 앞의 테스트에서 내가 지운 유저를 또 지우려면 내가 원하는 204가 아니라 500 반환

 

beforeAll 을 이용하여서 하니 

  • 옵션< getDataSourceByName('default') >을 추가하지 않아도 해당 에러가 뜨지 않았다. Error: DataSource with name "default" has already added.
  • 테스트할때마다 내가 적은 expect 부분을 수정하지 않아도 되었다.

의문점

  • beforeEach 에서는 중복이 발생했는데 어떻게 beforeAll 에서는 중복이 발생하지 않을까

-> 데이터베이스를 확인해보니 역시나 중복이 발생. 중복을 방지하기 위해  

 

최종적으로 테이블을 드랍하고 동기화 하는 코드를 추가하여 마무리하였다.

 beforeAll(async () => {
    initializeTransactionalContext();
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();
    
    dataSource = moduleFixture.get<DataSource>(DataSource);
    
    // 데이터베이스 테이블 초기화 및 동기화
    await dataSource.dropDatabase();
    await dataSource.synchronize();
    
    // 토큰 발행
    token = generateTestToken();
    
    app = moduleFixture.createNestApplication();
    await app.init();
  });

 

※ 데이테베이스 테이블 초기화를 beforeEach에 사용하면 생성한 유저가 사라져서 jwt 토큰을 발행하는데 문제가 발생한다.

+ Recent posts