Reputation: 617
I would like to delete all entries into my database after or before all jest tests.
Here is my 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()
})
I read on the typeorm documentation that the "synchronize" option would override the old tables with new one which are empty but it doesn't seems to work.
Here is the test I made:
describe('POST /create', () => {
it('Create a user', async () => {
const user: IStringTMap<string> = {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
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('[email protected]')
expect(res.body.password).toBe(undefined)
})
})
First yarn test
works but the next one doesn't (email already exists)
Any idea?
Upvotes: 16
Views: 27548
Reputation: 469
Note: examples with getConnection
is deprecated now.
A new approach could be:
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;`,
);
}
};
Upvotes: 2
Reputation: 191
Here is a simple and efficient way to fully clean a DB with typeorm, in creating a dedicated TestService which TRUNCATE all entities in one command:
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}`);
}
}
}
Then you can call this function in your testing files:
beforeEach(async () => {
await testService.cleanDatabase();
});
Upvotes: 7
Reputation: 311
Sorry I do not have enough reputation to respond to Michiel's comment but,
if you are using a postgreSQL database and your table have foreign key constraints your code may not work because according to the postgreSQL documentation TRUNCATE does not fire an ON DELETE trigger
The TRUNCATE TABLE does not fire ON DELETE trigger. Instead, it fires the BEFORE TRUNCATE and AFTER TRUNCATE triggers.
So you will probably have to use the EntityManager to make an SQL query like this:
entityManager.query('TRUNCATE TABLE table_name CASCADE;')
Hope you find this helpful.
Upvotes: 5
Reputation: 1843
Maybe a little late but was searching for this as well, this is what I came up with.
This will only delete the content inside the entities, not the entities itself.
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: If you're using foreign keys, make sure to add the {onDelete: "CASCADE"}
property to your columns in order to delete all the records correctly.
More information about that can be found here: https://github.com/typeorm/typeorm/issues/1460#issuecomment-366982161
Upvotes: 20
Reputation: 611
you can setup a new database in your e2e test file with a separate name and set the dropSchema: true
option when you import the typeorm module. you can import the typeorm module int he imports the same way you do in AppModule
Upvotes: 3
Reputation: 4931
You may not have to purge the database for this test. You could alternatively use a library like faker and bypass the email duplicate validation. Faker will produce a unique user with every test run. Change your user to:
import fake from 'faker';
const user: IStringTMap<string> = {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
password: faker.internet.password()
}
Upvotes: -4