import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as smartmongo from '../ts/index.js'; import { MongoClient, Db, Collection } from 'mongodb'; const { congodb } = smartmongo; let server: smartmongo.congodb.CongoServer; let client: MongoClient; let db: Db; // ============================================================================ // Server Startup // ============================================================================ tap.test('congodb: should start the server', async () => { server = new congodb.CongoServer({ port: 27117 }); // Use non-standard port for tests await server.start(); expect(server.running).toBeTrue(); }); tap.test('congodb: should connect with official MongoClient', async () => { client = new MongoClient('mongodb://127.0.0.1:27117', { directConnection: true, serverSelectionTimeoutMS: 5000, }); await client.connect(); expect(client).toBeTruthy(); }); tap.test('congodb: should get a database instance', async () => { db = client.db('testdb'); expect(db).toBeTruthy(); expect(db.databaseName).toEqual('testdb'); }); // ============================================================================ // Basic CRUD Tests // ============================================================================ tap.test('congodb: insertOne - should insert a document', async () => { const collection = db.collection('users'); const result = await collection.insertOne({ name: 'John Doe', email: 'john@example.com', age: 30, }); expect(result.acknowledged).toBeTrue(); expect(result.insertedId).toBeTruthy(); }); tap.test('congodb: insertMany - should insert multiple documents', async () => { const collection = db.collection('users'); const result = await collection.insertMany([ { name: 'Jane Doe', email: 'jane@example.com', age: 25 }, { name: 'Bob Smith', email: 'bob@example.com', age: 35 }, { name: 'Alice Johnson', email: 'alice@example.com', age: 28 }, ]); expect(result.acknowledged).toBeTrue(); expect(result.insertedCount).toEqual(3); expect(Object.keys(result.insertedIds).length).toEqual(3); }); tap.test('congodb: findOne - should find a single document', async () => { const collection = db.collection('users'); const doc = await collection.findOne({ name: 'John Doe' }); expect(doc).toBeTruthy(); expect(doc!.name).toEqual('John Doe'); expect(doc!.email).toEqual('john@example.com'); }); tap.test('congodb: find - should find multiple documents', async () => { const collection = db.collection('users'); const docs = await collection.find({ age: { $gte: 28 } }).toArray(); expect(docs.length).toEqual(3); }); tap.test('congodb: updateOne - should update a single document', async () => { const collection = db.collection('users'); const result = await collection.updateOne( { name: 'John Doe' }, { $set: { age: 31 } } ); expect(result.acknowledged).toBeTrue(); expect(result.matchedCount).toEqual(1); expect(result.modifiedCount).toEqual(1); const updated = await collection.findOne({ name: 'John Doe' }); expect(updated!.age).toEqual(31); }); tap.test('congodb: updateMany - should update multiple documents', async () => { const collection = db.collection('users'); const result = await collection.updateMany( { age: { $gte: 30 } }, { $set: { senior: true } } ); expect(result.acknowledged).toBeTrue(); expect(result.matchedCount).toEqual(2); expect(result.modifiedCount).toEqual(2); }); tap.test('congodb: deleteOne - should delete a single document', async () => { const collection = db.collection('users'); const result = await collection.deleteOne({ name: 'Bob Smith' }); expect(result.acknowledged).toBeTrue(); expect(result.deletedCount).toEqual(1); }); tap.test('congodb: deleteMany - should delete multiple documents', async () => { const collection = db.collection('users'); // First add some test docs to delete await collection.insertMany([ { name: 'Delete1', toDelete: true }, { name: 'Delete2', toDelete: true }, ]); const result = await collection.deleteMany({ toDelete: true }); expect(result.acknowledged).toBeTrue(); expect(result.deletedCount).toEqual(2); }); // ============================================================================ // Query Operator Tests // ============================================================================ tap.test('congodb: query - $eq operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ name: { $eq: 'Jane Doe' } }).toArray(); expect(docs.length).toEqual(1); expect(docs[0].name).toEqual('Jane Doe'); }); tap.test('congodb: query - $ne operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ name: { $ne: 'Jane Doe' } }).toArray(); expect(docs.every(d => d.name !== 'Jane Doe')).toBeTrue(); }); tap.test('congodb: query - $gt and $lt operators', async () => { const collection = db.collection('users'); const docs = await collection.find({ age: { $gt: 25, $lt: 35 } }).toArray(); expect(docs.every(d => d.age > 25 && d.age < 35)).toBeTrue(); }); tap.test('congodb: query - $in operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ name: { $in: ['Jane Doe', 'Alice Johnson'] } }).toArray(); expect(docs.length).toEqual(2); }); tap.test('congodb: query - $or operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ $or: [ { name: 'Jane Doe' }, { age: 31 } ] }).toArray(); expect(docs.length).toBeGreaterThanOrEqual(1); }); tap.test('congodb: query - $and operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ $and: [ { age: { $gte: 25 } }, { age: { $lte: 30 } } ] }).toArray(); expect(docs.every(d => d.age >= 25 && d.age <= 30)).toBeTrue(); }); tap.test('congodb: query - $exists operator', async () => { const collection = db.collection('users'); const docs = await collection.find({ senior: { $exists: true } }).toArray(); expect(docs.every(d => 'senior' in d)).toBeTrue(); }); // ============================================================================ // Update Operator Tests // ============================================================================ tap.test('congodb: update - $inc operator', async () => { const collection = db.collection('users'); await collection.updateOne( { name: 'Jane Doe' }, { $inc: { age: 1 } } ); const updated = await collection.findOne({ name: 'Jane Doe' }); expect(updated!.age).toEqual(26); }); tap.test('congodb: update - $unset operator', async () => { const collection = db.collection('users'); await collection.updateOne( { name: 'Jane Doe' }, { $unset: { senior: '' } } ); const updated = await collection.findOne({ name: 'Jane Doe' }); expect('senior' in updated!).toBeFalse(); }); tap.test('congodb: update - $push operator', async () => { const collection = db.collection('users'); await collection.updateOne( { name: 'Jane Doe' }, { $set: { tags: ['developer'] } } ); await collection.updateOne( { name: 'Jane Doe' }, { $push: { tags: 'tester' } } ); const updated = await collection.findOne({ name: 'Jane Doe' }); expect(updated!.tags).toContain('developer'); expect(updated!.tags).toContain('tester'); }); tap.test('congodb: update - $pull operator', async () => { const collection = db.collection('users'); await collection.updateOne( { name: 'Jane Doe' }, { $pull: { tags: 'tester' } } ); const updated = await collection.findOne({ name: 'Jane Doe' }); expect(updated!.tags).not.toContain('tester'); }); tap.test('congodb: update - upsert creates new document', async () => { const collection = db.collection('users'); const result = await collection.updateOne( { name: 'New User' }, { $set: { email: 'new@example.com', age: 40 } }, { upsert: true } ); expect(result.upsertedCount).toEqual(1); expect(result.upsertedId).toBeTruthy(); const inserted = await collection.findOne({ name: 'New User' }); expect(inserted).toBeTruthy(); expect(inserted!.email).toEqual('new@example.com'); }); // ============================================================================ // Cursor Tests // ============================================================================ tap.test('congodb: cursor - sort', async () => { const collection = db.collection('users'); const docs = await collection.find({}).sort({ age: -1 }).toArray(); for (let i = 1; i < docs.length; i++) { if (docs[i-1].age !== undefined && docs[i].age !== undefined) { expect(docs[i-1].age).toBeGreaterThanOrEqual(docs[i].age); } } }); tap.test('congodb: cursor - limit', async () => { const collection = db.collection('users'); const docs = await collection.find({}).limit(2).toArray(); expect(docs.length).toBeLessThanOrEqual(2); }); tap.test('congodb: cursor - skip', async () => { const collection = db.collection('users'); const allDocs = await collection.find({}).toArray(); const skippedDocs = await collection.find({}).skip(1).toArray(); expect(skippedDocs.length).toEqual(Math.max(0, allDocs.length - 1)); }); tap.test('congodb: cursor - project', async () => { const collection = db.collection('users'); const docs = await collection.find({}).project({ name: 1, _id: 0 }).toArray(); expect(docs.length).toBeGreaterThan(0); expect(docs[0].name).toBeTruthy(); expect(docs[0].email).toBeUndefined(); }); // ============================================================================ // FindOneAnd* Tests // ============================================================================ tap.test('congodb: findOneAndUpdate - returns updated document', async () => { const collection = db.collection('users'); const result = await collection.findOneAndUpdate( { name: 'Jane Doe' }, { $set: { status: 'active' } }, { returnDocument: 'after' } ); expect(result).toBeTruthy(); expect(result!.status).toEqual('active'); }); tap.test('congodb: findOneAndDelete - returns deleted document', async () => { const collection = db.collection('users'); // Insert a temp doc to delete await collection.insertOne({ name: 'TempUser', temp: true }); const result = await collection.findOneAndDelete({ name: 'TempUser' }); expect(result).toBeTruthy(); expect(result!.name).toEqual('TempUser'); // Verify deleted const found = await collection.findOne({ name: 'TempUser' }); expect(found).toBeNull(); }); // ============================================================================ // Count and Distinct Tests // ============================================================================ tap.test('congodb: countDocuments - counts matching documents', async () => { const collection = db.collection('users'); const count = await collection.countDocuments({ age: { $gte: 25 } }); expect(count).toBeGreaterThan(0); }); tap.test('congodb: estimatedDocumentCount - returns total count', async () => { const collection = db.collection('users'); const count = await collection.estimatedDocumentCount(); expect(count).toBeGreaterThan(0); }); tap.test('congodb: distinct - returns unique values', async () => { const collection = db.collection('users'); const names = await collection.distinct('name'); expect(names.length).toBeGreaterThan(0); // All names should be unique expect(new Set(names).size).toEqual(names.length); }); // ============================================================================ // Index Tests // ============================================================================ tap.test('congodb: createIndex - creates a single index', async () => { const collection = db.collection('users'); const indexName = await collection.createIndex({ email: 1 }); expect(indexName).toBeTruthy(); expect(indexName).toContain('email'); }); tap.test('congodb: createIndex - creates compound index', async () => { const collection = db.collection('users'); const indexName = await collection.createIndex({ name: 1, age: -1 }); expect(indexName).toBeTruthy(); }); tap.test('congodb: listIndexes - lists all indexes', async () => { const collection = db.collection('users'); const indexes = await collection.listIndexes().toArray(); expect(indexes.length).toBeGreaterThanOrEqual(1); // At least _id index expect(indexes.some(i => i.name === '_id_')).toBeTrue(); }); tap.test('congodb: dropIndex - drops an index', async () => { const collection = db.collection('users'); const indexName = await collection.createIndex({ toDropField: 1 }); await collection.dropIndex(indexName); const indexes = await collection.listIndexes().toArray(); expect(indexes.some(i => i.name === indexName)).toBeFalse(); }); // ============================================================================ // Aggregation Tests // ============================================================================ tap.test('congodb: aggregate - $match stage', async () => { const collection = db.collection('users'); const results = await collection.aggregate([ { $match: { age: { $gte: 25 } } } ]).toArray(); expect(results.length).toBeGreaterThan(0); expect(results.every(d => d.age >= 25)).toBeTrue(); }); tap.test('congodb: aggregate - $project stage', async () => { const collection = db.collection('users'); const results = await collection.aggregate([ { $project: { name: 1, _id: 0 } } ]).toArray(); expect(results.length).toBeGreaterThan(0); expect(results[0].name).toBeTruthy(); expect(results[0].email).toBeUndefined(); }); tap.test('congodb: aggregate - $sort stage', async () => { const collection = db.collection('users'); const results = await collection.aggregate([ { $match: { age: { $exists: true } } }, { $sort: { age: 1 } } ]).toArray(); for (let i = 1; i < results.length; i++) { expect(results[i].age).toBeGreaterThanOrEqual(results[i-1].age); } }); tap.test('congodb: aggregate - $group stage', async () => { const collection = db.collection('users'); // Add some categorized data await collection.insertMany([ { name: 'GroupTest1', category: 'A', value: 10 }, { name: 'GroupTest2', category: 'A', value: 20 }, { name: 'GroupTest3', category: 'B', value: 30 }, ]); const results = await collection.aggregate([ { $match: { category: { $exists: true } } }, { $group: { _id: '$category', total: { $sum: '$value' } } } ]).toArray(); expect(results.length).toEqual(2); const groupA = results.find(r => r._id === 'A'); const groupB = results.find(r => r._id === 'B'); expect(groupA!.total).toEqual(30); expect(groupB!.total).toEqual(30); }); tap.test('congodb: aggregate - $limit and $skip stages', async () => { const collection = db.collection('users'); const results = await collection.aggregate([ { $skip: 1 }, { $limit: 2 } ]).toArray(); expect(results.length).toBeLessThanOrEqual(2); }); // ============================================================================ // Bulk Operations Tests // ============================================================================ tap.test('congodb: bulkWrite - executes multiple operations', async () => { const collection = db.collection('bulktest'); const result = await collection.bulkWrite([ { insertOne: { document: { name: 'Bulk1', value: 1 } } }, { insertOne: { document: { name: 'Bulk2', value: 2 } } }, { updateOne: { filter: { name: 'Bulk1' }, update: { $set: { updated: true } } } }, ]); expect(result.insertedCount).toEqual(2); expect(result.modifiedCount).toEqual(1); }); // ============================================================================ // Database Operations Tests // ============================================================================ tap.test('congodb: listCollections - lists all collections', async () => { const collections = await db.listCollections().toArray(); expect(collections.length).toBeGreaterThan(0); }); tap.test('congodb: createCollection - creates a new collection', async () => { await db.createCollection('newcollection'); const collections = await db.listCollections().toArray(); expect(collections.some(c => c.name === 'newcollection')).toBeTrue(); }); tap.test('congodb: dropCollection - drops a collection', async () => { await db.createCollection('todrop'); await db.dropCollection('todrop'); const collections = await db.listCollections().toArray(); expect(collections.some(c => c.name === 'todrop')).toBeFalse(); }); // ============================================================================ // Admin Tests // ============================================================================ tap.test('congodb: admin - listDatabases', async () => { const admin = client.db().admin(); const result = await admin.listDatabases(); expect(result.ok).toEqual(1); expect(result.databases).toBeArray(); }); tap.test('congodb: admin - serverStatus', async () => { const admin = client.db().admin(); const status = await admin.serverStatus(); expect(status.ok).toEqual(1); }); tap.test('congodb: admin - ping', async () => { const admin = client.db().admin(); const result = await admin.ping(); expect(result.ok).toEqual(1); }); // ============================================================================ // Replace Operations Tests // ============================================================================ tap.test('congodb: replaceOne - replaces entire document', async () => { const collection = db.collection('replacetest'); await collection.insertOne({ name: 'Original', field1: 'value1', field2: 'value2' }); const result = await collection.replaceOne( { name: 'Original' }, { name: 'Replaced', newField: 'newValue' } ); expect(result.matchedCount).toEqual(1); expect(result.modifiedCount).toEqual(1); const replaced = await collection.findOne({ name: 'Replaced' }); expect(replaced).toBeTruthy(); expect(replaced!.newField).toEqual('newValue'); expect(replaced!.field1).toBeUndefined(); expect(replaced!.field2).toBeUndefined(); }); tap.test('congodb: findOneAndReplace - returns replaced document', async () => { const collection = db.collection('replacetest'); await collection.insertOne({ name: 'ToReplace', data: 'old' }); const result = await collection.findOneAndReplace( { name: 'ToReplace' }, { name: 'Replaced', data: 'new' }, { returnDocument: 'after' } ); expect(result).toBeTruthy(); expect(result!.data).toEqual('new'); }); // ============================================================================ // Cleanup // ============================================================================ tap.test('congodb: cleanup - drop database', async () => { const result = await db.dropDatabase(); expect(result).toBeTrue(); }); tap.test('congodb: cleanup - close client and server', async () => { await client.close(); await server.stop(); expect(server.running).toBeFalse(); }); export default tap.start();