meilisearch / meilisearch-js

JavaScript client for the Meilisearch API

Home Page:https://www.meilisearch.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

problematic tests regarding Node.js built-in `fetch`

flevi29 opened this issue · comments

Newer versions of Node.js (LTS 20.10.0, Maintenance 18.19.0) have built-in fetch, so the cross-fetch polyfill has no effect. This means the built-in fetch is used, but this presents a problem with the tests that are run:

So far I identified two reoccurring errors:

● Test on abortable search › Search key: search on index multiple times, and abort only one request

    expect(received).toHaveProperty(path, value)

    Expected path: "message"

    Expected value: "The user aborted a request."
    Received value: "This operation was aborted"

      1002 |
      1003 |     searchPromise.catch((error: any) => {
    > 1004 |       expect(error).toHaveProperty('message', 'The user aborted a request.')
           |                     ^
      1005 |     })
      1006 |   })
      1007 |

      at tests/search.test.ts:1004:21
● Tests on url construction › Test createDump route

    expect(received).rejects.toHaveProperty(path, value)

    Expected path: "message"

    Expected value: "request to http://127.0.0.1:7701/trailing/dumps failed, reason: connect ECONNREFUSED 127.0.0.1:7701"
    Received value: "fetch failed"

      60 |     const strippedHost = trailing ? host.slice(0, -1) : host
      61 |
    > 62 |     await expect(client.createDump()).rejects.toHaveProperty(
         |                                               ^
      63 |       'message',
      64 |       `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
      65 |         'http://',

      at Object.toHaveProperty (node_modules/expect/build/index.js:218:22)
      at tests/dump.test.ts:62:47
      at tests/dump.test.ts:8:71
      at Object.<anonymous>.__awaiter (tests/dump.test.ts:4:12)
      at Object.<anonymous> (tests/dump.test.ts:57:44)

The problem is that network and other errors aren't really standardized in fetch.
There are two potential paths we can take to address this problem:

  • Test for both built-in fetch and node-fetch
  • Simply switch to and require >= maintenance versions of Node.js, which has built-in fetch support, so we only need to test that

related: #1610

About the network error test, the code that we're testing here is flawed. As I said, it's not entirely standardized, so this doesn't work well across browsers and runtimes.

https://github.com/meilisearch/meilisearch-js/blob/main/src/errors/meilisearch-communication-error.ts this probably only works well for node-fetch.

On built-in Node.js fetch most relevant details of the error are behind the property cause, and they might differ in other ways.
In Firefox's version of fetch I get the following error:
image

Also fetch doesn't only throw because of ECONNREFUSED or whatever: https://developer.mozilla.org/en-US/docs/Web/API/fetch#exceptions
This code needs to be rewritten, should open separate issue just on this.

While the tests are passing now because of #1622, it is still relevant, because we're messing with non-standard properties of fetch errors, which means on any other implementation than what cross-fetch provides, they won't work as expected (basically most maintained browsers and newer runtimes with builtin fetch).

Okay, so while experimenting with builtin fetch, found another error:
image
expect header not supported
But because we're messing with the error object, it turns into the following:
image
I assumed the test runner is at fault, but no, it's just that the way health check is done and the error object is messed with takes away all the relevant information as to why this fails.

The gist of it is that builtin fetch actually checks if a provided header is valid and supported.
image
This Expect is an invalid unsupported header.

Okay, so the problem is that builtin undici fetch knows about this header, and this header is a special reserved header, which would require fetch, I presume, to work in a specific way, that it doesn't support.

The solution is to pass a random truly custom header, like 'Hello-There!': 'General Kenobi'. That way it works.