storyshots error - Could not locate module ./src/common mapped as - reactjs

I have just installed #storybook/addon-storyshots and followed their instruction to put it at the root.
src/Storyshots.test.ts
import initStoryshots from '#storybook/addon-storyshots';
initStoryshots();
When I run tests, all my existing tests pass but it fails on this file - StoryShots.test.ts with error:
Error:
FAIL src/Storyshots.test.ts
Test suite failed to run
Configuration error:
Could not locate module ./src/common mapped as:
C:\apps\vanilla\storybook-examples\src\$1.
Please check your configuration for these entries:
{
"moduleNameMapper": {
"/src\/(.*)/": "C:\apps\vanilla\storybook-examples\src\$1"
},
"resolver": undefined
}
at createNoMappedModuleFoundError (node_modules/jest-resolve/build/index.js:552:17)
at Object.<anonymous> (node_modules/shelljs/shell.js:9:14)
I do have module resolution going on in my project and everything works there. See example module resolution for my project:
tsconfig.json
{
...
"compilerOptions": {
"baseUrl": "./",
},
"include": [
"src/**/*", "#types", "stories"
]
}
.babelrc
{
"plugins": [
...
["module-resolver", {
"extensions": [".js", ".jsx", ".ts", ".tsx"],
"root": ["./"],
"alias": {
"src": "./src"
}
}]
]
}
webpack.config.dev.js
const src = path.join(__dirname, '/src');
module.exports = {
...
resolve: {
modules: [src, 'node_modules'],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss'],
// fix module resolver for typescript !!!
alias: {
src
}
},
I just haven't set any of these in .storybook folder - .storybook/. I'm not sure how storybook resolution works or why its looking for common/ folder. I have no common folder.
This is an example of one of my stories:
Basic.stories.tsx
import React from 'react';
import Basic from 'src/Components/Basic/Basic';
export const BasicHelloWorld = () => <Basic {...{ title: 'hello world' }} />;
export default { title: 'Basic' };
This is my storybook main.js
main.js
module.exports = {
stories: ['../**/*.stories.tsx', '../**/**/*.stories.tsx'],
addons: [
'#storybook/addon-actions',
'#storybook/addon-links',
]
};
Appreciate any suggestions. Thanks

It turns out the one thing I didn't include in my configs above was my jest.config.js file.
It turns out the following was causing this problem:
jest.config.js ! broken
moduleNameMapper: {
'src/(.*)': '<rootDir>/src/$1',
...
},
Today I decided to strip everything down, and in the process came across ts-jest config examples where the regex had an exact path, ie started with ^ and ended with $, ie not a wild match.
https://kulshekhar.github.io/ts-jest/user/config/
Not that I thought much of it or why it would break storyshots only and nothing else but anything around file matching and resolutions I thought was worth ensuring accuracy. I updated my regex to match the paths above and BINGO - NO MORE ERROR !!! HAHAH. A nice stroke of luck.
jest.config.js £ fixed
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1'
...
},

Related

TS Config nested alias for absolute path not working

