Jest cannot find module 'got' from node_modules - node.js

I'm getting an error from one of my (previously working) tests when I run yarn jest:
Cannot find module 'got' from 'src/rss/queries.ts'
I've added got in package.json:
"devDependencies": {
"got": "^12.0.0",
}
My jest.config.js:
module.exports = {
preset: 'ts-jest',
testMatch: ['**/*.test.ts(|x)'],
collectCoverageFrom: ['**/*.ts', '!.webpack/**/*'],
verbose: true,
}
I'm using got in ./src/rss/queries.ts:
import * as got from 'got'
I've also tried:
import { got, RequestError } from 'got'
In both cases the application works - I can see got making requests via the application logs (and vscode is indicating the correct path to the module in node_modules when I hover over the above). So it's definitely there, and working.
But jest can't find it. Why? It's not an uncommon stackoverflow question, but they all seem to relate to importing custom local modules via relative paths, etc. I'm just trying to use one out of node_modules...

Version 12 of got doesn't work with jest. Best to use version 11 for now. See the details in the release notes at: https://github.com/sindresorhus/got/releases/tag/v12.0.0

Wasn't able to find a reason for, or solution to, this. Ended up swapping got for axios, which is a shame as I liked many got features.

Related

Mock zip.js lib to be able to use jest

So, I have a project that imports a package utils, and this package depends on '#zip.js/zip.js' lib. This lib is meant for browser usage and doesn't work on node.
The first weird thing is that, when I try to run jest, I get:
FAIL tests/index.test.ts
● Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
./node_modules/#zip.js/zip.js/index.js:29
import Deflate from "./lib/core/codecs/deflate.js";
^^^^^^
SyntaxError: Cannot use import statement outside a module
> 1 | import {
| ^
2 | Data64URIWriter,
3 | Entry,
4 | TextWriter,
at Runtime.createScriptFromCode (../../node_modules/jest-cli/node_modules/jest-runtime/build/index.js:1350:14)
at Object.<anonymous> (../utils/src/unzipFolder.ts:1:1)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 5.926 s
Which is totally misleading.
Anyway, now that I know that the problem is the usage of zip.js on node, I need to mock it so that jest doesn't break.
According to the docs for Manual mocks, here is what I did:
create a folder __mocks__ in the root folder (next to node_modules)
create a folder #zip.js inside it
create a file zip.js inside
It didn't work. So I tried the code we see in that doc and try to add jest.mock('#zip.js/zip.js') as first line in my test file, but to no avail.
I'm really not sure about how the mock system is actually working, so any help is really appreciated.
Edit:
I'll keep here the list of what was tried and failed:
using "type": "module" in package.json (same result)
All solutions from here and there (same result. Anyway, I'm convinced that the error message is just misleading)
I discovered the moduleNameMapper feature from jest. It totally solved my problem.
Here is my final jest.config.js file:
export default {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'#zip.js/zip.js': '<rootDir>/__mocks__/#zip.js/zip.js',
},
}
And here is what I have in <rootDir>/__mocks__/#zip.js/zip.js file:
module.exports = {}
Hope it helps someone!

Jest "Cannot find module" with typescript paths in CI

On the Gitlab-CI environment 2 of our Jest tests fail with Cannot find module.
The strange thing is that it works on my local Win10 machine - even when I run the tests in a similar docker-container (node 12.12.0).
Here is the console output:
FAIL apps/server/src/domain/dashboard/permission-group.service.spec.ts
Test suite failed to run
Cannot find module '#cm/utils-server' from 'license.service.ts'
9 | isLicenseFileContent,
10 | LicenseStatus,
> 11 | parseLicenseInfo
| ^
12 | } from '#cm/license-shared';
13 | import { ExitCode } from '../../util/exit-codes';
14 | import { readFile } from '#cm/utils-server';
at Resolver.resolveModule (../../node_modules/jest-resolve/build/index.js:259:17)
at Object.<anonymous> (src/domain/license/license.service.ts:11:24)
I am not sure how to correctly interpret this output:
permission-group.service.spec.ts: this is the test that fails
Cannot find module '#cm/utils-server' from 'license.service.ts':
Ok, the test or some of its dependencies, use license.service.ts and in the license.service.ts file the '#cm/utils-server' module cannot be found.
What is the meaning of error-indicator (> at parseLicenseInfo)?
This is for the import #cm/license-shared - not for #cm/utils-server as indicated by the error message in 2
#cm/utils-server is also imported, but 2 lines below in line 14: So is this maybe just a bug in jest?
I just had this issue and searched for some solutions. Found this site which gave a clue about what could be done: to configure Jest's moduleNameMapper property.
So, reading the documentation I found this solution:
Open the tsconfig.json and jest.config.js files (or equivalent)
In tsconfig.json, find your absolute paths definition. My configuration looks like this:
"paths": {
"#modules/*": ["modules/*"],
"#config/*": ["config/*"],
"#shared/*": ["shared/*"]
}
In the jest.config.json, find and uncomment the moduleNameMapper property and start to translate your TS absolute paths into the Jest mapper syntax. Sounds complicated, but it isn't:
moduleNameMapper: {
"#modules/(.*)": "<rootDir>/src/modules/$1",
"#config/(.*)": "<rootDir>/src/config/$1",
"#shared/(.*)": "<rootDir>/src/shared/$1",
}
The <rootDir> if defined automatically, and points to the package.json directory
"#modules/(.*)" is a Regex for "any string starting with '#module/' followed by anything after it
"<rootDir>/src/modules/$1" is the corresponding directory. $1 is a pointer to the Regex expression between the parenthesis ((.*)). Other expressions will be pointed by $2, $3 and so on
After doing this, I was able to execute my tests without any problem.
Console output before follow the above steps:
$ jest
FAIL src/modules/appointments/services/CreateAppointmentService.spec.ts
● Test suite failed to run
Cannot find module '...'
Console output after:
$ jest
PASS src/modules/appointments/services/CreateAppointmentService.spec.ts
Hope this help someone,
Thanks!
For those who are facing this issue in 2022. Please add this code in your
jest-unit.json (or your jest config json file).
"moduleDirectories": ["<rootDir>/../", "node_modules"]
Result:
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".\\.spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"moduleDirectories": ["<rootDir>/../", "node_modules"]
}
For now we use a workaround: we had paths defined in multiple tsconfig.json files of our mono-repo. We moved all paths up to the root-tsconfig and now the tests work again.
But we don't really understand why this works.
And a drawback is that it's now easy to accidentally refer to a path that you shouldn't use in the lib (because the IDE now always uses all paths for code-assistance)
I meet the same problem, I found the reason is the package(which cannot found) doesn't set the main field in package.json, add it then everythings ok.

How to import a node module inside an angular web worker?

I try to import a node module inside an Angular 8 web worker, but get an compile error 'Cannot find module'. Anyone know how to solve this?
I created a new worker inside my electron project with ng generate web-worker app, like described in the above mentioned ng documentation.
All works fine until i add some import like path or fs-extra e.g.:
/// <reference lib="webworker" />
import * as path from 'path';
addEventListener('message', ({ data }) => {
console.log(path.resolve('/'))
const response = `worker response to ${data}`;
postMessage(response);
});
This import works fine in any other ts component but inside the web worker i get a compile error with this message e.g.
Error: app/app.worker.ts:3:23 - error TS2307: Cannot find module 'path'.
How can i fix this? Maybe i need some additional parameter in the generated tsconfig.worker.json?
To reproduce the error, run:
$ git clone https://github.com/hoefling/stackoverflow-57774039
$ cd stackoverflow-57774039
$ yarn build
Or check out the project's build log on Travis.
Note:
1) I only found this as a similar problem, but the answer handles only custom modules.
2) I tested the same import with a minimal electron seed which uses web workers and it worked, but this example uses plain java script without angular.
1. TypeScript error
As you've noticed the first error is a TypeScript error. Looking at the tsconfig.worker.json I've found that it sets types to an empty array:
{
"compilerOptions": {
"types": [],
// ...
}
// ...
}
Specifying types turns off the automatic inclusion of #types packages. Which is a problem in this case because path has its type definitions in #types/node.
So let's fix that by explicitly adding node to the types array:
{
"compilerOptions": {
"types": [
"node"
],
// ...
}
// ...
}
This fixes the TypeScript error, however trying to build again we're greeted with a very similar error. This time from Webpack directly.
2. Webpack error
ERROR in ./src/app/app.worker.ts (./node_modules/worker-plugin/dist/loader.js!./src/app/app.worker.ts)
Module build failed (from ./node_modules/worker-plugin/dist/loader.js):
ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in './src/app'
To figure this one out we need to dig quite a lot deeper...
Why it works everywhere else
First it's important to understand why importing path works in all the other modules. Webpack has the concept of targets (web, node, etc). Webpack uses this target to decide which default options and plugins to use.
Ordinarily the target of a Angular application using #angular-devkit/build-angular:browser would be web. However in your case, the postinstall:electron script actually patches node_modules to change that:
postinstall.js (parts omitted for brevity)
const f_angular = 'node_modules/#angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
fs.readFile(f_angular, 'utf8', function (err, data) {
var result = data.replace(/target: "electron-renderer",/g, '');
var result = result.replace(/target: "web",/g, '');
var result = result.replace(/return \{/g, 'return {target: "electron-renderer",');
fs.writeFile(f_angular, result, 'utf8');
});
The target electron-renderer is treated by Webpack similarily to node. Especially interesting for us: It adds the NodeTargetPlugin by default.
What does that plugin do, you wonder? It adds all known built in Node.js modules as externals. When building the application, Webpack will not attempt to bundle externals. Instead they are resolved using require at runtime. This is what makes importing path work, even though it's not installed as a module known to Webpack.
Why it doesn't work for the worker
The worker is compiled separately using the WorkerPlugin. In their documentation they state:
By default, WorkerPlugin doesn't run any of your configured Webpack plugins when bundling worker code - this avoids running things like html-webpack-plugin twice. For cases where it's necessary to apply a plugin to Worker code, use the plugins option.
Looking at the usage of WorkerPlugin deep within #angular-devkit we see the following:
#angular-devkit/src/angular-cli-files/models/webpack-configs/worker.js (simplified)
new WorkerPlugin({
globalObject: false,
plugins: [
getTypescriptWorkerPlugin(wco, workerTsConfigPath)
],
})
As we can see it uses the plugins option, but only for a single plugin which is responsible for the TypeScript compilation. This way the default plugins, configured by Webpack, including NodeTargetPlugin get lost and are not used for the worker.
Solution
To fix this we have to modify the Webpack config. And to do that we'll use #angular-builders/custom-webpack. Go ahead and install that package.
Next, open angular.json and update projects > angular-electron > architect > build:
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
// existing options
}
}
Repeat the same for serve.
Now, create extra-webpack.config.js in the same directory as angular.json:
const WorkerPlugin = require('worker-plugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
module.exports = (config, options) => {
let workerPlugin = config.plugins.find(p => p instanceof WorkerPlugin);
if (workerPlugin) {
workerPlugin.options.plugins.push(new NodeTargetPlugin());
}
return config;
};
The file exports a function which will be called by #angular-builders/custom-webpack with the existing Webpack config object. We can then search all plugins for an instance of the WorkerPlugin and patch its options adding the NodeTargetPlugin.

React Developer Tools Shows "Waiting for roots to load..."

I've just switched to Preact 8.4.2 and would like to get the React Developer Tools to work as well. In my webpack.config.js, I've added:
alias: {
react: 'preact-compat',
'react-dom': 'preact-compat'
}
In my entry .js file, I've added:
require('preact/debug');
After adding these, I was getting an error when attempting to build:
Module parse failed: /myProject/node_modules/preact/src/preact.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| import { h, h as createElement } from './h';
| import { cloneElement } from './clone-element';
| import { Component } from './component';
# ./~/preact/debug.js 6:14-31
I only had .jsx files loading with babel-loader (not .js), so I added an additional entry in my webpack.config.js file:
{
test: /\.js$/,
include: /node_modules\/preact/,
loader: 'babel-loader'
},
After adding this entry, I'm able to build without issues, but my React Developer Tools just shows:
Waiting for roots to load...
to reload the inspector [click here]
Something is either up with your preact app or your webpack config. I just solved a similar problem.
First step, check if its your preact. If you have no console errors, drop your preact into this working boilerplate (you'll have to do a little rewiring to get it working) https://github.com/developit/preact-boilerplate
If after firing it up with your code, Devtools works as expected, then there is something wrong with your build. In that case it turns into a game of line by line updating your (mostly) working build to match preact-boilerplate.
In my case, I had included "src" in my webpack resolve. This threw no errors in terminal/console, and the build worked perfectly otherwise. Once I found it, devtools started working.

Unexpected token import - using react and node

I'm getting an error when running my react app: Uncaught SyntaxError: Unexpected token import
I know that there are a plethora of similar issues on here, but I think mine is a little different. First of all, here is the repository, since I'm not sure where exactly the error is: repo
I'm using create-react-app, and in a seperate backend directory I'm using babel (with a .babelrc file containing the preset es2015). The app worked fine until I added another file in a new directory in the backend folder (/backend/shared/validations/signup.js).
I was using es6 before that too, and it was working perfectly fine. First I thought it was some problem with windows, but I cloned the repo on my Ubuntu laptop and I'm getting the same error there.
Some things I tried already:
Move the entire folder from /backend to the root folder
Move just the file (signup.js) just about everywhere
So no matter where the file is, the error stays the same. If I remove the entire file and all references to it the app works again.
I think this error is pretty weird, considering I'm using es6 everywhere else in the app without trouble. It would be great if anyone could help me with this error.
edit: If you want to test this on your own machine just clone the repo and run npm start in the root folder (and also npm start in the backend folder, but that isn't required for the app to run, or for the error to show up).
That's what's happening:
Your webpack is set to run babel loader only in the src folder (include directive).
To change that, one approach is:
1) extract webpack configuration with npm run eject (don't know if there is another way to override settings in react-create-app). From the docs:
Running npm run eject copies all the configuration files and the
transitive dependencies (Webpack, Babel, ESLint, etc) right into your
project so you have full control over them.
2) in config/paths.js, add an appShared key, like that:
module.exports = {
/* ... */
appSrc: resolveApp('src'),
appShared: resolveApp('backend/shared'),
/* ... */
};
3) in config/webpack.config.dev.js, add the path to the babel loader, like that:
{
test: /\.(js|jsx)$/,
include: [ paths.appSrc, paths.appShared ],
loader: 'babel',
/* ... */
},
It works now!

Resources