From 33c12b3b013bfb72b524cf43a40e65464a32f860 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 6 Oct 2025 09:06:07 +0200 Subject: [PATCH 1/6] test(NODE-7191): convert tests in typescript --- ...on.test.js => document_validation.test.ts} | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) rename test/integration/crud/{document_validation.test.js => document_validation.test.ts} (87%) diff --git a/test/integration/crud/document_validation.test.js b/test/integration/crud/document_validation.test.ts similarity index 87% rename from test/integration/crud/document_validation.test.js rename to test/integration/crud/document_validation.test.ts index e17f93d8225..a52608fc4aa 100644 --- a/test/integration/crud/document_validation.test.js +++ b/test/integration/crud/document_validation.test.ts @@ -1,6 +1,6 @@ -'use strict'; -const { assert: test, setupDatabase } = require('../shared'); -const { expect } = require('chai'); +import { expect } from 'chai'; + +import { assert as test, setupDatabase } from '../shared'; describe('Document Validation', function () { before(function () { @@ -18,14 +18,14 @@ describe('Document Validation', function () { }, test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); + const configuration = this.configuration; + const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { - var db = client.db(configuration.db); + const db = client.db(configuration.db); expect(err).to.not.exist; // Get collection - var col = db.collection('createValidationCollection'); + const col = db.collection('createValidationCollection'); // Drop the collection col.drop(function () { @@ -75,14 +75,14 @@ describe('Document Validation', function () { }, test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); + const configuration = this.configuration; + const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { - var db = client.db(configuration.db); + const db = client.db(configuration.db); expect(err).to.not.exist; // Get collection - var col = db.collection('createValidationCollection'); + const col = db.collection('createValidationCollection'); // Drop the collection col.drop(function () { @@ -157,14 +157,14 @@ describe('Document Validation', function () { }, test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); + const configuration = this.configuration; + const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { - var db = client.db(configuration.db); + const db = client.db(configuration.db); expect(err).to.not.exist; // Get collection - var col = db.collection('createValidationCollection'); + const col = db.collection('createValidationCollection'); // Drop the collection col.drop(function () { @@ -207,14 +207,14 @@ describe('Document Validation', function () { }, test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); + const configuration = this.configuration; + const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { - var db = client.db(configuration.db); + const db = client.db(configuration.db); expect(err).to.not.exist; // Get collection - var col = db.collection('createValidationCollection'); + const col = db.collection('createValidationCollection'); // Drop the collection col.drop(function () { @@ -269,12 +269,12 @@ describe('Document Validation', function () { }, test: function (done) { - var configuration = this.configuration; - var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); + const configuration = this.configuration; + const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { - var db = client.db(configuration.db); + const db = client.db(configuration.db); // Some docs for insertion - var docs = [ + const docs = [ { title: 'this is my title', author: 'bob', @@ -290,7 +290,7 @@ describe('Document Validation', function () { ]; // Get collection - var col = db.collection('createValidationCollectionOut'); + const col = db.collection('createValidationCollectionOut'); // Drop the collection col.drop(function () { From 8986efb258cfd63f04149b5b05d748fe9dd7617c Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 6 Oct 2025 09:29:03 +0200 Subject: [PATCH 2/6] test(NODE-7191): refactor tests --- .../crud/document_validation.test.ts | 495 +++++++----------- 1 file changed, 180 insertions(+), 315 deletions(-) diff --git a/test/integration/crud/document_validation.test.ts b/test/integration/crud/document_validation.test.ts index a52608fc4aa..01c81e70a56 100644 --- a/test/integration/crud/document_validation.test.ts +++ b/test/integration/crud/document_validation.test.ts @@ -1,345 +1,210 @@ import { expect } from 'chai'; +import { MongoBulkWriteError, type MongoClient, MongoServerError } from '../../../src'; import { assert as test, setupDatabase } from '../shared'; -describe('Document Validation', function () { +describe.only('Document Validation', function () { + let client: MongoClient; + before(function () { return setupDatabase(this.configuration); }); - it('should allow bypassing document validation in 3.2 or higher on inserts', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { - mongodb: '>=3.1.7', - topology: ['single', 'replicaset', 'sharded'] - } - }, - - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - expect(err).to.not.exist; - - // Get collection - const col = db.collection('createValidationCollection'); - - // Drop the collection - col.drop(function () { - // Create a collection with a validator - db.createCollection( - 'createValidationCollection', - { validator: { a: { $exists: true } } }, - function (err) { - expect(err).to.not.exist; - - // Ensure validation was correctly applied - col.insert({ b: 1 }, function (err) { - test.ok(err != null); - - // Ensure validation was correctly applied - col.insert({ b: 1 }, { bypassDocumentValidation: true }, function (err) { - expect(err).to.not.exist; - - // Bypass valiation on insert - col.insertOne({ b: 1 }, { bypassDocumentValidation: true }, function (err) { - expect(err).to.not.exist; - - // Bypass valiation on insert - col.insertMany([{ b: 1 }], { bypassDocumentValidation: true }, function (err) { - expect(err).to.not.exist; - - client.close(done); - }); - }); - }); - }); - } - ); - }); + beforeEach(function () { + client = this.configuration.newClient(this.configuration.writeConcernMax(), { maxPoolSize: 1 }); + }); + + afterEach(async function () { + await client?.close(); + }); + + it('should allow bypassing document validation on inserts', { + metadata: { requires: { topology: ['single', 'replicaset', 'sharded'] } }, + + test: async function () { + const db = client.db(this.configuration.db); + + // Get collection + const col = db.collection('createValidationCollection'); + + // Drop the collection + await col.drop(); + // Create a collection with a validator + await db.createCollection('createValidationCollection', { + validator: { a: { $exists: true } } }); + + // Ensure validation was correctly applied + const err = await col.insertOne({ b: 1 }).catch(err => err); + test.ok(err instanceof MongoServerError); + + // Bypass valiation on insertOne + await col.insertOne({ b: 1 }, { bypassDocumentValidation: true }); + + // Bypass valiation on insertMany + await col.insertMany([{ b: 1 }], { bypassDocumentValidation: true }); } }); - it('should allow bypassing document validation in 3.2 or higher on updates', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { - mongodb: '>=3.1.7', - topology: ['single', 'replicaset', 'sharded'] - } - }, - - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - expect(err).to.not.exist; - - // Get collection - const col = db.collection('createValidationCollection'); - - // Drop the collection - col.drop(function () { - // Create a collection with a validator - db.createCollection( - 'createValidationCollection', - { validator: { a: { $exists: true } } }, - function (err) { - expect(err).to.not.exist; - - // Should fail - col.update({ b: 1 }, { $set: { b: 1 } }, { upsert: true }, function (err) { - expect(err).to.exist; - - // Ensure validation was correctly applied - col.update( - { b: 1 }, - { $set: { b: 1 } }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - // updateOne - col.updateOne( - { c: 1 }, - { $set: { c: 1 } }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - // updateMany - col.updateMany( - { d: 1 }, - { $set: { d: 1 } }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - // updateMany - col.replaceOne( - { e: 1 }, - { e: 1 }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - client.close(done); - } - ); - } - ); - } - ); - } - ); - }); - } - ); - }); + it('should allow bypassing document validation on updates', { + metadata: { requires: { topology: ['single', 'replicaset', 'sharded'] } }, + + test: async function () { + const db = client.db(this.configuration.db); + + // Get collection + const col = db.collection('createValidationCollection'); + + // Drop the collection + await col.drop(); + // Create a collection with a validator + await db.createCollection('createValidationCollection', { + validator: { a: { $exists: true } } }); + + // Should fail + const err = await col + .updateOne({ b: 1 }, { $set: { b: 1 } }, { upsert: true }) + .catch(err => err); + expect(err).to.be.instanceOf(MongoServerError); + + // Ensure validation was correctly applied + await col.updateOne( + { b: 1 }, + { $set: { b: 1 } }, + { upsert: true, bypassDocumentValidation: true } + ); + + // updateMany + await col.updateMany( + { d: 1 }, + { $set: { d: 1 } }, + { upsert: true, bypassDocumentValidation: true } + ); + + // replaceOne + await col.replaceOne({ e: 1 }, { e: 1 }, { upsert: true, bypassDocumentValidation: true }); } }); - it('should allow bypassing document validation in 3.2 or higher on bulkWrite', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { - mongodb: '>=3.1.7', - topology: ['single', 'replicaset', 'sharded'] - } - }, - - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - expect(err).to.not.exist; - - // Get collection - const col = db.collection('createValidationCollection'); - - // Drop the collection - col.drop(function () { - // Create a collection with a validator - db.createCollection( - 'createValidationCollection', - { validator: { a: { $exists: true } } }, - function (err) { - expect(err).to.not.exist; - - // Should fail - col.bulkWrite([{ insertOne: { b: 1 } }], function (err) { - test.ok(err != null); - - col.bulkWrite( - [{ insertOne: { b: 1 } }], - { bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - client.close(done); - } - ); - }); - } - ); - }); + it('should allow bypassing document validation on bulkWrite', { + metadata: { requires: { topology: ['single', 'replicaset', 'sharded'] } }, + + test: async function () { + const db = client.db(this.configuration.db); + + // Get collection + const col = db.collection('createValidationCollection'); + + // Drop the collection + await col.drop(); + // Create a collection with a validator + await db.createCollection('createValidationCollection', { + validator: { a: { $exists: true } } + }); + + // Should fail + const err = await col.bulkWrite([{ insertOne: { document: { b: 1 } } }]).catch(err => err); + expect(err).to.be.instanceOf(MongoBulkWriteError); + + await col.bulkWrite([{ insertOne: { document: { b: 1 } } }], { + bypassDocumentValidation: true }); } }); - it('should allow bypassing document validation in 3.2 or higher on findAndModify', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { - mongodb: '>=3.1.7', - topology: ['single', 'replicaset', 'sharded'] - } - }, - - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - expect(err).to.not.exist; - - // Get collection - const col = db.collection('createValidationCollection'); - - // Drop the collection - col.drop(function () { - // Create a collection with a validator - db.createCollection( - 'createValidationCollection', - { validator: { a: { $exists: true } } }, - function (err) { - expect(err).to.not.exist; - - // Should fail - col.findOneAndUpdate({ b: 1 }, { $set: { b: 1 } }, { upsert: true }, function (err) { - test.ok(err != null); - - // Should pass - col.findOneAndUpdate( - { b: 1 }, - { $set: { b: 1 } }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - // Should pass - col.findOneAndReplace( - { c: 1 }, - { c: 1 }, - { upsert: true, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - client.close(done); - } - ); - } - ); - }); - } - ); - }); + it('should allow bypassing document validation on findAndModify', { + metadata: { requires: { topology: ['single', 'replicaset', 'sharded'] } }, + + test: async function () { + const db = client.db(this.configuration.db); + + // Get collection + const col = db.collection('createValidationCollection'); + + // Drop the collection + await col.drop(); + // Create a collection with a validator + await db.createCollection('createValidationCollection', { + validator: { a: { $exists: true } } }); + + // Should fail + const err = await col + .findOneAndUpdate({ b: 1 }, { $set: { b: 1 } }, { upsert: true }) + .catch(err => err); + expect(err).to.be.instanceOf(MongoServerError); + + // Should pass + await col.findOneAndUpdate( + { b: 1 }, + { $set: { b: 1 } }, + { upsert: true, bypassDocumentValidation: true } + ); + + // Should pass + await col.findOneAndReplace( + { c: 1 }, + { c: 1 }, + { upsert: true, bypassDocumentValidation: true } + ); } }); it('should correctly bypass validation for aggregation using out', { - // Add a tag that our runner can trigger on - // in this case we are setting that node needs to be higher than 0.10.X to run - metadata: { - requires: { - mongodb: '>=3.1.7', - topology: ['single', 'replicaset', 'sharded'] - } - }, - - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); - client.connect(function (err, client) { - const db = client.db(configuration.db); - // Some docs for insertion - const docs = [ + metadata: { requires: { topology: ['single', 'replicaset', 'sharded'] } }, + + test: async function () { + const db = client.db(this.configuration.db); + // Some docs for insertion + const docs = [ + { + title: 'this is my title', + author: 'bob', + posted: new Date(), + pageViews: 5, + tags: ['fun', 'good', 'fun'], + other: { foo: 5 }, + comments: [ + { author: 'joe', text: 'this is cool' }, + { author: 'sam', text: 'this is bad' } + ] + } + ]; + + // Get collection + const col = db.collection('createValidationCollectionOut'); + + // Drop the collection + await col.drop(); + // Create a collection with a validator + await db.createCollection('createValidationCollectionOut', { + validator: { a: { $exists: true } } + }); + // Insert the docs + await col.insertMany(docs, { writeConcern: { w: 1 }, bypassDocumentValidation: true }); + + // Execute aggregate, notice the pipeline is expressed as an Array + const cursor = col.aggregate( + [ { - title: 'this is my title', - author: 'bob', - posted: new Date(), - pageViews: 5, - tags: ['fun', 'good', 'fun'], - other: { foo: 5 }, - comments: [ - { author: 'joe', text: 'this is cool' }, - { author: 'sam', text: 'this is bad' } - ] - } - ]; - - // Get collection - const col = db.collection('createValidationCollectionOut'); - - // Drop the collection - col.drop(function () { - // Create a collection with a validator - db.createCollection( - 'createValidationCollectionOut', - { validator: { a: { $exists: true } } }, - function (err) { - expect(err).to.not.exist; - - // Insert the docs - col.insertMany( - docs, - { writeConcern: { w: 1 }, bypassDocumentValidation: true }, - function (err) { - expect(err).to.not.exist; - - // Execute aggregate, notice the pipeline is expressed as an Array - const cursor = col.aggregate( - [ - { - $project: { - author: 1, - tags: 1 - } - }, - { $unwind: '$tags' }, - { - $group: { - _id: { tags: '$tags' }, - authors: { $addToSet: '$author' } - } - }, - { $out: 'createValidationCollectionOut' } - ], - { bypassDocumentValidation: true } - ); - - cursor.toArray(function (err) { - expect(err).to.not.exist; - - client.close(done); - }); - } - ); + $project: { + author: 1, + tags: 1 } - ); - }); - }); + }, + { $unwind: '$tags' }, + { + $group: { + _id: { tags: '$tags' }, + authors: { $addToSet: '$author' } + } + }, + { $out: 'createValidationCollectionOut' } + ], + { bypassDocumentValidation: true } + ); + await cursor.toArray(); } }); }); From 7d196c7298d4647e7b7f76ae6aa675bef1b876e1 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 6 Oct 2025 09:50:54 +0200 Subject: [PATCH 3/6] ignore nsNotFound errors --- test/integration/crud/document_validation.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/integration/crud/document_validation.test.ts b/test/integration/crud/document_validation.test.ts index 01c81e70a56..1bc943027fc 100644 --- a/test/integration/crud/document_validation.test.ts +++ b/test/integration/crud/document_validation.test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { MongoBulkWriteError, type MongoClient, MongoServerError } from '../../../src'; -import { assert as test, setupDatabase } from '../shared'; +import { assert as test, ignoreNsNotFound, setupDatabase } from '../shared'; describe.only('Document Validation', function () { let client: MongoClient; @@ -28,7 +28,7 @@ describe.only('Document Validation', function () { const col = db.collection('createValidationCollection'); // Drop the collection - await col.drop(); + await col.drop().catch(ignoreNsNotFound); // Create a collection with a validator await db.createCollection('createValidationCollection', { validator: { a: { $exists: true } } @@ -56,7 +56,7 @@ describe.only('Document Validation', function () { const col = db.collection('createValidationCollection'); // Drop the collection - await col.drop(); + await col.drop().catch(ignoreNsNotFound); // Create a collection with a validator await db.createCollection('createValidationCollection', { validator: { a: { $exists: true } } @@ -97,7 +97,7 @@ describe.only('Document Validation', function () { const col = db.collection('createValidationCollection'); // Drop the collection - await col.drop(); + await col.drop().catch(ignoreNsNotFound); // Create a collection with a validator await db.createCollection('createValidationCollection', { validator: { a: { $exists: true } } @@ -123,7 +123,7 @@ describe.only('Document Validation', function () { const col = db.collection('createValidationCollection'); // Drop the collection - await col.drop(); + await col.drop().catch(ignoreNsNotFound); // Create a collection with a validator await db.createCollection('createValidationCollection', { validator: { a: { $exists: true } } @@ -176,7 +176,7 @@ describe.only('Document Validation', function () { const col = db.collection('createValidationCollectionOut'); // Drop the collection - await col.drop(); + await col.drop().catch(ignoreNsNotFound); // Create a collection with a validator await db.createCollection('createValidationCollectionOut', { validator: { a: { $exists: true } } From 3f98aca4bdeedddfd6aace739694c7db21f87737 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Mon, 6 Oct 2025 10:20:52 +0200 Subject: [PATCH 4/6] remove .only --- test/integration/crud/document_validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/document_validation.test.ts b/test/integration/crud/document_validation.test.ts index 1bc943027fc..3e74daaf4f4 100644 --- a/test/integration/crud/document_validation.test.ts +++ b/test/integration/crud/document_validation.test.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { MongoBulkWriteError, type MongoClient, MongoServerError } from '../../../src'; import { assert as test, ignoreNsNotFound, setupDatabase } from '../shared'; -describe.only('Document Validation', function () { +describe('Document Validation', function () { let client: MongoClient; before(function () { From ae26fbcb13e1c108c0b7d92cbf82f9fafea52d64 Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Tue, 7 Oct 2025 13:44:28 +0200 Subject: [PATCH 5/6] use chai.expect for asserting instanceof --- test/integration/crud/document_validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/document_validation.test.ts b/test/integration/crud/document_validation.test.ts index 3e74daaf4f4..b7cb76ab939 100644 --- a/test/integration/crud/document_validation.test.ts +++ b/test/integration/crud/document_validation.test.ts @@ -36,7 +36,7 @@ describe('Document Validation', function () { // Ensure validation was correctly applied const err = await col.insertOne({ b: 1 }).catch(err => err); - test.ok(err instanceof MongoServerError); + expect(err).to.be.instanceOf(MongoServerError); // Bypass valiation on insertOne await col.insertOne({ b: 1 }, { bypassDocumentValidation: true }); From e6d59bf14ae6adc7f065f1dc5fbbd22c75127b0d Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Tue, 7 Oct 2025 16:47:59 +0200 Subject: [PATCH 6/6] fix linting issues --- test/integration/crud/document_validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/document_validation.test.ts b/test/integration/crud/document_validation.test.ts index b7cb76ab939..ec60976e420 100644 --- a/test/integration/crud/document_validation.test.ts +++ b/test/integration/crud/document_validation.test.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { MongoBulkWriteError, type MongoClient, MongoServerError } from '../../../src'; -import { assert as test, ignoreNsNotFound, setupDatabase } from '../shared'; +import { ignoreNsNotFound, setupDatabase } from '../shared'; describe('Document Validation', function () { let client: MongoClient;