Jest cannot find module #env React Native - reactjs

I'm currently facing some problem I'm using in my react native app https://github.com/goatandsheep/react-native-dotenv for handling .env.
Error => Cannot find module '#env' from 'src/api/api.ts'
I'm testing currently my redux saga to call the api endpoint:
import axios from 'axios';
import {API_URL} from '#env';
export default axios.create({
baseURL: API_URL,
responseType: 'json',
});
API Endpoint
export const sendCheckNumber = async (
phoneNumber: string,
): Promise<AuthenticationTO> => {
const response = await axios.get<AuthenticationTO>(
`SendCheckNumber/${phoneNumber}`,
);
return response.data;
};
I'm using ts-jest package.json. I saw in the docs its possible to include bable in ts-jest because I'm using bable to import the 'module:react-native-dotenv', as plugin. I thought that will already solve my problem but unfortunately it still fails. Maybe someone of you have some suggestion what could cause this error.
Thank you!!!
package.json
"jest": {
"preset": "react-native",
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
"\\.(ts|tsx)$": "ts-jest"
},
"globals": {
"ts-jest": {
"babelConfig": "babel.config.js",
"tsConfig": "tsconfig.jest.json"
}
},
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"modulePaths": [
"<rootDir>/src"
],
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
}

Maintainer goatandsheep here. I recently added some documentation on how this is done. Take a look at the documentation section on TypeScript. Here is the excerpt:
Create a types folder in your project
Inside that folder, create a *.d.tsfile, say, env.d.ts
in that file, declare a module as the following format:
declare module '#env' {
export const API_BASE: string;
}
Add all of your .env variables inside this module.
Finally, add this folder into the typeRoots field in your tsconfig.json file:
{
"typeRoots": ["./src/types"],
}
Let me know if that works!

