'How can I mock nest typeorm database module in end to end (e2e) tests?
all. Include details about your goal: I'm trying to mock repository in e2e test
Describe expected and actual results: Request to server will not have access to persistent layer. We should mock connection and repository.
I've updated code but the repository still not overrided. Maybe I need to implement it through a Facade provider
You can play with code here My code
Solution 1:[1]
You could use TypeORM fixtures, they allow you to create fixtures / fake data for use while developing or testing your code.
npm install typeorm-fixtures-cli --save-dev
Fixtures can be expressed in YAML files. For example:
entity: User
items:
user{1..10}:
username: bob
fullname: Bob
birthDate: 1980-10-10
email: [email protected]
favoriteNumber: 42
The library integrates Faker to help generate fake data such as names, e-mail addresses, phone numbers...etc. You can also establish relations between different fixtures.
Afterwards you can load the fixtures and use them with TypeORM.
const loadFixtures = async (fixturesPath: string) => {
let connection;
try {
connection = await createConnection();
await connection.synchronize(true);
const loader = new Loader();
loader.load(path.resolve(fixturesPath));
const resolver = new Resolver();
const fixtures = resolver.resolve(loader.fixtureConfigs);
const builder = new Builder(connection, new Parser());
for (const fixture of fixturesIterator(fixtures)) {
const entity = await builder.build(fixture);
await getRepository(entity.constructor.name).save(entity);
}
} catch (err) {
throw err;
} finally {
if (connection) {
await connection.close();
}
}
};
You can combine this with an in-memory SQLLite database. Just have TypeORM generate the database based on the entity metadata. Use fixtures to load up the fake data into the in-memory database and then run your tests.
Solution 2:[2]
Use it in app.module.ts TypeOrmModule.forRoot() and TypeOrmModule.forFeature([CatEntity]) in cats.module.ts
import { getRepositoryToken } from '@nestjs/typeorm';
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
// import modules, the modules should import the entities they deal with.
// The testing module should be barebones
imports: [
// basically looks like a unit test but goes through the HTTP motions
// if you want to include the AppModule you'll need to create a configuration
// for the database module (TypeORM) that will be accessible in a testing context
// AppModule,
CatModule,
],
})
// this is for overriding a provider that exists in a module already (such as the ProjectsModule)
.overrideProvider(getRepositoryToken(ProjectEntity))
// this is how you give the factory, value, or class to use instead
.useFactory({
factory: () => ({
create: jest.fn(() => new Promise((resolve) => resolve(cat))),
find: jest.fn(() => new Promise((resolve) => resolve([cat]))),
update: jest.fn((id, project2) => new Promise((resolve) => resolve(cat2))),
findOne: jest.fn(
({ uuid }) =>
new Promise((resolve) => {
resolve(cat);
}),
),
delete: jest.fn((uuid) => new Promise((resolve) => resolve())),
save: jest.fn(
(data) =>
new Promise((resolve) => {
// data = data.uuid === undefined ? data.uuid = uuid() : data;
resolve(data);
}),
),
}),
})
.compile();
app = module.createNestApplication();
await app.init();
});
I am available to answer to any question
Solution 3:[3]
I found the typeorm-test-transactions library that saved my day.
It will not mock the database, instead it will rollback all the transactions made inside its runInTransaction
function.
this is an example
// import the library functions
import {
runInTransaction,
initialiseTestTransactions,
} from 'typeorm-test-transactions';
// ...
initialiseTestTransactions();
describe('Test endpoint', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('Endpoint shuld work /endpoint', async () => {
// the database operations inside runInTransaction will be rolled back
await runInTransaction(async () => {
const email = '[email protected]'
const password = '12345678'
const userrepo = getRepository(User)
const user = userrepo.create({email, password, privilege})
return await userrepo.save(user)
await request(app.getHttpServer())
.get('/endpoint')
.expect(200);
})()
});
});
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Christophe Geers |
Solution 2 | gian848396 |
Solution 3 |