라이브러리 사용법

https://github.com/viniciusjssouza/typeorm-transactional-tests

beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [TypeOrmModule.forRoot(typeORMTestConfig)],
      providers: [...],
    }).compile();

    dataSource = moduleFixture.get<DataSource>(DataSource);
  });

beforeEach(async () => {
  transactionalContext = new TransactionalTestContext(dataSource);
  await transactionalContext.start();
});

afterEach(async () => {
  await transactionalContext.finish();
});

어떻게 동작하고 있을까?

Monkey patching : 다른 사람이 작성한 코드(일반적으로 라이브러리나 프레임워크)를 변경하거나 확장하는 프로그래밍 기법

transactionContext.start()

constructor(private readonly connection: DataSource) {}

async start(): Promise<void> {
  if (this.queryRunner) {
    throw new Error('Context already started');
  }
  try {
    **this.queryRunner = this.buildWrappedQueryRunner();
    this.monkeyPatchQueryRunnerCreation(this.queryRunner);**

    await this.queryRunner.connect();
    await this.queryRunner.startTransaction();
  } catch (error) {
    await this.cleanUpResources();
    throw error;
  }
}

private **buildWrappedQueryRunner()**: QueryRunnerWrapper {
    const queryRunner = this.connection.createQueryRunner();
    return **wrap**(queryRunner);
  }

private **monkeyPatchQueryRunnerCreation(queryRunner: QueryRunnerWrapper)**: void {
    this.originQueryRunnerFunction = DataSource.prototype.createQueryRunner;
    DataSource.prototype.createQueryRunner = () => queryRunner;
}

wrap()

const wrap = (originalQueryRunner: QueryRunner): QueryRunnerWrapper => {
  release = originalQueryRunner.release;
  originalQueryRunner.release = () => {
    return Promise.resolve();
  };

  (originalQueryRunner as QueryRunnerWrapper).releaseQueryRunner = () => {
    originalQueryRunner.release = release;
    return originalQueryRunner.release();
  };

  return originalQueryRunner as QueryRunnerWrapper;
};