elbywan / wretch

A tiny wrapper built around fetch with an intuitive syntax. :candy:
MIT License
4.83k stars 98 forks source link

Quick remedy for "Cannot find module 'wretch/middlewares'" ESM error when using Jest #181

Open dmudro opened 1 year ago

dmudro commented 1 year ago

Jest is a pretty common part of modern app stack. importing wretch middleware in the (non spec) code fails when running the suite:

Cannot find module 'wretch/middlewares' from...

in my case it fails on retry middleware specifically. similar problems have been reported in #144 and #150.

I spent quite some time finding a relatively clean solution and thought to share a simple one that has worked best for me so far:

  1. create a mock module in <root>/__mocks/wretch/middlewares.ts
  2. ...with file content:
    module.exports = {
    retry: jest.fn(),
    };

    (or as needed).

ultimately this issue seems to be related to experimental nature of Jest ESM imports which I do not even have enabled. or perhaps there is something that wretch can do on the export side?

if nothing else I hope the above mocks fix might help someone else.

elbywan commented 1 year ago

Hey @dmudro 👋,

Thanks for the feedback and workaround!

I tried again today with jest 29 and I for me following the jest documentation was good enough to make it work seamlessly.

# install everything
npm i -D jest 
npm i wretch
// This is needed in the package.json
{
  "type": "module",
}
// test.js
import abort from "wretch/addons/abort";
import { delay } from "wretch/middlewares/delay";

test("import addons and middlewares", () => {
  expect(abort).toBeDefined();
  expect(delay).toBeDefined();
  console.log(abort, delay);
});
# run it with the right flag, or set the NODE_OPTIONS=--experimental-vm-modules flag
node --experimental-vm-modules node_modules/jest/bin/jest.js
# Output:

  console.log
    [Function: abort] [Function: delay]

      at Object.log (test.js:7:11)

(node:69465) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
 PASS  ./test.js
  ✓ import addons and middlewares (14 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.281 s, estimated 1 s
Ran all test suites.

With typescript it also works fine for me by installing ts-jest, renaming my test file to .ts and removing the "type": "module", part from the package.json file.

node node_modules/jest/bin/jest.js
  console.log
    [Function (anonymous)] [Function (anonymous)]

      at Object.<anonymous> (test.ts:7:11)

 PASS  ./test.ts
  ✓ import addons and middlewares (19 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.363 s, estimated 1 s
Ran all test suites.
wuahi commented 1 year ago

Hello, i am getting similar errors just using in fastify. My plugin implementation is :

import { FastifyPluginAsync } from 'fastify'
import fp from 'fastify-plugin'
import wretch from 'wretch'
import { retry } from 'wretch/middlewares'

const wretchPlugin: FastifyPluginAsync = async (fastify) => {
    const wretchSetup = wretch().middlewares([retry({ delayTimer: 2000, maxAttempts: 1 })])
    fastify.decorate('wretch', wretchSetup)
}

export default fp(wretchPlugin, {
    name: 'wretch',
})

And the error is: Error: Package subpath './middlewares' is not defined by "exports" in /path/to/file/node_modules/wretch/package.json

wuahi commented 1 year ago

NEVERMIND! i am an idiot :laughing: . There is just a bad index at /middlewares, so it does not properly export the middlewares straight from there. So for example if you need the 'retry' middleware, you want to import it like:

import {retry} from "wretch/middlewares/retry"

Thou id would be nice if the index at /middlewares could also export the middlewares :)