Skip to content

Commit

Permalink
fix(NODE-3442): AsyncIterator has incorrect return type (#2916)
Browse files Browse the repository at this point in the history
  • Loading branch information
nbbeeken committed Jul 21, 2021
1 parent 0f05678 commit 4a10389
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 19 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -57,6 +57,7 @@
"@types/whatwg-url": "^8.2.1",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"bluebird": "^3.7.2",
"chai": "^4.2.0",
"chai-subset": "^1.6.0",
"chalk": "^4.1.0",
Expand Down
9 changes: 7 additions & 2 deletions src/cursor/abstract_cursor.ts
Expand Up @@ -221,9 +221,14 @@ export abstract class AbstractCursor<
return this[kDocuments].splice(0, number ?? this[kDocuments].length);
}

[Symbol.asyncIterator](): AsyncIterator<TSchema | null> {
[Symbol.asyncIterator](): AsyncIterator<TSchema, void> {
return {
next: () => this.next<TSchema>().then(value => ({ value, done: value === null }))
next: () =>
this.next().then(value =>
value !== null && value !== undefined
? { value, done: false }
: { value: undefined, done: true }
)
};
}

Expand Down
24 changes: 20 additions & 4 deletions test/functional/cursor_async_iterator.test.js
Expand Up @@ -2,6 +2,7 @@

const { expect } = require('chai');
const Sinon = require('sinon');
const { Promise: BluebirdPromise } = require('bluebird');

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

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

collection = client.db(this.configuration.db).collection('async_cursor_tests');
Expand Down Expand Up @@ -121,5 +123,19 @@ describe('Cursor Async Iterator Tests', function () {
expect(countBeforeIteration).to.not.equal(promiseSpy.callCount);
expect(promiseSpy.called).to.equal(true);
});

it('should properly use custom promise manual iteration', async function () {
const cursor = collection.find();

const iterator = cursor[Symbol.asyncIterator]();
let isDone;
do {
const promiseFromIterator = iterator.next();
expect(promiseFromIterator).to.be.instanceOf(BluebirdPromise);
const { done, value } = await promiseFromIterator;
if (done) expect(value).to.be.a('undefined');
isDone = done;
} while (!isDone);
});
});
});
2 changes: 1 addition & 1 deletion test/types/community/cursor.test-d.ts
Expand Up @@ -94,7 +94,7 @@ expectType<{ name: string }[]>(

void async function () {
for await (const item of cursor) {
if (!item) break;
expectNotType<{ foo: number } | null>(item);
expectType<number>(item.foo);
}
};
15 changes: 3 additions & 12 deletions test/unit/execute_legacy_operation.test.js
Expand Up @@ -28,9 +28,8 @@ describe('executeLegacyOperation', function () {
expect(caughtError).to.equal(expectedError);
});

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

const topology = {
logicalSessionTimeoutMinutes: null
Expand All @@ -39,18 +38,10 @@ describe('executeLegacyOperation', function () {
throw expectedError;
};

const callback = err => (callbackError = err);
const options = { skipSessions: true };

executeLegacyOperation(topology, operation, [{}, null], options).then(null, callback);

setTimeout(() => {
try {
expect(callbackError).to.equal(expectedError);
done();
} catch (e) {
done(e);
}
return executeLegacyOperation(topology, operation, [{}, null], options).then(null, err => {
expect(err).to.equal(expectedError);
});
});
});

0 comments on commit 4a10389

Please sign in to comment.