Loopback: The loopback#urlNotFound and loopback#errorHandler middleware file paths can not be resolved in test env

Created on 6 Apr 2016  Â·  19Comments  Â·  Source: strongloop/loopback

In my test env, it try to resolve paths from following positions:

  • try resolve loopback#urlNotFound at node_modules/loopback/server/middleware/urlNotFound.js
  • try resolve loopback#errorHandler at node_modules/loopback/server/middleware/errorHandler.js

and In fact, the correct filename are url-not-found.js and error-handler.js, In development and production environments, They are works, why?

help wanted

Most helpful comment

After a prolonged fight, this preset fixed all of the issues we were facing: https://github.com/negativetwelve/jest-preset-loopback

All 19 comments

Are you getting an error message? or there is a specific problem?
I have a test file where I set

process.env.NODE_ENV = 'test'

and it works fine.. if you have a repo, you can refer me to for your case, it will help me sort this problem out. Thanks.

Hi @xixilive
There is a new errorhandler in place so those problems will be fixed soon.
Thanks for pointing out the issue.

Hi @loay, I face the same issue when running test with jest.

  Cannot resolve path "loopback/server/middleware/urlNotFound"

      at resolveAppPath (node_modules/loopback-boot/lib/compiler.js:386:15)

Currently, I work around by renaming the file from url-not-found.js to urlNotFound.js. Should we fix it in loopback-boot to get the correct file name?

AFAIK, loopback#urlNotFound is usually resolved by loopback-boot to require('loopback').urlNotFound. When require('loopback') does not export urlNotFound property, then loopback-boot is trying to treat the fragment as a filename. Here is the relevant source code in 2.x branch: lib/compiler.js.

I suspect jest is modifying the outcome of require('loopback') in such way that require('loopback').urlNotFound is no longer defined.

It seems like url-not-found and error-handler are treated differently by re-naming file names into camelCase properties.

So, can we just re-name the fragment back to the correct file name like the following?

if (fragment) {
  if (fragment === 'urlNoFound') {
    fragment = 'url-not-found';
  }
  if (fragment === 'errorHandler') {
    fragment = 'error-handler';
  }
}

can we just re-name the fragment back to the correct file name like the following?

Sorry, that does not make sense to me.

IMO, this issue needs more research. Why is the code building loopback.urlNotFound not working in Jest, when it seems to work for everybody else?

Yeah, the problem is the file is named url-not-found in node_modules (instead of urlNotFound), I copied-pasted and renamed urlNotFound the copy and it works. But edit the file in node_modules isn't a good solution.

Do you have a way to fix it ?

There is a new errorhandler in place so those problems will be fixed soon.

Should we wait for loopback 4??

There is a new errorhandler in place so those problems will be fixed soon.

Should we wait for loopback 4??

I am afraid that comment about a new error-handler was misleading. We do use strong-error-handler instead of errorhandler, but the urlNotFound middleware is still required to convert "no path found" situation into a javascript error for the error-handling middleware to handle.

But yes, this problem will go away in LoopBack 4, because it's an entirely new code base and we are not exporting any urlNotFound entity so far.

Yeah but, as you said, it's an entirely new code, so it's not a valid solution for the majority of us (I mean, the people in this issue).

In my case what I did was just add some hardcoded code to my test.js which copies these files to their expected locations if they not exist. Something like this:

~~~js
// Dirty trick to bypass the loopback-boot file naming issue...
const files = [
{
original: 'url-not-found',
desired: 'urlNotFound',
},
{
original: 'error-handler',
desired: 'errorHandler',
}
]

files.forEach((file) => {
const base = path.resolve('./node_modules/loopback/server/middleware')
const desired = ${base}/${file.desired}.js
if (!fs.existsSync(desired)) {
fs.copyFileSync(${base}/${file.original}.js, desired)
}
})
~~~

@elboletaire I feel your paint! Unfortunately we don't have bandwidth to investigate this issue ourselves.

My recommendation is to load your test setup in a debugger, set breakpoint to loopback-boot's compiler's method resolveMiddleware (see my earlier https://github.com/strongloop/loopback/issues/2201#issuecomment-290720446), and find out why the module resolver behaves differently in the test environment.

I have the same time than you. The dirty trick works, so I'm not gonna loose more time on it.

We'll see if loopback 4 fits our needs btw... because it's like a totally new framework... 😕

After a prolonged fight, this preset fixed all of the issues we were facing: https://github.com/negativetwelve/jest-preset-loopback

After a prolonged fight, this preset fixed all of the issues we were facing: https://github.com/negativetwelve/jest-preset-loopback

@PaddyMann This is awesome, thank you for figuring the solution and sharing it on GitHub. I'd love to give your Jest preset more publicity, could you perhaps send a pull request to add your project to our Community Projects section on loopback.io? See the instructions here. If you can come up with a better place where to tell Jest users how to configure it for LoopBack projects then I am happy to consider it too!

@bajtos I can't take credit for this — after a prolonged fight, I was lucky enough to stumble across the good work by @negativetwelve

Kudos to him!

This issue is the top search result when you hit the loopback/server/middleware/urlNotFound error (at least on the Strongloop site), so at least others should find it here in future.

Wow, glad my work could help someone! Thanks for pinging me @PaddyMann!

I'll submit a PR to the community projects section right now but if you have other places you think this should be outlined, I'm glad to submit it there as well

Thanks! you guys helped me a lot

I found configuring jest with testEnvironment: 'node' resolved the issue for me. Otherwise jest thinks it is running in a browser by default.

Was this page helpful?
0 / 5 - 0 ratings