I'm trying to set up path aliases in my tsconfig.json for a React app bundled with Vite. Here is the relevant part of my tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
...
"paths": {
"*": ["src/*", "node_modules/*"],
"components/*": ["src/components/*"],
"containers/*": ["src/containers/*"],
"pages/*": ["src/constants/*"],
"store/*": ["src/store/*"],
"types/*": ["src/types/*"],
"NestedFolder/*": [
"src/components/NestedFolder/*"
],
}
},
"include": ["src/**/*", "*"]
}
The only issue is with the NestedFolder. When I import this way, everything works:
import { ComponentName } from "components/NestedFolder/types";
However, the nested alias fails:
import { ComponentName } from "NestedFolder/types";
// error
EslintPluginImportResolveError: typescript with invalid interface loaded as resolver
Occurred while linting .../src/components/NestedFolder/canvas/index.ts:1
Rule: "import/namespace"
// error on hover in VS Code
Unable to resolve path to module 'NestedFolder/types'.eslintimport/no-unresolved
I would like to do nested components because I have several folders that are nested 3-4 levels and it would be nice to have a cleaner view of my imports. Is there a way to do this?
You need to install the vite-tsconfig-paths plugin to set up path aliases using TypeScript and Vite.
If nothing changes and you are using VSCode make sure to restart the TypeScript server by pressing Ctrl+Shift+P or Cmd+Shift+P, typing restart, and then selecting the command: TypeScript: Restart TS server
The accepted answer did not work for me. I found that I had to install the following packages:
npm i eslint-plugin-import eslint-import-resolver-alias eslint-import-resolver-typescript
And then add the following configurations, with the important ingredient being strongly-defined alias paths:
const path = require('path');
module.exports = {
root: true, // important to ensure nested eslint scoping in monorepos
plugins: ['#typescript-eslint', 'import'],
extends: [
'airbnb-typescript-prettier',
'plugin:import/typescript'
],
parser: '#typescript-eslint/parser',
parserOptions: {
project: path.join(__dirname, './tsconfig.json'),
tsconfigRootDir: './src',
},
settings: {
"import/parsers": { // add this definition
"#typescript-eslint/parser": [".ts", ".tsx"],
},
'import/resolver': {
alias: {
map: [
// define each alias here
['components', path.join(__dirname, './src/components')],
],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
},
typescript: {
project: path.join(__dirname, './tsconfig.json'),
},
},
},
}
I think this could be improved on by harmonizing the aliases between the .eslintrc and vite.config so aliases only need to be defined once, using a tactic like the one defined here: https://stackoverflow.com/a/68908814/14198287
if vite-tsconfig-paths is not working for you. Make sure you didn't install v4.0.0. That version has a bug.
v4.0.1 fix it.
Install with the following:
npm install vite-tsconfig-paths#latest
Should install v4.0.1 at least.
I think this could be improved on by harmonizing the aliases between the .eslintrc and vite.config so aliases only need to be defined once, using a tactic like the one defined here: https://stackoverflow.com/a/68908814/14198287

Cannot find module error while import using jest in next.js

I am trying to configure Jest in my Next.js project. In my test file, I have imported my component like import { HamburgerMenu } from './HamburgerMenu.jsx'. In that component, there are so many other imports. Once of them is
import {
checkValidEmail, getNumbers, getFormttedPhoneNo, validateSubscription,
} from 'helpers/utils';
When I run tests, it gives me the following error (which is on above import statement):
Cannot find module 'helpers/utils' from 'components/common/Smart/HamburgerMenu/HamburgerMenu.jsx'
So here are the details.
jest.config.js (at root dir)
module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testPathIgnorePatterns: ['/node_modules/', '/.next/'],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': '<rootDir>/node_modules/babel-jest'
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
moduleNameMapper: {
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
},
}
I have added jest: true in the ESLint file.
babel.config.js file (at root dir):
module.exports = {
presets: ["next/babel"],
plugins: [["babel-plugin-styled-components", { ssr: true }]]
};
You can try to add
...
moduleDirectories: ['node_modules', '.'],
...
to your jest.config.js

Storybook Can't Find Components in React, Next.JS, Typescript Project

