所有测试后Jest/TypeORM清除数据库

jaql4c8m  于 2023-08-01  发布在  Jest
关注(0)|答案(6)|浏览(145)

我想在所有jest测试之前或之后删除数据库中的所有条目。
下面是我的setup.js:

import { getConnection, getConnectionManager } from "typeorm"

beforeAll(async () => {
    const connectionManager = getConnectionManager()
    const connection = connectionManager.create({
        "type": "postgres",
        "host": "localhost",
        "port": 54320,
        "username": "test",
        "password": "test",
        "database": "test",
        "entities": ["../src/entities/*.ts"],
        "logging": false,
        "synchronize": true
    })
    await connection.connect()
})

afterAll(async () => {
    await getConnection().close()
})

字符串
我在typeorm文档中读到,“synchronize”选项会用新的空表覆盖旧表,但它似乎不起作用。
下面是我做的测试:

describe('POST /create', () => {
    it('Create a user', async () => {
        const user: IStringTMap<string> = {
            firstName: 'John',
            lastName: 'Doe',
            email: 'john.doe@test.com',
            password: 'test123!',
        }

        const res: Response = await request(app)
            .post('/create')
            .send(user)
            .expect(200)

        expect(res.type).toEqual('application/json')
        expect(res.body.email).toBe('john.doe@test.com')
        expect(res.body.password).toBe(undefined)
    })
})


第一个yarn test工作,但下一个不工作(电子邮件已经存在)
你知道吗?

vql8enpb

vql8enpb1#

也许有点晚,但也在寻找这个,这是我想出来的。
这只会删除实体内部的内容,而不会删除实体本身。

afterEach(async () => {

    // Fetch all the entities
    const entities = getConnection().entityMetadatas;

    for (const entity of entities) {
        const repository = getConnection().getRepository(entity.name); // Get repository
        await repository.clear(); // Clear each entity table's content
    }
});

字符串

EDIT:如果您使用的是外键,请确保将{onDelete: "CASCADE"}属性添加到您的列中,以便正确删除所有记录。

更多信息可以在这里找到:https://github.com/typeorm/typeorm/issues/1460#issuecomment-366982161

bqucvtff

bqucvtff2#

这里有一个简单而有效的方法来完全清理一个带有typeorm的数据库,创建一个专用的TestService,在一个命令中TRUNCATE所有实体:

import { Inject, Injectable } from "@nestjs/common";
import { Connection } from "typeorm";

@Injectable()
export class TestService {
  constructor(@Inject("Connection") public connection: Connection) {}

  public async cleanDatabase(): Promise<void> {
    try {
      const entities = this.connection.entityMetadatas;
      const tableNames = entities.map((entity) => `"${entity.tableName}"`).join(", ");
      
      await this.connection.query(`TRUNCATE ${tableNames} CASCADE;`);
      console.log("[TEST DATABASE]: Clean");
    } catch (error) {
      throw new Error(`ERROR: Cleaning test database: ${error}`);
    }
  }
}

字符串
然后你可以在你的测试文件中调用这个函数:

beforeEach(async () => {
  await testService.cleanDatabase();
});

h6my8fg2

h6my8fg23#

你可以在你的e2e测试文件中设置一个新的数据库,并在导入typeorm模块时设置dropSchema: true选项。你可以像在AppModule中一样导入typeorm模块int

6ioyuze2

6ioyuze24#

对不起,我没有足够的声誉来回应米歇尔的评论,但是,
如果您使用的是PostgreSQL数据库,并且表具有外键约束,则代码可能无法工作,因为根据PostgreSQL文档,TRUNCATE不会触发ON DELETE触发器
TRUNCATE TABLE不激发ON DELETE触发器。相反,它会触发BEFORE TRUNCATE和AFTER TRUNCATE触发器。
因此,您可能需要使用EntityManager来进行如下SQL查询:

entityManager.query('TRUNCATE TABLE table_name CASCADE;')

字符串
希望这对你有帮助。

eyh26e7m

eyh26e7m5#

注意:使用getConnection的示例现在已弃用。一种新的办法可以是:

import { DataSource } from 'typeorm';
import { databaseConfig } from '../src/config/database'; // TypeORM configuration

export const clearDatabase = async () => {
  const appDataSource = new DataSource(databaseConfig);
  const entities = appDataSource.entityMetadatas;

  for await (const entity of entities) {
    const repository = appDataSource.getRepository(entity.name);

    await repository.query(
      `TRUNCATE ${entity.tableName} RESTART IDENTITY CASCADE;`,
    );
  }
};

字符串

9rygscc1

9rygscc16#

您可能不必为此测试清除数据库。您也可以使用像faker这样的库,绕过电子邮件重复验证。Faker将在每次测试运行时产生一个唯一的用户。将您的用户更改为:

import fake from 'faker';

const user: IStringTMap<string> = {
  firstName: faker.name.firstName(),
  lastName: faker.name.lastName(),
  email: faker.internet.email(),
  password: faker.internet.password()
}

字符串

相关问题