I fixed this problem like following.
import {API_URL} from '#env';`
Added this instead:
import {API_URL} from 'react-native-dotenv';
And add the next in babel.config.js
module.exports = function (api) {
api.cache(true)
return {
presets: ["babel-preset-expo"],
plugins: [
[
"module:react-native-dotenv",
{
moduleName: "react-native-dotenv",
},
],
],
}
}
It works well for me.

Related

Storybook with Vite error: fn.apply is not a function

I'm refactoring a React webapp from CRA to using Vite and having issues with Storybook. The storybook's GUI opens, and I see a list of stories on the left panel. But whichever story I choose I get an error TypeError: fn.apply is not a function in Canvas tab like shown here:
I found a similar issue on Storybook's GitHub, and tried to change names StorybookName to storybookName in all the stories, also checked all the React components in the stories to make sure all of them are correctly defined as functions.
When it was using CRA storybook worked fine, but with Vite it's not working. Maybe I'm missing some configuration for Vite, so here's my vite.config.js as well:
import react from '#vitejs/plugin-react';
import { defineConfig } from 'vite';
import svgrPlugin from 'vite-plugin-svgr';
const path = require('path');
export default defineConfig({
esbuild: {
jsxFactory: 'jsx',
jsxInject: `import { jsx } from '#emotion/react'`,
},
optimizeDeps: {
include: ['#emotion/react'],
},
plugins: [
react({
jsxImportSource: '#emotion/react',
babel: {
plugins: ['#emotion/babel-plugin'],
},
}),
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
});
And here's main.js from storybook:
const path = require('path');
const svgrPlugin = require('vite-plugin-svgr');
module.exports = {
core: {
builder: 'storybook-builder-vite',
},
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: ['#storybook/addon-links', '#storybook/addon-essentials'],
viteFinal: (config) => {
return {
...config,
plugins: [
...config.plugins,
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
};
},
};
In Chrome Dev Tools I get this error:
I found the reason and it appears that all the configurations I had were correct. The problem was in the way how I aplied one of the decorators for Storybook. Basically, I wasn't correctly exporting one of the decorators and therefore was applying undefined instead of a decorator.
So, for whoever faces this issue, please note that it's most of the time a problem with syntax. Check all your functions, components, decorators and so on and make sure they are all correctly defined and exported.
The error message itself doesn't give any clue where to dig, which is a big shame, so this one is pretty tough to debug.

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

How to allow scss in jest for unit testing for typescript nextjs?

I have an error on the scss importation. I have tried using mockup and identity-obj-proxy but none of them work. I am wondering if my regex expression might be wrong or something.
The error is located at
import utilityStyles from "~/scss/Utils.scss"; and `{#import "~Scss/helpers/variables";`
In package.json I have
"preset": "ts-jest",
"moduleNameMapper": {
"^~(.*)$": "<rootDir>/src/$1",
"^src/(.*)$": "<rootDir>/src/$1",
"^.*.(css|scss)$": "identity-obj-proxy"
},
In the index.d.ts I have
declare module '*.scss' {
const content: { [key: string]: string };
export default content;
}
declare module 'raw-loader!*' {
const content: string
export default content
}
Update
I thought the problem was due to my regex expression, so I tried
"^(.*)(css|less|scss)$": "identity-obj-proxy" but still doesn't work
If you are usig jest to test you can do like this
"jest": {
"setupFiles": [
"<rootDir>/tests/setupTest.js"
],
"moduleNameMapper": {
"\\.(scss|css|jpg|png|gif)$": "<rootDir>/tests/file.mock.js"
}
},
And in file.mock.js
module.exports = {};

Jest throwing TypeError: Cannot read property 'fetch' of undefined

I'm trying to run some tests with Jest on my react/react-native library (only some business logic inside).
We are testing actions that uses fetch function (polyfill with whatwg-fetch).
I've added whatwg-fetch (thanks to Safari) for react.
Whenever i try to run a test, i'm getting this error:
TypeError: Cannot read property 'fetch' of undefined
at node_modules/whatwg-fetch/fetch.js:4:11
at Object.<anonymous> (node_modules/whatwg-fetch/fetch.js:461:3)
at Object.<anonymous> (node_modules/jest-expo/src/setup.js:138:416)
What can cause this issue? Is there a way in the jest config to avoid this?
Here are some files for debug:
Jest config in package.json
"jest": {
"preset": "jest-expo",
"moduleFileExtensions": [
"js",
"jsx",
"ts",
"tsx"
],
"verbose": true,
"transform": {
"^.+\\.(js|ts|tsx)$": "<rootDir>/node_modules/babel-jest"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/",
"<rootDir>/dist/"
],
"transformIgnorePatterns": [
"node_modules/?!react-native"
]
},
Webpack config:
const config = {
entry: [
'whatwg-fetch',
__dirname + '/src/index.ts',
],
devtool: 'source-map',
output: {
path: path.join(__dirname, '/dist'),
filename: 'index.js',
library: 'checkinatwork-module',
libraryTarget: 'umd',
umdNamedDefine: true,
},
module: {
loaders: [
{ test: /\.(tsx|ts)?$/, loader: 'ts-loader', exclude: /node_modules/ },
],
},
resolve: {
modules: [
'./src',
'node_modules',
],
extensions: ['.js', '.ts', '.jsx', '.tsx', 'json'],
},
plugins: [
],
};
Test file:
import expect from 'expect';
import * as actions from '../../src/components/Checkin/checkin.action';
import * as reducers from '../../src/components/Checkin/checkin.reducer';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import nock from 'nock';
const middlewares = [ thunk ];
const mockStore = configureMockStore(middlewares);
describe('=> ADD CHECKIN ACTIONS', () => {
describe('- REQUEST', () => {
it('Action: ADD_CHECKIN_REQUEST should request addCawCheckin', () => {
const expectedAction = {
type: actions.ADD_CHECKIN_REQUEST,
isFetching: true,
};
expect(actions.addCheckinRequest())
.toEqual(expectedAction);
});
it('Reducer: newCheckin should trigger ADD_CHECKIN_REQUEST and initiate loading', () => {
const expectedState = {
isFetching: true,
status: null,
};
expect(reducers.newCheckin(reducers.newCheckinDefaultState, actions.addCheckinRequest()))
.toEqual(expectedState);
});
});
Action file:
export const getCheckins = (sessionId, date, url, isRefresh) => {
const config = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId: {sessionId},
date: {date},
}),
};
return dispatch => {
if (!isRefresh) {
dispatch(getCheckinsRequest());
}
return fetch(url + 'getCAWCheckIns', config)
.then(response => response.json())
.then(({ checkins }) => {
dispatch(getCheckinsSuccess(checkins));
}).catch(err => {
dispatch(getCheckinsError('Get checkins failed'));
console.error('Get checkins failed: ', err);
});
};
};
Thanks!
I've done it in the spec with:
import { fetch } from 'whatwg-fetch';
global.fetch = fetch;
And it has worked as expected with Jest.
might be late to the game, but this worked for me.
Possible solution #1
Note: React.PropTypes is deprecated as of React v15.5. Please use the prop-types library instead.
If you install the npm package prop-types, it has isomorphic-fetch as a dependency. This will give you fetch as a global. You will still need to import it into your test file. You might need to exclude it from your linter too.
add this to the top of the test file.
import fetch from 'isomorphic-fetch'
I didn't need to call fetch in the test suite, but I needed to make it available.
If you use this approach, I think you would remove the 'whatwg-fetch', from your webpack entry
Hope this helps
Updated: Possible solution #2
Using the example of #zvona from above, but create a MOCKS folder in your app. then a file /globalMock.js. You might not have set it up properly.
__MOCKS__/globalMock.js
// use one of these imports
import { fetch } from 'whatwg-fetch' // if you want to keep using the polyfill
import { fetch } from 'isomorphic-fetch' // from a dependency node module that I spoke of in the previous solution.
global.fetch = fetch
Now in package.json
add this to your Jest configuration:
"jest": {
"verbose": true,
"rootDir": "app",
"setupFiles": ["<rootDir>/__MOCKS__/globalMock.js"]
}
this will allow the use of fetch in your tests.
I also had to use this same concept for localStorage. Where I keep all of my globals that Jest doesn't have access.
Upgrading react-native, jest, and babel-jest to the latest versions fixed this issue for us.
This worked for me. In your expo set up file(node_modules/jest-expo/src/setup.js) where it requires whatwg-fetch, I changed that require to require('fetch-everywhere')
const { Response, Request, Headers, fetch } =
require('fetch-everywhere');
global.Response = Response;
global.Request = Request;
global.Headers = Headers;
global.fetch = fetch;
For some reasons, only fetch everywhere was working with expo and jest.

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