I am trying to create an expo react app using typescript. The app works perfectly fine but when I am trying to write some tests using Jest, it always says it can not find the module '#env' from my store file.
Cannot find module '#env' from 'src/store.ts'
Require stack:
src/store.ts
src/screens/HomeScreen.tsx
src/tests/HomeScreen.test.tsx
> 1 | import { REACT_APP_API_URL } from '#env';
| ^
2 | import axios from 'axios';
3 | import { Alert } from 'react-native';
4 | import create from 'zustand';
at Resolver._throwModNotFoundError (node_modules/jest-resolve/build/resolver.js:425:11)
at Object.<anonymous> (src/store.ts:1:1)
at Object.<anonymous> (src/screens/HomeScreen.tsx:5:1)
at Object.<anonymous> (src/tests/HomeScreen.test.tsx:3:1)
HomeScreen.test.txt
import React from 'react';
import renderer from 'react-test-renderer';
import Home from '../screens/HomeScreen';
describe('<App />', () => {
it('has 1 child', () => {
const tree = renderer.create(<Home />).toJSON();
console.log('test', tree);
});
});
The #env is defined in a src/types and the file env.d.ts
declare module '#env' {
export const REACT_APP_API_URL: string;
}
jest.config.js
// jest.config.js
// Sync object
module.exports = {
preset: 'jest-expo',
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
tsconfig: {
jsx: 'react',
},
},
],
},
testMatch: ['**/?(*.)+(spec|test).ts?(x)'],
collectCoverageFrom: [
'**/*.{ts,tsx}',
'!**/coverage/**',
'!**/node_modules/**',
'!**/babel.config.js',
'!**/jest.setup.js',
],
moduleFileExtensions: ['js', 'ts', 'tsx'],
transformIgnorePatterns: [
'node_modules/(?!(jest-)?react-native|#react-native|react=native|react-clone-referenced-element|#react-native-community|expo(nent)?|#expo(nent)?/.*|react-navigation|#react-navigation/.*|#unimodules/.*|sentry-expo)',
],
coverageReporters: ['json-summary', 'text', 'lcov'],
rootDir: './',
modulePaths: ['<rootDir>'],
collectCoverage: false,
moduleNameMapper: {
'#(.*)': '<rootDir>/node_modules/$1',
},
};
tsconfig.json
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"jsx": "react-jsx",
"strict": true,
"typeRoots": ["./src/types"],
"types": ["jest", "node","#types/jest"],
"baseUrl": ".", // this must be specified if "paths" is specified.
"paths": {
"#env": ["node_modules/#env"] // this mapping is relative to "baseUrl"
},
},
}
babel.config.js
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin',
[
'module:react-native-dotenv',
{
moduleName: '#env',
path: '.env',
blacklist: null,
whitelist: null,
safe: false,
allowUndefined: true,
},
],
],
};
};
I tried mostly everything e.g. Jest cannot find module #env React Native from here and also clear cache and reinstall all but nothing worked.
Can someone help me with this?
Create a types folder in your source folder.
Create a file named env.d.ts in the types folder.
Define your env variables as strings.
declare module '#env' {
export const REACT_APP_API_URL: string;
// other ones
}
first you create new folder under your src folder and you call it types, then you create a file named .env.d.js under types. finally you add your env variable
declare module '#env' {
export const REACT_APP_API_URL;
}
Related
Hello everyone I'm using vue 3 with storybook 6.5.16 and when i import the SVGs as a component using svg-inline-loader i get the following error in storybook app:
enter image description here
(Failed to execute 'createElement' on 'Document' svg is not a valid name)
Storybook main.js
const path = require('path');
module.exports = {
stories: [
'../src/**/*.stories.mdx',
'../src/**/*.stories.#(js|jsx|ts|tsx)',
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
],
framework: '#storybook/vue3',
core: {
builder: '#storybook/builder-webpack5',
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: "sass-loader",
options: {
additionalData: `
#import "#/assets/scss/main.scss";
`,
implementation: require('sass'),
},
},
],
});
(() => {
const ruleSVG = config.module.rules.find(rule => {
if (rule.test) {
const test = rule.test.toString();
const regular = /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
const regularString = regular.toString();
if (test === regularString) {
return rule;
}
}
});
ruleSVG.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
})();
config.module.rules.push({
test: /\.svg$/,
use: ['svg-inline-loader'],
});
config.resolve.alias['#'] = path.resolve('src');
return config;
},
}
package.json file
enter image description here
SVG Vue components
<template>
<div
ref="icon"
class="v-icon"
#click="onClick"
>
<component
:is="iconName"
class="v-icon__svg"
/>
</div>
</template>
<script>
import Cards from '#/assets/icons/Cards.svg';
export default {
name: 'VIcon',
components: {
Cards,
},
props: {
iconName: {
type: String,
required: true,
},
},
};
</script>
.babelrc file
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
i tried to use vue-svg-loader to replace svg-inline-loader but it didn't work and I got another error while building the app
ModuleBuildError: Module build failed: Error: Cannot find module './Block'
I also tried to use babel-loader in conjunction with vue-svg-loader but unfortunately I also got an error:
enter image description here
has anyone come across this or can you show your use cases of using SVGs components in Storybook and Vue 3?
I am creating a Vue component library with Rollup, but when I use slots it gives me the following error:
Uncaught (in promise) TypeError: currentRenderingInstance is null
I made a very simple component in my library:
<script setup></script>
<template>
<button>
<slot></slot>
</button>
</template>
<style scoped></style>
Then I simply use it like this:
<ExampleComponent>
Text
</ExampleComponent>
If I remove the slot and replace it with a prop or hard-coded text, everything works fine.
This is my rollup.config.js:
import { defineConfig } from 'rollup';
import path from 'path';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import vue from 'rollup-plugin-vue';
// the base configuration
const baseConfig = {
input: 'src/entry.js',
};
// plugins
const plugins = [
vue(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
}),
// process only `<style module>` blocks.
postcss({
modules: {
generateScopedName: '[local]___[hash:base64:5]',
},
include: /&module=.*\.css$/,
}),
// process all `<style>` blocks except `<style module>`.
postcss({ include: /(?<!&module=.*)\.css$/ }),
commonjs(),
];
const external = ['vue'];
const globals = {
vue: 'Vue',
};
export default [
// esm
defineConfig({
...baseConfig,
input: 'src/entry.esm.js',
external,
output: {
file: 'dist/vue-my-lib.esm.js',
format: 'esm',
exports: 'named',
},
plugins,
}),
// cjs
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.ssr.js',
format: 'cjs',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
// iife
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.min.js',
format: 'iife',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
];
Any idea about the problem?
After a whole day of searching, I found the solution (here and here). It's a problem with using a library locally (e.g., through npm link) where it seems there are two instances of Vue at the same time (one of the project and one of the library). So, the solution is to tell the project to use specifically its own vue through webpack.
In my case, I use Jetstream + Inertia, so I edited webpack.mix.js:
const path = require('path');
// ...
mix.webpackConfig({
resolve: {
symlinks: false,
alias: {
vue: path.resolve("./node_modules/vue"),
},
},
});
Or if you used vue-cli to create your project, edit the vue.config.js:
const { defineConfig } = require("#vue/cli-service");
const path = require("path");
module.exports = defineConfig({
// ...
chainWebpack(config) {
config.resolve.symlinks(false);
config.resolve.alias.set("vue", path.resolve("./node_modules/vue"));
},
});
Thanks to #mikelplhts
On vite + esbuild I used:
export default defineConfig({
...
resolve: {
alias: [
...
{
find: 'vue',
replacement: path.resolve("./node_modules/vue"),
},
],
},
...
As stated in the title, I've recently switched our project from app.json to app.config.json ready for EAS builds in Expo. Since then, my simple App.test.js has been failing
TypeError: Cannot read property 'environment' of undefined
const enableInExpoDevelopment = Constants.manifest.extra.environment !== 'Development'
This is the App.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import App from '../App';
describe('<App />', () => {
it('has 1 child', () => {
const tree = renderer.create(<App />).toJSON();
expect(tree.children.length).toBe(1);
});
});
And this is the current jest.config.js
module.exports = {
preset: 'jest-expo',
transform: {
'^.+\\.js$': require.resolve('react-native/jest/preprocessor.js')
},
transformIgnorePatterns: [
'node_modules/(?!(jest-)?react-native|react-clone-referenced-
element|#react-native-community|expo(nent)?|#expo(nent)?/.*|react-
navigation|#react-navigation/.*|#unimodules/.*|unimodules|sentry-
expo|native-base|#sentry/.*)'
],
reporters: [
'default'
],
setupFiles: [
'./__mocks__/#react-native-async-storage/async-storage.js'
]
}
I have a Vue CLI up and running successfully with PostCSS and all of the plugins I require. However, when it comes to setting up the same PostCSS config for Storybook, no matter which combination of things I try from various sources that I've come across, I cannot get my Webpack file to compile correctly.
.storybook/postcss.config.js
module.exports = {
plugins: {
autoprefixer: {},
'postcss-nested': {},
'postcss-custom-media': {},
'postcss-advanced-variables': {},
},
};
.storybook/webpack.config.js
const path = require('path');
const rootPath = path.resolve(__dirname, '../src');
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
'postcss-loader',
],
});
config.resolve.alias['#'] = rootPath;
return config;
};
./storybook.config.js
import { configure } from '#storybook/vue';
import Vue from 'vue';
import Vuex from 'vuex';
import '../src/css/main.css';
import '../src/stories/main.css';
Vue.use(Vuex);
function loadStories() {
require('../src/stories');
}
configure(loadStories, module);
Error
ERROR in ./src/css/main.css (./node_modules/#storybook/core/node_modules/css-loader/dist/cjs.js??ref--3-1!./node_modules/postcss-loader/src??postcss!./node_modules/style-loader!./node_modules/css-loader??ref--6-1!./node_modules/postcss-loader/src!./src/css/main.css)
Module build failed (from ./node_modules/postcss-loader/src/index.js):
SyntaxError
(2:1) Unknown word
1 |
> 2 | var content = require("!!../../node_modules/css-loader/index.js??ref--6-1!../../node_modules/postcss-loader/src/index.js!./main.css");
| ^
Please help, I got this error when trying to create test for vue js dynamic component using jest.
I'm using babel-plugin-syntax-dynamic-import and babel-plugin-transform-dynamic-import with babel ver > 7.0.0
● Test suite failed to run
TypeError: Path must be a string. Received undefined
at TestExclude.shouldInstrument (node_modules/test-exclude/index.js:77:31)
at shouldSkip (node_modules/babel-plugin-istanbul/lib/index.js:59:21)
at PluginPass.enter (node_modules/babel-plugin-istanbul/lib/index.js:74:15)
at newFn (node_modules/#babel/core/node_modules/#babel/traverse/lib/visitors.js:193:21)
at NodePath._call (node_modules/#babel/core/node_modules/#babel/traverse/lib/path/context.js:53:20)
at NodePath.call (node_modules/#babel/core/node_modules/#babel/traverse/lib/path/context.js:40:17)
at NodePath.visit (node_modules/#babel/core/node_modules/#babel/traverse/lib/path/context.js:88:12)
at TraversalContext.visitQueue (node_modules/#babel/core/node_modules/#babel/traverse/lib/context.js:118:16)
Here's my my-page.js code:
const MyComponent = () => import('src/components/MyComponent')
...
components: {
MyComponent
},
...
myPage.spec.js code:
import { shallow } from 'vue-test-utils'
import MyPage from '#/pages/MyPage'
describe('MyPage.vue', () => {
let component
beforeEach(() => {
component = shallow(MyPage, {
...
})
jest.resetModules()
jest.clearAllMocks()
})
it('method#isEven', () => {
let result = component.vm.isEven(2)
expect(result).toBe(true)
})
})
jest.conf.js code:
const path = require('path')
module.exports = {
rootDir: path.resolve(__dirname, '../../'),
moduleFileExtensions: [
'js',
'json',
'vue'
],
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/src/$1'
},
transform: {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
},
testPathIgnorePatterns: [
'<rootDir>/test/e2e'
],
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
setupFiles: ['<rootDir>/test/unit/setup'],
coverageDirectory: '<rootDir>/test/unit/coverage',
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!src/main.js',
'!src/router/index.js',
'!**/node_modules/**'
],
testURL: 'http://localhost/unit-test'
}
Do I need to add more configuration?
No need to use babel-plugin-syntax-dynamic-import, use babel-plugin-dynamic-import-node instead. Implementation can be seen at https://jestjs.io/docs/en/webpack.html#using-with-webpack-2
thanks to https://github.com/facebook/jest/issues/5920