-
Notifications
You must be signed in to change notification settings - Fork 39
test: replaced node-fetch with native fetch in test setup #2022
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
base: main
Are you sure you want to change the base?
Conversation
f6e2ca8 to
9a12921
Compare
8ae3d4d to
9b3dec7
Compare
9b3dec7 to
1c4034b
Compare
a2d3f22 to
72fbfc4
Compare
| 'request to http://127.0.0.1:65212/ failed, reason: connect ' + | ||
| 'ECONNREFUSED 127.0.0.1:65212 -- console.error - should be traced' | ||
| )); | ||
| runAndTrace('exit-span', true, 'fetch failed -- console.error - should be traced')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Native fetch and node-fetch represent the same failure; they are just surfaced differently.
Native fetch:
- Throws a TypeError: fetch failed
- The real cause is nested under error.cause
node-fetch:
- Throws a FetchError
- The connection error is exposed directly
b17ea69 to
f1ba9ae
Compare
| if (process.env.DETACHED_REQUEST) { | ||
| setTimeout(async () => { | ||
| await fetch(downstreamDummyUrl, { headers: { 'X-Downstream-Header': 'yes' } }); | ||
| const fetchResponse = await fetch(downstreamDummyUrl, { headers: { 'X-Downstream-Header': 'yes' } }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes because native fetch and node-fetch v2 complete the request at different points in the lifecycle.
Native fetch resolves when response headers arrive, not when the body finishes. The response body is streamed, and if it isn’t consumed, the tracing span is finalized too early and no trace is emitted.
node-fetch v2 tracks the full HTTP lifecycle, so traces are generated even without reading the body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Native fetch resolves when response headers arrive, not when the body finishes. The response body is streamed, and if it isn’t consumed, the tracing span is finalized too early and no trace is emitted.
Don't we have to add await response.json(); to all apps?
We usually only do
fetch(`http://127.0.0.1:${agentPort}/ping`)
.then(() => {
httpSuccess(res, data);
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. I only applied this to the cases where tests were breaking (when fetch is called inside a setTimeout, etc.). In the other cases, using await fetch() or .then() allows the promise to resolve and the instrumentation’s .finally() to run, so the span is transmitted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed: this needs more investigation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bug/misbehavior in nativeFetch.
finally is triggered with a delay when using without .text() or .json(). This is not right IMO.
We already receive the response.headers in the then method.
I am quiet sure that the one who added finally intend to handle success or error in one place.
Similar to httpClient (please compare):
- we wait for response headers
- span.d + transmit is executed after the headers (not after the body)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, I’ll check this and see whether we can fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we should fix this issue as a PR before this PR 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
created a pr #2265
|
I believe this also needs to be removed!
|
@abhilash-sivan IMO, this is not part of the test setup code. It is a minimal test application (metrics-test-app) that exists solely to be test the metrics collection. The purpose of the test is to verify that when this application runs with node-fetch as a dependency, the metrics system reports it correctly. Therefore, this dependency is not related to test setup and does not need to be replaced or removed the test explicitly requires an external dependency to validate the behavior. |
abhilash-sivan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
kirrg001
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments 👍
| // To use it in a CommonJS environment, we load it via a dynamic import and | ||
| // forward all arguments to the default export. | ||
| // eslint-disable-next-line no-shadow | ||
| const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this part of this PR? Looks like a separate PR to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve created a separate PR to clarify and extend the tests: #2264.
| if (process.env.DETACHED_REQUEST) { | ||
| setTimeout(async () => { | ||
| await fetch(downstreamDummyUrl, { headers: { 'X-Downstream-Header': 'yes' } }); | ||
| const fetchResponse = await fetch(downstreamDummyUrl, { headers: { 'X-Downstream-Header': 'yes' } }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bug/misbehavior in nativeFetch.
finally is triggered with a delay when using without .text() or .json(). This is not right IMO.
We already receive the response.headers in the then method.
I am quiet sure that the one who added finally intend to handle success or error in one place.
Similar to httpClient (please compare):
- we wait for response headers
- span.d + transmit is executed after the headers (not after the body)
|



Migrate test setup files from
node-fetch-v2to the nativefetchAPI available in Node.js 18+. This change removes the dependency onnode-fetch-v2in the test code and uses the built-infetchimplementation instead.Note:
This update replaces all usages of
node-fetch-v2in the test setup.Background:
node-fetch-v2: https://github.com/instana/nodejs/pull/1160/files