I have storybook setup with my next.js, typescript and react project. The project renders fine but storybook breaks and give me the me error: "Module not found: Error: Can't resolve 'components/atoms' in...." It seems like the path to components is causing it to break:
import { Element } from 'components/atoms';
but the following works:
import { Element } from '../../atoms
I have a tsconfig.json file with the following:
"compilerOptions": {
"baseUrl": "src",
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
],
...
I tried some of the suggestions online but none seems to resolve the path issue. I created a webpack.config.js in my .storybook folder with the following, but still get errors.
module.exports = {
...
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules']
}
};
I would like to not use the ../../ when calling files and just be able to use the ./components structure.
Spent some time fighting with Storybook )
Here is my .storybook/main.js version, that finally worked:
const path = require("path");
module.exports = {
webpackFinal: async (config, { configType }) => {
config.resolve.modules.push(path.resolve(__dirname, '../src'));
return config;
},
stories: [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
addons: [
"#storybook/addon-links",
"#storybook/addon-essentials",
"#storybook/preset-create-react-app"
]
}
For someone who is still looking for a solution, try adding the below inside your webpackFinal before returning config. It is because storybook isn't configured to access files using absolute paths.
config.resolve.modules = [...(config.resolve.modules || []), path.resolve('./')]
I was having an issue resolving aliases
Error: Can't resolve '#foo/bar'
In root > .storybook/main.js I added the property config.resolve.alias
const path = require('path');
module.exports = {
stories: ['../libs/feature/src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
],
framework: '#storybook/react',
webpackFinal: async (config, { configType }) => {
config.resolve.alias = {
...config.resolve.alias,
'#foo/bar': path.resolve(__dirname, '../libs/bar/src/'),
};
return config;
},
};
I think what you need is path aliases.
If you're working on a typescript project, you can declare aliases that map to a certain absolute path in your application using tsconfig.json paths compiler option:
"baseUrl": "./src",
"paths": {
"components/*": ["components/*"],
"#/common/*": ["common/*"],
}
Official link => typescriptlang.org
Here you have a good explanation about this typescript feature.
Path aliases with TypeScript in Node.js
Be aware that is not always that easy because in production your build toolchain will have to translate them to the correct paths as tsc doesn’t do it.
Fortunately nexjts has added this feature recently => https://nextjs.org/docs/advanced-features/module-path-aliases

Persuading webpack to use node_modules/#types

I'm trying to get to grips with using Typescript 2, Webpack and Angular 1.5, but when building Webpack keeps complaining that it:
Cannot resolve module '#types/angular' in C:\play\gt\src
I'm stumped. Been Googling this and messing about but am getting nowhere.
My app.ts looks like:
import * as angular from "#types/angular";
let app = angular.module ("GT.module", []);
My tsconfig looks like:
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"typeRoots" : [
"node_modules/#types"
]
},
"exclude": [
"node_modules",
"**/*.spec.ts"
],
"include" : [
"src/**/*"
]
}
...and lastly webpack config:
module.exports = {
entry: './src/app.ts',
output: {
filename: './dist/app.js'
},
devtool: "source-map",
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'],
modulesDirectories: ["node_modules"]
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' }
]
}
}
What is your directory tree looks like?
It should look like this:
node_modules/
#types/
angular/
src/
tsconfig.json
webpack.config.js
Then you don't need "typeRoots" : ["node_modules/#types"]
and import * as angular from "#types/angular"; should became import * as angular from "angular";
The Typescript compiler 2.0 will know where to look to find the typings at the right places (ie: in node_modules/#types)
#types are not modules you can import, they are typedefs for the compiler to reference.
The #types/angular package does not actually implement .module and your code will break (if it ever compiles).
You probably want to do something more like:
/// <reference path="../node_modules/#types/angular/index.d.ts" />
import * as angular from "angular";
let app = angular.module ("GT.module", []);
But, you typically won't even need the reference, as the compiler will automatically include typedefs from #types/* packages unless you tell it not to (by setting types or typeRoot in your tsconfig.json). This behavior was added in v2 and is fairly recent.

SyntaxError with Jest and React and importing CSS files

I am trying to get my first Jest Test to pass with React and Babel.
I am getting the following error:
SyntaxError: /Users/manueldupont/test/avid-sibelius-publishing-viewer/src/components/TransportButton/TransportButton.less: Unexpected token
> 7 | #import '../variables.css';
| ^
My package.json config for jest look like this:
"babel": {
"presets": [
"es2015",
"react"
],
"plugins": [
"syntax-class-properties",
"transform-class-properties"
]
},
"jest": {
"moduleNameMapper": {
"^image![a-zA-Z0-9$_-]+$": "GlobalImageStub",
"^[./a-zA-Z0-9$_-]+\\.png$": "RelativeImageStub"
},
"testPathIgnorePatterns": [
"/node_modules/"
],
"collectCoverage": true,
"verbose": true,
"modulePathIgnorePatterns": [
"rpmbuild"
],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react/",
"<rootDir>/node_modules/react-dom/",
"<rootDir>/node_modules/react-addons-test-utils/",
"<rootDir>/node_modules/fbjs",
"<rootDir>/node_modules/core-js"
]
},
So what am I missing?
moduleNameMapper is the setting that tells Jest how to interpret files with different extension. You need to tell it how to handle Less files.
Create a file like this in your project (you can use a different name or path if you’d like):
config/CSSStub.js
module.exports = {};
This stub is the module we will tell Jest to use instead of CSS or Less files. Then change moduleNameMapper setting and add this line to its object to use it:
'^.+\\.(css|less)$': '<rootDir>/config/CSSStub.js'
Now Jest will treat any CSS or Less file as a module exporting an empty object. You can do something else too—for example, if you use CSS Modules, you can use a Proxy so every import returns the imported property name.
Read more in this guide.
I solved this by using the moduleNameMapper key in the jest configurations in the package.json file
{
"jest":{
"moduleNameMapper":{
"\\.(css|less|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
"\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js"
}
}
}
After this you will need to create the two files as described below
__mocks__/styleMock.js
module.exports = {};
__mocks__/fileMock.js
module.exports = 'test-file-stub';
If you are using CSS Modules then it's better to mock a proxy to enable className lookups.
hence your configurations will change to:
{
"jest":{
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
},
}
}
But you will need to install identity-obj-proxy package as a dev dependancy i.e.
yarn add identity-obj-proxy -D
For more information. You can refer to the jest docs
UPDATE who use create-react-app from feb 2018.
You cannot override the moduleNameMapper in package.json but in jest.config.js it works, unfortunately i havent found any docs about this why it does.
So my jest.config.js look like this:
module.exports = {
...,
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(scss|sass|css)$": "identity-obj-proxy"
}
}
and it skips scss files and #import quite well.
Backing my answer i followed jest webpack
Similar situation, installing identity-object-proxy and adding it to my jest config for CSS is what worked for me.
//jest.config.js
module.exports = {
moduleNameMapper: {
"\\.(css|sass)$": "identity-obj-proxy",
},
};
The specific error I was seeing:
Jest encountered an unexpected token
/Users/foo/projects/crepl/components/atoms/button/styles.css:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.button { }
^
SyntaxError: Unexpected token .
1 | import React from 'react';
> 2 | import styles from './styles.css';
If you're using ts-jest, none of the solutions above will work! You'll need to mock transform.
jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
roots: [
"<rootDir>/src"
],
transform: {
".(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/jest-config/file-mock.js",
'.(css|less)$': '<rootDir>/jest-config/style-mock.js'
},
};
file-mock.js
module.exports = {
process() {
return `module.exports = 'test-file-stub'`;
},
};
style-mock.js
module.exports = {
process() {
return 'module.exports = {};';
}
};
I found this working example if you want more details.
Solution of #import Unexpected token=:)
Install package:
npm i --save-dev identity-obj-proxy
Add in jest.config.js
module.exports = {
"moduleNameMapper": {
"\\.(css|less|scss)$": "identity-obj-proxy"
}
}
Update: Aug 2021
If you are using Next JS with TypeScript. Simply follow the examples repo.
Else you will be wasting days configuring the environment.
https://github.com/vercel/next.js/tree/canary/examples/with-jest
I added moduleNameMapper at the bottom of my package.json where I configured my jest just like this:
"jest": {
"verbose": true,
"moduleNameMapper": {
"\\.(scss|less)$": "<rootDir>/config/CSSStub.js"
}
}

Resources