Skip to content

Instantly share code, notes, and snippets.

@ziomarco
Last active September 1, 2023 08:13
Show Gist options
  • Save ziomarco/3b1f3641741992c1fd4705b76673c3fc to your computer and use it in GitHub Desktop.
Save ziomarco/3b1f3641741992c1fd4705b76673c3fc to your computer and use it in GitHub Desktop.
Easy NestJS Mongoose Testing
/*
Merging all the times <entity>.module.ts and fake module instantation is boring for all, so let's help us using this structure.
*/
export const moduleConf = {
imports: [
TracksModule,
MongooseModule.forFeature([{ name: Entity.name, schema: EntitySchema }]),
MongooseModule.forFeature([
{ name: SecondEntity.name, schema: SecondEntitySchema },
]),
],
controllers: [EntityController],
providers: [EntityService, SecondEntityService],
};
@Module(moduleConf)
export class EntityModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { EntityService } from './Entity.service';
import { moduleConf } from './Entity.module';
import {
injectMongoConnectionInTestsModulesDependencies,
killTestingDb,
} from '../utils/injectMongoConnectionInTests';
import { injectDbMocks } from '../utils/test/injectDbMocks';
import { Entity, EntitySchema } from './models/Entity/Entity.schema';
import { entityMocks } from './Entity.mocks';
describe('EntityService', () => {
let service: EntityService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule(
injectMongoConnectionInTestsModulesDependencies(moduleConf),
).compile();
await injectDbMocks<Entity>('entity', EntitySchema, entityMocks);
service = module.get<EventsService>(EventsService);
});
afterAll(async () => {
await killTestingDb();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should find invited user', async () => {
const userEvents = await service.getJoinedEvents('memberB');
expect(userEvents.length).toBe(1);
});
it('should not find invited user', async () => {
const userEvents = await service.getJoinedEvents('unExistantMemberB');
expect(userEvents.length).toBe(0);
});
});
/*
Util file for injecting mocks (also using fakinggoose if you want)
*/
import { isArray } from 'class-validator';
import mongoose, { Schema } from 'mongoose';
import { testDbUri } from '../injectMongoConnectionInTests';
import { factory } from 'fakingoose';
import { FactoryOptions } from 'fakingoose/dist/types';
const connectDB = async () => {
const uri = testDbUri;
await mongoose.connect(uri);
if (!mongoose.connection) {
throw new Error('ERROR_WHILE_CONNECTING_TO_DB');
}
};
export async function injectDbMocks<T>(
schemaName: string,
schema: Schema,
data: T | Array<T> | Omit<T, '_id'> | Omit<T, '_id'>[],
): Promise<T | T[]> {
let injected;
const model = mongoose.model(schemaName, schema);
await connectDB();
if (isArray(data)) {
injected = [];
for (const item of data) {
const modelInstance = new model(item);
await modelInstance.save();
injected.push(modelInstance);
}
return injected;
}
const modelInstance = new model(data);
await modelInstance.save();
injected = modelInstance;
return injected;
}
export function getFakingooseFactory<T>(
schema: Schema,
options: FactoryOptions<T> = { _id: { skip: true } },
) {
// @ts-ignore
const model = mongoose.model('fakemodel', schema);
return factory(model, options);
}
export function generateFakeData<T>(schema: Schema): T {
const fakingooseFactory = getFakingooseFactory(schema);
return fakingooseFactory.generate() as T;
}
import { MongoMemoryServer } from 'mongodb-memory-server';
import { ModuleMetadata } from '@nestjs/common/interfaces';
import { MongooseModule } from '@nestjs/mongoose';
import { disconnect } from 'mongoose';
export let dbInstance: MongoMemoryServer;
export let testDbUri: string;
const ensureDbInstance = async () => {
if (!dbInstance) {
dbInstance = await MongoMemoryServer.create();
testDbUri = dbInstance.getUri();
console.log('testDbUri is: ', testDbUri);
}
};
export const injectMongoConnectionInTestsModulesDependencies = (
testModuleConf: ModuleMetadata,
) => {
const fakeDbDependency = MongooseModule.forRootAsync({
useFactory: async () => {
await ensureDbInstance();
return {
uri: testDbUri,
};
},
});
testModuleConf.imports.push(fakeDbDependency);
return testModuleConf;
};
export const killTestingDb = async () => {
await disconnect();
if (dbInstance) await dbInstance.stop();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment