Skip to content

Commit 4a10389

Browse files
authored
fix(NODE-3442): AsyncIterator has incorrect return type (#2916)
1 parent 0f05678 commit 4a10389

File tree

5 files changed

+32
-19
lines changed

5 files changed

+32
-19
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"@types/whatwg-url": "^8.2.1",
5858
"@typescript-eslint/eslint-plugin": "^4.19.0",
5959
"@typescript-eslint/parser": "^4.19.0",
60+
"bluebird": "^3.7.2",
6061
"chai": "^4.2.0",
6162
"chai-subset": "^1.6.0",
6263
"chalk": "^4.1.0",

src/cursor/abstract_cursor.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,14 @@ export abstract class AbstractCursor<
221221
return this[kDocuments].splice(0, number ?? this[kDocuments].length);
222222
}
223223

224-
[Symbol.asyncIterator](): AsyncIterator<TSchema | null> {
224+
[Symbol.asyncIterator](): AsyncIterator<TSchema, void> {
225225
return {
226-
next: () => this.next<TSchema>().then(value => ({ value, done: value === null }))
226+
next: () =>
227+
this.next().then(value =>
228+
value !== null && value !== undefined
229+
? { value, done: false }
230+
: { value: undefined, done: true }
231+
)
227232
};
228233
}
229234

test/functional/cursor_async_iterator.test.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const { expect } = require('chai');
44
const Sinon = require('sinon');
5+
const { Promise: BluebirdPromise } = require('bluebird');
56

67
describe('Cursor Async Iterator Tests', function () {
78
context('default promise library', function () {
@@ -87,11 +88,12 @@ describe('Cursor Async Iterator Tests', function () {
8788
context('custom promise library', () => {
8889
let client, collection, promiseSpy;
8990
before(async function () {
90-
class CustomPromise extends Promise {}
91-
promiseSpy = Sinon.spy(CustomPromise.prototype, 'then');
92-
client = this.configuration.newClient({}, { promiseLibrary: CustomPromise });
91+
promiseSpy = Sinon.spy(BluebirdPromise.prototype, 'then');
92+
client = this.configuration.newClient({}, { promiseLibrary: BluebirdPromise });
9393

94-
await client.connect();
94+
const connectPromise = client.connect();
95+
expect(connectPromise).to.be.instanceOf(BluebirdPromise);
96+
await connectPromise;
9597
const docs = Array.from({ length: 1 }).map((_, index) => ({ foo: index, bar: 1 }));
9698

9799
collection = client.db(this.configuration.db).collection('async_cursor_tests');
@@ -121,5 +123,19 @@ describe('Cursor Async Iterator Tests', function () {
121123
expect(countBeforeIteration).to.not.equal(promiseSpy.callCount);
122124
expect(promiseSpy.called).to.equal(true);
123125
});
126+
127+
it('should properly use custom promise manual iteration', async function () {
128+
const cursor = collection.find();
129+
130+
const iterator = cursor[Symbol.asyncIterator]();
131+
let isDone;
132+
do {
133+
const promiseFromIterator = iterator.next();
134+
expect(promiseFromIterator).to.be.instanceOf(BluebirdPromise);
135+
const { done, value } = await promiseFromIterator;
136+
if (done) expect(value).to.be.a('undefined');
137+
isDone = done;
138+
} while (!isDone);
139+
});
124140
});
125141
});

test/types/community/cursor.test-d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ expectType<{ name: string }[]>(
9494

9595
void async function () {
9696
for await (const item of cursor) {
97-
if (!item) break;
97+
expectNotType<{ foo: number } | null>(item);
9898
expectType<number>(item.foo);
9999
}
100100
};

test/unit/execute_legacy_operation.test.js

+3-12
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,8 @@ describe('executeLegacyOperation', function () {
2828
expect(caughtError).to.equal(expectedError);
2929
});
3030

31-
it('should reject promise with errors on throw errors, and rethrow error', function (done) {
31+
it('should reject promise with errors on throw errors, and rethrow error', function () {
3232
const expectedError = new Error('THIS IS AN ERROR');
33-
let callbackError;
3433

3534
const topology = {
3635
logicalSessionTimeoutMinutes: null
@@ -39,18 +38,10 @@ describe('executeLegacyOperation', function () {
3938
throw expectedError;
4039
};
4140

42-
const callback = err => (callbackError = err);
4341
const options = { skipSessions: true };
4442

45-
executeLegacyOperation(topology, operation, [{}, null], options).then(null, callback);
46-
47-
setTimeout(() => {
48-
try {
49-
expect(callbackError).to.equal(expectedError);
50-
done();
51-
} catch (e) {
52-
done(e);
53-
}
43+
return executeLegacyOperation(topology, operation, [{}, null], options).then(null, err => {
44+
expect(err).to.equal(expectedError);
5445
});
5546
});
5647
});

0 commit comments

Comments
 (0)