Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add callbackify() and callbackifyAll() methods #82

Merged
merged 12 commits into from Feb 13, 2019

Conversation

AVaksman
Copy link
Contributor

@AVaksman AVaksman commented Feb 4, 2019

  • Tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs - please suggest how to edit README.md

@google-cloud/promisify

A simple utility for promisifying and callbackifying functions and classes.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Feb 4, 2019
src/index.ts Outdated
.then((res: []) => {
cb(null, ...res);
})
.catch((err: Error) => cb(err));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bug. The error handler should be passed as the second parameter of the then method. That prevents errors thrown in the callback method from triggering the catch clause, and double calling the callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Fixed

src/index.ts Outdated
exports.callbackify(originalMethod, options);
}
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

});
});

it('should call the callback with error when promise rejects', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a "it should call the callback only a single time when the promise rejects" to test the error we caught above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test 'should call the callback only a single time when the promise resolves but callback throws an error', however skipping the test as of now as I am unable to catch the error thrown by the callback in the test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused. Why do we need to skip the test? I really think we need to have that enabled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error that is thrown by the callback is crushing the test. I am not able to catch /intercept it.
I tried assert.throws, try=>catch block around func(callback), process.on('uncaughtException'), process.on('unhandledRejection').

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestions would be greatly appreciated.

Copy link
Contributor Author

@AVaksman AVaksman Feb 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the bug was only in case when promise resolves, but callback throws an error, then callback is called again with that error in the catch block.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so in that scenario it would be a user error, I misunderstood. I wonder if we would want to change our logic to look something like this

originalMethod
  .apply(context, arguments)
  // tslint:disable-next-line:no-any
  .then((res: any) => {
    res = Array.isArray(res) ? res : [res];
    cb(null, ...res);
  }, (err: Error) => cb(err))
  .catch(err => process.emitWarning(err));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fill that if error is thrown by the user's function, it should be propagated and the process should crush, no?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the native callbackify doesn't do anything special with the error either. So I don't think we shouldn't concern ourselves with user errors like that.

Copy link
Contributor Author

@AVaksman AVaksman Feb 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caught that error 👍
Test is enabled.

test/index.ts Outdated Show resolved Hide resolved
@JustinBeckwith JustinBeckwith changed the title Add callbackify() and callbackifyAll() feat: add callbackify() and callbackifyAll() methods Feb 6, 2019
@AVaksman
Copy link
Contributor Author

AVaksman commented Feb 6, 2019

Added changes for scenarios when promise returns not array.

src/index.ts Outdated
const originalMethod = Class.prototype[methodName];
if (!originalMethod.callbackified_) {
Class.prototype[methodName] =
exports.callbackify(originalMethod, options);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like callbackify actually accepts any options

});
});

it('should call the callback with error when promise rejects', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of a separate test, you could modify the current test to look like this

const error = new Error('err');
func = util.callbackify(async () => {
  throw error;
});
func((err: Error) => {
  assert.strictEqual(err, error);
  done();
});

If done gets called multiple times the test will fail, so I think that would satisfy @JustinBeckwith's ask (maybe?)

@yoshi-automation yoshi-automation added the 🚨 This issue needs some love. label Feb 11, 2019
@codecov
Copy link

codecov bot commented Feb 13, 2019

Codecov Report

Merging #82 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #82   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           1      1           
  Lines          34     54   +20     
  Branches        5      8    +3     
=====================================
+ Hits           34     54   +20
Impacted Files Coverage Δ
src/index.ts 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3569647...64bf092. Read the comment docs.

@JustinBeckwith JustinBeckwith merged commit c6127bb into googleapis:master Feb 13, 2019
@yoshi-automation yoshi-automation removed the 🚨 This issue needs some love. label Apr 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants