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

TypeError in Node 12 #1509

Closed
panva opened this issue Apr 17, 2019 · 18 comments
Closed

TypeError in Node 12 #1509

panva opened this issue Apr 17, 2019 · 18 comments

Comments

@panva
Copy link

panva commented Apr 17, 2019

A quick heads up, feel free to close once you acknowledge. The test suite does not pass under node 12 (both nock latest and beta channels).

Tested using node nighly build, installed using

NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly/
nvm i node

Here's the trace i'm getting when pre-testing my modules' test suite relying on nock under node 12, same issue.

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type function
    at Function.from (buffer.js:218:9)
    at OverriddenClientRequest.RequestOverrider.req.write (/node_modules/nock/lib/request_overrider.js:112:27)
    at OverriddenClientRequest.RequestOverrider.req.end (/node_modules/nock/lib/request_overrider.js:133:11)
    at handleRequest (/node_modules/got/source/request-as-event-emitter.js:211:14)
    at get (/node_modules/got/source/request-as-event-emitter.js:235:5)
    at Immediate.<anonymous> (/node_modules/got/source/request-as-event-emitter.js:306:10)
@paulmelnikow
Copy link
Member

Thanks for the report!

We'd be happy to have help looking into and addressing the root cause!

@paulmelnikow
Copy link
Member

It looks like it has to do with the allowed arguments to request.end. We don't handle the case where callback is specified but buffer and encoding are not, or where buffer and callback are provided but encoding is not.

Not sure why this is different in Node 12, though. 🤔

It would be helpful to have some more tests written from the perspective of an http client library, which check that the functions can be called in all the same ways as the native functions.

@panva
Copy link
Author

panva commented Apr 23, 2019

The "problem" is that Buffer.from now throws on invalid inputs.

V11

> Buffer.from(()=>{})
<Buffer >

V12

> Buffer.from(()=>{})
Thrown:
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type function
    at Function.from (buffer.js:219:9)
    at repl:1:8

request_overrider's req.write should handle the "optionality" of arguments and not blindly pass them to Buffer.from

@panva
Copy link
Author

panva commented Apr 24, 2019

I am now applying this patch to nock 10.0.6 to have my CI pass under node 12. It's probably not the complete solution tho.

@gr2m
Copy link
Member

gr2m commented Apr 24, 2019

@panva meta question: how do the patches get applied in https://github.com/panva/node-oidc-provider?

@panva
Copy link
Author

panva commented Apr 24, 2019

@gr2m travis.yml before_script hook using patch-package module.

@mastermatt
Copy link
Member

For reference, here is how Node handles the optional params for end.
https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js#L672-L678

Personally, I prefer @panva version because Node allows for .end(callback, encoding) but the docs don't cover it.

@paulmelnikow
Copy link
Member

This issue feels important to resolve! ♨️

For reference, here is how Node handles the optional params for end.
https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js#L672-L678

Personally, I prefer @panva version because Node allows for .end(callback, encoding) but the docs don't cover it.

We should definitely match Node's behavior and the docs. If Node's behavior and the docs conflict we can match the behavior, though we obviously should not implement any new behavior.

This should be tested with a test that uses http, calls request.end() in the various expected ways, and asserts the result is as intended.

In general I'd like to segregate the tests that test nock's mock surface, i.e. the part that HTTP clients interact with, from the high-level functional tests calling through the nock public interface, that make up most of our tests. The new tests for this issue could go in a new file and I can work on collecting the rest of these tests at a later date.

If anyone wants to pick this up, I'd be happy to review it!

gugu added a commit to gugu/nock that referenced this issue May 8, 2019
According to docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Fixes nock#1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
gugu added a commit to gugu/nock that referenced this issue May 9, 2019
According to docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Fixes nock#1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
paulmelnikow pushed a commit that referenced this issue May 9, 2019
According to the docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Closes #1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
@nockbot
Copy link
Collaborator

nockbot commented May 9, 2019

🎉 This issue has been resolved in version 11.0.0-beta.13 🎉

The release is available on:

Your semantic-release bot 📦🚀

@panva
Copy link
Author

panva commented May 9, 2019

@paulmelnikow would it be too much of a hassle to land this on the 10.x release line as well?

@paulmelnikow
Copy link
Member

11.x will be released very soon and feedback on the beta releases would be very helpful. Though if someone wants to backport the fix and the test in a new PR on the master branch, I suppose we could ship it!

@gugu
Copy link
Contributor

gugu commented May 9, 2019

Thanks, I upgraded to 11.0.0-beta.13, works fine for me

@paulmelnikow paulmelnikow changed the title issues under node 12 TypeError in Node 12 May 9, 2019
@paulmelnikow
Copy link
Member

paulmelnikow commented May 9, 2019

Thanks @gugu for implementing this fix!

I think we still need to handle the .end(encoding, callback) form. I'll open a new issue for that.

Added: #1549

@gugu
Copy link
Contributor

gugu commented May 9, 2019

Do we? According to the docs, signature is
request.end([data[, encoding]][, callback])
it means, it can be
request.end(data, encoding, callback) or
request.end(data, encoding) or
request.end(callback) or
request.end(data, callback) or
request.end(data) or
request.end()

According to this, .end(encoding, callback) is not a valid signature

https://nodejs.org/api/http.html#http_request_end_data_encoding_callback

@mastermatt
Copy link
Member

@gugu check out my comment above, #1509 (comment)
The docs don't cover that form, but the implementation does. The question is which way do we prefer?

Since we're trying to mimic, it might be worth simply copying the implementation from the Node source, despite the docs. 🤷‍♂

@paulmelnikow
Copy link
Member

paulmelnikow commented May 9, 2019

Ah, indeed!

Though I think we're not handling request.end(data, callback) case.

Added: I think matching the undocumented behavior of the implementation is a good idea.

@panva
Copy link
Author

panva commented May 9, 2019

@gugu thanks for taking the time to fix this!

sounisi5011 added a commit to sounisi5011/metalsmith-netlify-published-date that referenced this issue Jul 20, 2019
* nock@10.0.6 -> nock@11.0.0-beta.13

Addressed this bug: nock/nock#1509
@nockbot
Copy link
Collaborator

nockbot commented Aug 13, 2019

🎉 This issue has been resolved in version 11.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

gr2m pushed a commit that referenced this issue Sep 4, 2019
According to the docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Closes #1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
gr2m pushed a commit that referenced this issue Sep 4, 2019
According to the docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Closes #1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
gr2m pushed a commit that referenced this issue Sep 5, 2019
According to the docs, `req.end` can accept callback as a first argument. That's what `got` module does.

Closes #1509

```
request.end([data[, encoding]][, callback])#

History
data <string> | <Buffer>
encoding <string>
callback <Function>
Returns: <this>
Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream. If the request is chunked, this will send the terminating '0\r\n\r\n'.

If data is specified, it is equivalent to calling request.write(data, encoding) followed by request.end(callback).

If callback is specified, it will be called when the request stream is finished.
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants