jest says cannot import outside a module - javascript

I'm attempting make a few functions using the Test Driven Development (TDD)
I am writing in javascript.
checkTransparency(urlString)
maketransparent(urlString)
are two functions of mine I'm trying to test and develop which is located in a file called transcript.js.
These uses the inkscape and graphicsmagick npm. I checked checkTransparent works in some other project of mine, but I'm trying to make sure I can just copy paste this transparent.js into another project and use it elsewhere as well.
My folder structure of the project are the following :
+ node_modules
+ src
--- transparent.js
+ test
--- transparent.spec.js
+ package.json
+ package-lock.json
+ jest.config.js
I am using jest as my test framework.
The problem is when I run jest (or npm test)
I get the following:
FAIL test/transparent.spec.js
● 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:
• 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:
\\..............\transparent\test\transparent.spec.js:4 <FEW DETAILS OMITTED HERE DELIBERATELY>
import { checkTransparency, makeTransparent } from "../src/transparent"; // const transparent = require("../src/transparent");
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Runtime._execModule (C:/Users/Kjeong/AppData/Local/Yarn/Data/global/node_modules/jest-runtime/build/index.js:988:58)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.862s
Ran all test suites.
my jest.config.js:
module.exports = {
testEnvironment: "node",
moduleDirectories: ["node_modules", "src", "transparent"],
moduleFileExtensions: [
"js",
"json",
"jsx",
"ts",
"tsx",
"node"
],
clearMocks: true,
}
I've tried the following exports to get this thing working:
export function checkTransparency(urlString) { ... }
export function makeTransparent(urlString) {... }
module.exports = {
checkTransparency: checkTransparency,
makeTransparent: makeTransparent,
};

In your package.json, using configuration like following could solve your problem:
{
"name": "<blah blah>",
"version": "1.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "node server.js",
"test": "node --experimental-vm-modules node_modules/.bin/jest"
},
}

If you really want to use import keyword then you probably need to follow these explanations. Otherwise why not just require ?
const { checkTransparency, makeTransparent } = require('../src/transparent')
Hope this helps :)

Related

Jest command not recognized

So i just started learning about Test Driven Developement and as an example i was asked to run the command npm test helloWorld.spec.js in the terminal but i got this error :
> javascript-exercises#1.0.0 test
> jest "helloWorld.spec.js"
'jest' n’est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
// in english jest isn't recognized as an internal command or external
I'm working on windows and the only thing i have installed is node so what do i have to do?
Choose one of the following methods
1) Install globally
You need to install jest globally:
npm install jest -g
Note: You will have to call it as jest something.spec.js in your cli or specify a test command in your package.json.
2) Install locally
Install jest locally with npm install jest -D.
You can use a script in your package.json called test which would be "test": "jest".
If any of the above don't work, try reinstalling jest.
If it still doesn't work, try removing node_modules and npm cache clean --force and npm install
3) Config file
If you already have jest installed but it's not working, you can use a config file to track files based on regex pattern (you can do a lot more if you check out the docs).
The following part is from the docs:
Jest's configuration can be defined in the package.json file of your project, or through a jest.config.js, or jest.config.ts file or through the --config <path/to/file.js|ts|cjs|mjs|json> option. If you'd like to use your package.json to store Jest's config, the "jest" key should be used on the top level so Jest will know how to find your settings:
{
"name": "my-project",
"jest": {
"verbose": true
}
}
Or through JavaScript:
// Sync object
/** #type {import('#jest/types').Config.InitialOptions} */
const config = {
verbose: true,
};
module.exports = config;
// Or async function
module.exports = async () => {
return {
verbose: true,
};
};
Or through TypeScript (if ts-node is installed):
import type {Config} from '#jest/types';
// Sync object
const config: Config.InitialOptions = {
verbose: true,
};
export default config;
// Or async function
export default async (): Promise<Config.InitialOptions> => {
return {
verbose: true,
};
};
When using the --config option, the JSON file must not contain a "jest" key:
{
"bail": 1,
"verbose": true
}
Regex options
testMatch [array]
(default: [ "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ])
The glob patterns Jest uses to detect test files. By default it looks for .js, .jsx, .ts and .tsx files inside of __tests__ folders, as well as any files with a suffix of .test or .spec (e.g. Component.test.js or Component.spec.js). It will also find files called test.js or spec.js.
Note: Each glob pattern is applied in the order they are specified in the config. (For example ["!**/__fixtures__/**", "**/__tests__/**/*.js"] will not exclude __fixtures__ because the negation is overwritten with the second pattern. In order to make the negated glob work in this example it has to come after **/__tests__/**/*.js.)
testRegex [string | array]
Default: (/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$
The pattern or patterns Jest uses to detect test files. By default it looks for .js, .jsx, .ts and .tsx files inside of \_\_tests\_\_ folders, as well as any files with a suffix of .test or .spec (e.g. Component.test.js or Component.spec.js). It will also find files called test.js or spec.js. See also testMatch [array], but note that you cannot specify both options.

Configure jest with latest version of d3-path

For some reason, my jest configuration doesn't work with the latest version of d3-path#3.0.1. It worked fine with version 2.0.0. I guess it has something to do with d3-path switching to ESM, but I was already using ES6 in my own code, so I don't get why it suddenly doesn't work anymore. I have the following packages installed:
"dependencies": {
"d3-path": "^3.0.1"
},
"devDependencies": {
"#babel/core": "^7.15.8",
"#babel/preset-env": "^7.15.8",
"babel-jest": "^27.3.1",
"jest": "^27.3.1"
}
My babel.config.js:
module.exports = {
presets: [['#babel/preset-env', {targets: {node: 'current'}}]],
};
My index.js:
import { path } from 'd3-path'
export default () => path()
The test file:
import fn from '../src/index.js'
describe('test', () => {
it('works', () => {
fn()
expect(2 + 2).toBe(4)
})
})
The error message:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){export {default as path} from "./path.js";
^^^^^^
SyntaxError: Unexpected token 'export'
> 1 | import { path } from 'd3-path'
To reproduce:
git clone https://github.com/luucvanderzee/jest-problem.git
cd jest-problem
npm i
npm run test
// The test runs without failure- this is because we're currently still using d3-path#2.0.0
npm uninstall d3-path && npm install d3-path // (upgrade to d3-path#3.0.1)
npm run test
// Now the test fails.
How should I configure jest and/or babel to solve this issue?
EDIT:
I already tried the following (from this page of the jest docs):
Creating a jest.config.js file with the following:
module.exports = {
transform: {}
}
Changing my "test" command from "jest" to "node --experimental-vm-modules node_modules/jest/bin/jest.js"
This gives me another error:
/home/luuc/Projects/javascript/jest-problem/test/test.test.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import fn from '../src/index.js'
^^^^^^
SyntaxError: Cannot use import statement outside a module
I also don't get what is meant by
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
Isn't the problem that the module is not transformed? Would adding an ignore pattern not just lead to the module not getting transformed?
Problem
The error happens because jest does not send the content of node_modules to be transformed by babel by default.
The following output line of npm run test indicates one way to solve the problem:
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
Solution
The configuration of jest should be updated in order to instruct it to transform the ESM code present in d3-path dependency.
To do so, add the following to a jest.config.js file in the root directory of the project:
module.exports = {
transformIgnorePatterns: ['node_modules/(?!(d3-path)/)']
}
npm run test runs fine after that.
The transformIgnorePatterns option is documented here.
Edit - including more modules
In order to include all modules starting with d3, the following syntax may be used:
transformIgnorePatterns: ['/node_modules/(?!(d3.*)/)']
TLDR;
transformIgnorePatterns: [
"/node_modules/(?!d3|d3-array|d3-axis|d3-brush|d3-chord|d3-color|d3-contour|d3-delaunay|d3-dispatch|d3-drag|d3-dsv|d3-ease|d3-fetch|d3-force|d3-format|d3-geo|d3-hierarchy|d3-interpolate|d3-path|d3-polygon|d3-quadtree|d3-random|d3-scale|d3-scale-chromatic|d3-selection|d3-shape|d3-time|d3-time-format|d3-timer|d3-transition|d3-zoom}|internmap|d3-delaunay|delaunator|robust-predicates)"
]
For the ones reaching this page after updating recharts dependency, here I found the solution, provided by them.

ava + ts-node converting .spec.ts files into .ts

I am running ava with ts-node with the following config:
"ava": {
"files": [
"tests/**/*",
"!test/exclude-files-in-this-directory",
"!**/exclude-files-with-this-name.*"
],
"failFast": true,
"failWithoutAssertions": false,
"extensions": [
"spec.ts",
"ts"
],
"environmentVariables": {
"NODE_ENV": "test"
},
"require": [
"ts-node/register",
"tsconfig-paths/register"
],
"tap": false,
"verbose": true
}
The problem is that .spec.ts files don't get recognized, as ts-node is doing some kind of conversion (I think) of the .spec.ts files into just .ts, which means that the extension with spec.ts is never matched.
Here's the output of the tests
- graphql › stage-2 › workspace.ts › do later
✔ general › functions.ts › returns proper difference
The files are named workspace.spec.ts and functions.spec.ts
Is there anyway for ts-node to not drop the spec part?
ts-node should only kick in when AVA requires the test file. I can't immediately spot why this isn't working. Are those spec.ts files inside the tests directory?
P.S. NODE_ENV already defaults to test, and you don't need to disable tap either.

Compiling React projects in MonoRepo failing

I'm trying to setup yarn workspaces with my docker instance. This is my directory structure:
/monorepo/
/node_modules/
#libs/common
#services/common
#services/project-A
...OTHER DEPS...
package.json
/services/
/common/
index.jsx
package.json
/project-A/
webpack.base.config.js
**REACT project with babel, webpack, etc**
/libs/
/tools/
/common/
index.jsx
package.json
To simplify my docker setup I just configured this volume within my docker compose that maps the entire monorepo directory:
volumes:
- '../../../monorepo:/monorepo'
From there in my Project-A I import #libs/common and #services/common. This works fine when the common libraries are exporting simple functions like:
export const Add = (a,b) => a+b
Webpack has no issue resolving this and building Project-A.
However when I try to import a component from one of the common libraries like this:
/libs/tools/common:
import React from 'react'
export MySharedComponent = () => <>HELLLO</>
I get an error in the build process:
Error: Cannot find module '/monorepo/libs/tools/common/webpack.base.config.js'
Require stack:
- /monorepo/node_modules/eslint-import-resolver-webpack/index.js
- /monorepo/node_modules/eslint-module-utils/resolve.js
- /monorepo/node_modules/eslint-plugin-import/lib/rules/no-unresolved.js
- /monorepo/node_modules/eslint-plugin-import/lib/index.js
The eslint file under Project-A:
{
"parser": "babel-eslint",
"env": {
"browser": true,
"node": true,
"jest": true,
"cypress/globals": true
},
"settings": {
"import/resolver": {
"webpack": {
"config": "webpack.base.config.js"
}
}
}
}
The babel.rc under Project-A
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"#babel/preset-react",
"#babel/preset-flow"
],
"env": {
"test": {
"plugins": [
[
"babel-plugin-webpack-alias",
{
"config": "./webpack.base.config.js"
}
]
]
}
}
}
My Question:
Is the main issue that there's no webpack config set up in the common repositories. Therefore the workspace does not know how to compile my shared resources?
Should there only be 1 webpack build config in my workspace used by all projects within the workspace? Currently I only have 1 config under Project-A?
What happens if I have specific webpack needs per project, does 1 config (if that's the answer) make sense?
1) First, there is a line in your code that you are referring to webpack.base.config.js in both babelrc and eslint,
so if that file does not exist, this error that says module not found makes sense.
2) Second: if you build and use your repositories in the same situation and environment, yes you can have one config for both but you might need environment setup (Development, Production) for your config.
But if you really want to make your dependencies and configs apart, webpack support multiple entries for your project which you can check that out.

How Should VSCode Be Configured To Support A Lerna Monorepo?

I have a lerna monorepo containing lots of packages.
I'm trying to achieve the following:
Ensure that VSCode provides the correct import suggestions (based on package names, not on relative paths) from one package to another.
Ensure that I can 'Open Definition' of one of these imports and be taken to the src of that file.
For 1. I mean that if I am navigating code within package-a and I start to type a function exported by package-b, I get a suggestion that will trigger the adding of an import: `import { example } from 'package-b'.
For 2. I mean that if I alt/click on the name of a function exported by 'package-b' while navigating the file from a different package that has imported it, I am taken to '/packages/namespace/package/b/src/file-that-contains-function.js',
My (lerna) monorepo is structured as standard, for example here is a 'components' package that is published as #namespace/components.
- packages
- components
- package.json
- node_modules
- src
- index.js
- components
- Button
- index.js
- Button.js
- es
- index.js
- components
- Button
- index.js
- Button.js
Note that each component is represented by a directory so that it can contain other components if necessary. In this example, packages/components/index exports Button as a named export. Files are transpiled to the package's /es/ directory.
By default, VSCode provides autosuggestions for imports, but it is confused by this structure and, for if a different package in the monorepo needs to use Button for example, will autosuggest all of the following import paths:
packages/components/src/index.js
packages/components/src/Button/index.js
packages/components/src/Button/Button.js
packages/components/es/index.js
packages/components/es/Button/index.js
packages/components/es/Button/Button.js
However none of these are the appropriate, because they will be rendered as relative paths from the importing file to the imported file. In this case, the following import is the correct import:
import { Button } from '#namespace/components'
Adding excludes to the project's jsconfig.json has no effect on the suggested paths, and doesn't even remove the suggestions at /es/*:
{
"compilerOptions": {
"target": "es6",
},
"exclude": [
"**/dist/*",
"**/coverage/*",
"**/lib/*",
"**/public/*",
"**/es/*"
]
}
Explicitly adding paths using the "compilerOptions" also fails to set up the correct relationship between the files:
{
"compilerOptions": {
"target": "es6",
"baseUrl": ".",
"paths": {
"#namespace/components/*": [
"./packages/namespace-components/src/*.js"
]
}
},
}
At present Cmd/Clicking on an import from a different package fails to open anything (no definition is found).
How should I configure VSCode so that:
VSCode autosuggests imports from other packages in the monorepo using the namespaced package as the import value.
Using 'Open Definition' takes me to the src of that file.
As requested, I have a single babel config in the root:
const { extendBabelConfig } = require(`./packages/example/src`)
const config = extendBabelConfig({
// Allow local .babelrc.js files to be loaded first as overrides
babelrcRoots: [`packages/*`],
})
module.exports = config
Which extends:
const presets = [
[
`#babel/preset-env`,
{
loose: true,
modules: false,
useBuiltIns: `entry`,
shippedProposals: true,
targets: {
browsers: [`>0.25%`, `not dead`],
},
},
],
[
`#babel/preset-react`,
{
useBuiltIns: true,
modules: false,
pragma: `React.createElement`,
},
],
]
const plugins = [
`#babel/plugin-transform-object-assign`,
[
`babel-plugin-styled-components`,
{
displayName: true,
},
],
[
`#babel/plugin-proposal-class-properties`,
{
loose: true,
},
],
`#babel/plugin-syntax-dynamic-import`,
[
`#babel/plugin-transform-runtime`,
{
helpers: true,
regenerator: true,
},
],
]
// By default we build without transpiling modules so that Webpack can perform
// tree shaking. However Jest cannot handle ES6 imports becuase it runs on
// babel, so we need to transpile imports when running with jest.
if (process.env.UNDER_TEST === `1`) {
// eslint-disable-next-line no-console
console.log(`Running under test, so transpiling imports`)
plugins.push(`#babel/plugin-transform-modules-commonjs`)
}
const config = {
presets,
plugins,
}
module.exports = config
In your case, I would make use of lerna in combination with yarn workspaces.
When running yarn install, all your packages are linked under your #namespace in a global node_modules folder. With that, you get IntelliSense.
I've set up an example repository here: https://github.com/flolude/stackoverflow-lerna-monorepo-vscode-intellisense
You just need to add "useWorkspaces": "true" to your lerna.json
lerna.json
{
"packages": ["packages/*"],
"version": "0.0.0",
"useWorkspaces": "true"
}
And the rest is just propper naming:
global package.json
{
"name": "namespace",
// ...
}
package.json of your component package
{
"name": "#namespace/components",
"main": "src/index.js",
// ...
}
package.json of the package that imports the components
{
"name": "#namespace/components",
"main": "src/index.js",
"dependencies": {
"#namespace/components":"0.0.0"
}
// ...
}
Then you can do the following:
import { Component1 } from '#namespace/components';
// your logic
Automatically Importing from #namespace
Unfortunately, I couldn't find a way to make this work in VSCode with a Javascript Monorepo. But there are some things you can do:
Use Typescript (tutorial, other tutorial)
Use module-alias
Add import {} from '#namespace/components' to the top of your file
Use Auto Import Extension
Edit: This is broken with the latest version of VSCode.
I finally managed to get this working reliably. You need to create a separate jsconfig.js for every package in your monorepo, for example:
{monorepo root}/packages/some-package/jsconfig.json:
{
"compilerOptions": {
"target": "es6",
"jsx": "preserve",
"module": "commonjs"
},
"include": ["src/**/*.js"],
"exclude": ["src/index.js"]
}
Note that I've excluded the src/index.js file so it doesn't get offered as an import suggestion from within that package.
This setup appears to achieve:
Intellisense import suggestions from packages instead of using relative paths.
Go to definition to source of other packages in the monorepo.
VSCode has been pretty flaky of late, but it seems to be working.
Note this is working for a JavaScript-only monorepo (not Typescript).

Categories

Resources