UNPKG

@kenniy/godeye-data-contracts

Version:

Enterprise-grade base repository architecture for GOD-EYE microservices with zero overhead and maximum code reuse

271 lines (270 loc) 10.8 kB
"use strict"; /** * Mongoose Mock Utilities * Provides comprehensive mocking for Mongoose models, queries, and operations */ Object.defineProperty(exports, "__esModule", { value: true }); exports.MockRepositoryBuilder = exports.MongooseMockFactory = void 0; /** * Mongoose Mock Factory - Creates comprehensive Mongoose mocks */ class MongooseMockFactory { /** * Creates a mock query with chainable methods */ static createMockQuery(returnValue) { const mockQuery = { populate: jest.fn().mockReturnThis(), select: jest.fn().mockReturnThis(), sort: jest.fn().mockReturnThis(), limit: jest.fn().mockReturnThis(), skip: jest.fn().mockReturnThis(), lean: jest.fn().mockReturnThis(), exec: jest.fn().mockResolvedValue(returnValue), }; return mockQuery; } /** * Creates a mock document with save functionality */ static createMockDocument(data = {}) { const document = { _id: data._id || 'mock_doc_id', ...data, save: jest.fn().mockResolvedValue({ _id: data._id || 'mock_doc_id', ...data }), toObject: jest.fn().mockReturnValue({ ...data }), toJSON: jest.fn().mockReturnValue({ ...data }), }; return document; } /** * Creates a mock session for transaction testing */ static createMockSession() { return { startTransaction: jest.fn(), commitTransaction: jest.fn().mockResolvedValue(undefined), abortTransaction: jest.fn().mockResolvedValue(undefined), endSession: jest.fn().mockResolvedValue(undefined), }; } /** * Creates a mock aggregate query */ static createMockAggregate(returnValue = []) { const aggregate = { exec: jest.fn().mockResolvedValue(returnValue), allowDiskUse: jest.fn().mockReturnThis(), maxTimeMS: jest.fn().mockReturnThis(), append: jest.fn().mockReturnThis(), }; return aggregate; } /** * Creates a comprehensive mock model with all methods */ static createMockModel(modelName = 'TestModel', collectionName = 'test', schemaPaths = ['_id', '__v', 'name', 'email', 'status', 'createdAt']) { const mockSession = this.createMockSession(); // Create schema mock with paths const mockSchema = { eachPath: jest.fn((callback) => { schemaPaths.forEach(path => { const schemaType = this.createSchemaType(path); callback(path, schemaType); }); }), paths: schemaPaths.reduce((acc, path) => { acc[path] = this.createSchemaType(path); return acc; }, {}), }; const mockDb = { startSession: jest.fn().mockResolvedValue(mockSession), transaction: jest.fn().mockImplementation(async (callback) => { const session = mockSession; return await callback(session); }), }; // Constructor function for creating documents function MockModelConstructor(data = {}) { return MongooseMockFactory.createMockDocument(data); } // Add static methods to constructor const mockModel = MockModelConstructor; // Collection info mockModel.collection = { name: collectionName }; mockModel.modelName = modelName; mockModel.schema = mockSchema; mockModel.db = mockDb; // Query methods mockModel.findOne = jest.fn(() => this.createMockQuery(null)); mockModel.find = jest.fn(() => this.createMockQuery([])); mockModel.findById = jest.fn(() => this.createMockQuery(null)); mockModel.findByIdAndUpdate = jest.fn(() => this.createMockQuery(null)); mockModel.findByIdAndDelete = jest.fn(() => this.createMockQuery(null)); mockModel.findOneAndUpdate = jest.fn(() => this.createMockQuery(null)); mockModel.findOneAndDelete = jest.fn(() => this.createMockQuery(null)); // Bulk operations mockModel.updateMany = jest.fn(() => this.createMockQuery({ modifiedCount: 0 })); mockModel.deleteMany = jest.fn(() => this.createMockQuery({ deletedCount: 0 })); mockModel.insertMany = jest.fn().mockResolvedValue([]); mockModel.bulkWrite = jest.fn().mockResolvedValue({}); // Count and aggregation mockModel.countDocuments = jest.fn(() => this.createMockQuery(0)); mockModel.estimatedDocumentCount = jest.fn(() => this.createMockQuery(0)); mockModel.aggregate = jest.fn(() => this.createMockAggregate([])); // Index operations mockModel.createIndexes = jest.fn().mockResolvedValue({}); mockModel.ensureIndexes = jest.fn().mockResolvedValue({}); // Validation mockModel.validate = jest.fn().mockResolvedValue({}); return mockModel; } /** * Creates schema type information for a given path */ static createSchemaType(path) { const relationPaths = { 'profile': { options: { ref: 'Profile' } }, 'business': { options: { ref: 'Business' } }, 'user': { options: { ref: 'User' } }, 'owner': { options: { ref: 'User' } }, 'author': { options: { ref: 'User' } }, 'posts': { options: { type: [{ ref: 'Post' }] } }, 'comments': { options: { type: [{ ref: 'Comment' }] } }, 'files': { options: { type: [{ ref: 'File' }] } }, 'tags': { options: { type: [{ ref: 'Tag' }] } }, 'folder': { options: { ref: 'Folder' } }, 'permissions': { options: { type: [{ ref: 'Permission' }] } }, }; return relationPaths[path] || { options: {} }; } /** * Creates a repository-specific mock model with common schema */ static createUserModel() { return this.createMockModel('User', 'users', [ '_id', '__v', 'name', 'firstName', 'lastName', 'email', 'status', 'userType', 'verified', 'phone', 'createdAt', 'updatedAt', 'profile', 'business', 'posts' ]); } static createFileModel() { return this.createMockModel('File', 'files', [ '_id', '__v', 'name', 'originalName', 'mimeType', 'size', 'fileType', 'userId', 'folderId', 'tags', 'createdAt', 'updatedAt', 'user', 'folder' ]); } static createProfileModel() { return this.createMockModel('Profile', 'profiles', [ '_id', '__v', 'bio', 'avatar', 'userId', 'profileKind', 'user' ]); } static createBusinessModel() { return this.createMockModel('Business', 'businesses', [ '_id', '__v', 'name', 'type', 'ownerId', 'owner', 'contact' ]); } } exports.MongooseMockFactory = MongooseMockFactory; /** * Mock Repository Builder - Fluent interface for building repository mocks */ class MockRepositoryBuilder { constructor(modelName = 'TestModel', collectionName = 'test') { this.returnValues = {}; this.model = MongooseMockFactory.createMockModel(modelName, collectionName); } static create(modelName, collectionName) { return new MockRepositoryBuilder(modelName, collectionName); } /** * Configure return values for query methods */ withFindOneResult(result) { this.model.findOne.mockReturnValue(MongooseMockFactory.createMockQuery(result)); return this; } withFindResult(results) { this.model.find.mockReturnValue(MongooseMockFactory.createMockQuery(results)); return this; } withFindByIdResult(result) { this.model.findById.mockReturnValue(MongooseMockFactory.createMockQuery(result)); return this; } withCountResult(count) { this.model.countDocuments.mockReturnValue(MongooseMockFactory.createMockQuery(count)); return this; } withAggregateResult(results) { this.model.aggregate.mockReturnValue(MongooseMockFactory.createMockAggregate(results)); return this; } withInsertManyResult(results) { this.model.insertMany.mockResolvedValue(results); return this; } withUpdateResult(result) { this.model.findByIdAndUpdate.mockReturnValue(MongooseMockFactory.createMockQuery(result)); this.model.updateMany.mockReturnValue(MongooseMockFactory.createMockQuery(result)); return this; } withDeleteResult(success = true) { const result = success ? { deletedCount: 1 } : { deletedCount: 0 }; this.model.findByIdAndDelete.mockReturnValue(MongooseMockFactory.createMockQuery(success ? {} : null)); this.model.deleteMany.mockReturnValue(MongooseMockFactory.createMockQuery(result)); return this; } /** * Configure error scenarios */ withFindOneError(error) { const mockQuery = MongooseMockFactory.createMockQuery(null); mockQuery.exec.mockRejectedValue(error); this.model.findOne.mockReturnValue(mockQuery); return this; } withSaveError(error) { // Override the constructor to return a document that fails on save const originalModel = this.model; function FailingMockModel(data) { const doc = MongooseMockFactory.createMockDocument(data); doc.save.mockRejectedValue(error); return doc; } // Copy static methods Object.assign(FailingMockModel, originalModel); this.model = FailingMockModel; return this; } /** * Configure complex aggregation results (for pagination) */ withPaginationResult(items, total) { const aggregateResult = [{ data: items, totalCount: [{ count: total }], }]; this.model.aggregate.mockReturnValue(MongooseMockFactory.createMockAggregate(aggregateResult)); return this; } /** * Reset all mocks to default state */ reset() { jest.clearAllMocks(); // Restore default behaviors this.model.findOne.mockReturnValue(MongooseMockFactory.createMockQuery(null)); this.model.find.mockReturnValue(MongooseMockFactory.createMockQuery([])); this.model.countDocuments.mockReturnValue(MongooseMockFactory.createMockQuery(0)); this.model.aggregate.mockReturnValue(MongooseMockFactory.createMockAggregate([])); return this; } /** * Get the built mock model */ build() { return this.model; } } exports.MockRepositoryBuilder = MockRepositoryBuilder;