vue.config.js configureWebpack not used in unit tests (vue 3) - javascript

In my vue config I have the following:
configureWebpack: {
resolve: {
alias: {
react: path.resolve(__dirname, 'composition/react'),
hooks: path.resolve(__dirname, 'composition'),
},
},
},
In my component I have the following:
import { useEffect, useState } from 'react';
This is so I can re use some of the Vue code in React projects. This works when running and building the project but not when testing. When unit testing I get the error: Cannot find module 'react' from 'useCategories.js', the above import is from useCategories.
The following is in the jest.config.js:
module.exports = {
preset: '#vue/cli-plugin-unit-jest',
transform: {
'^.+\\.vue$': 'vue-jest'
}
}
If unit testing in vue is ignoring values from vue.config.js then how can I set the webpack path resolve values for testing. I would rather not repeat these values but if it's a JavaScript file I guess I can import it from the same file in different configs.

Webpack isn't used in Jest, this would make module testing impractical, so Webpack config cannot affect anything.
As the documentation explains, it's necessary to provide module mapping in Jest config as well, e.g.:
moduleNameMapper: {
'^react$': '<rootDir>/composition/react',
...

Related

Esbuild with ReactJS.NET?

TL;DR How can I use esbuild with ReactJS.NET?
Long version
ReactJS.NET expects the following from a "bundle":
React.Exceptions.ReactNotInitialisedException: 'React has not been loaded correctly: missing (React, ReactDOM, ReactDOMServer). Please expose your version of React as global variables named 'React', 'ReactDOM', and 'ReactDOMServer'
What Webpack actually does is always quite unclear to me, but looking at the ReactJS.NET Webpack tutorial here, this is the setup:
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import RootComponent from './home.jsx';
global.React = React;
global.ReactDOM = ReactDOM;
global.ReactDOMServer = ReactDOMServer;
global.Components = { RootComponent };
Further at the sample webpack-config here, there is this output-setting:
{
[...]
globalObject: 'this',
}
Mirroring this in esbuild would be using iife and esbuild.globalName = 'this', but it throws an error:
> (global name):1:0: error: Expected identifier but found "this"
1 │ this
Esbuild is quite stern on that it is a bundler (not a transpile-and-concatenator), so how would I tweak Esbuild to have the bundle mutate the global object to what React.NET expects? - And is it even possible?
Thanks,
Flemming
Found a solution.
import { build } from 'esbuild'
const globalName = 'whatever'
build({
[...]
format: 'iife',
globalName,
footer: {
// Important! Assigns the raw export of the bundle to whatever `this` is in the given context
js: `Object.assign(this, ${globalName})`,
},
})

Relative Imports in React.js

Currently I have an import which looks like this
import Button from "../../../components/Button/Button"
but I want to make it relative so I wouldn't require to type the ../../../ time and again.
I want to import using this method:
import Button from "components/Button/Button" or src/components/Button/Button
but please also assure that it will work on both production and development.
If you are using vscode with project created with create-react-app you can try adding a jsconfig.json file in root with this .
{
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}
If you are using webpack. You can use resolve.
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/'),
Components: path.resolve(__dirname, 'src/components/'),
}
}
};
Now, instead of using relative paths when importing like so:
import Utility from '../../utilities/utility';
import Button from '../../src/components/Button';
you can use the alias:
import Utility from 'Utilities/utility';
import Button from 'Components/Button';
you can download the react snippet plugig to help you with import
import Butoon from './component/Button/Button' I Think

Build React components library with Webpack 4

I'm currently building a library of React components and bundling it with Webpack 4.
Everything works just fine from building the library's bundle to publishing it on an npm registry.
But then, I'm not able to import any of its components in an other React application and get this error message at runtime:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
And here is the related code:
A dumb component from my components library:
button/index.js
import React from "react";
const Button = () => <button>Foobar</button>;
export { Button };
The main entry point of my library index.js:
import { Button } from "./src/components/Button";
export { Button };
My Webpack config webpack.config.js:
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./index.js",
plugins: [new CleanWebpackPlugin()],
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "commonjs",
library: ""
}
};
And finally, the import of this component in an other application:
import { Button } from "my-design-system";
I guess I'm missing something in my Webpack config or one of the property may be wrong, but after reading multiple posts and tutorials, I can't figure which one.
You're exporting your library as commonjs and trying to import it via import/export syntax. You should change your output to
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "umd",
library: "my-design-system"
}
Found a lot of info here: https://webpack.js.org/guides/author-libraries/
What I would do is to export your components as default and then re-export as named from index.js:
/// Button.js
import React from "react";
const Button = () => <button>Foobar</button>;
export default Button ;
// index.js
export { default as Button } from "./src/components/Button";
Then you can do
import { Button } from "my-design-system";
Also make sure you have main set up, pointing to your index.js, in your design system's package.json
Additionally, if you still want to have named exports in some of your components, you can export everything from that component file:
//index.js
export * from "./src/components/ComponentWithNamedExports";
Either way you will make sure there's always one point of export for all your components.
EDIT: As noted in by Maaz Syed Adeeb, you have wrong libraryTarget in your config. I'd remove both libraryTarget and library from there.

React eliminate dots from import

I am kinda new in the web and would like to ask a simple question.
Basically I just want to eliminate dots from my import. I mean thing like:
import Component from '../../container/etc'
How could I just start my import from the root? So its would become smth like:
import Component from 'container/etc'
I used create-react-app for set up
You can add the resolve config in webpack like
module.exports = {
//things here
resolve: {
extensions: ['.jsx', '.scss', '.js', '.json'],
modules: [
path.resolve(__dirname, 'app'),
'node_modules'
]
}
// other things here
}
where you directory structure would be like
-- app
-- container
-- etc.js
-- api.json
so you can import like
import ETC from 'container/etc';
import json from 'api.json'
In case you are using create-react-app, you can create a .env file on the root of your project and make the NODE_PATH point to the src folder (or wherever you have your code) all you'll have to do is write:
NODE_PATH=src
Create-react-app will read your .env file without ejecting.

Configuring Enzyme 3.x Adapter

I am writing tests for a React app using Jest and Enzyme. Enzyme 3.x introduced Adapters to provide compatibility across different versions of React. The installation documentation gives examples how to set this up:
// setup file
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
What is this "setup file" referred to in the comment? Is this a file which can be run before all tests? Where does this file go in a React project? Does it need a particular name?
It doesn't need a particular name, and yes, it's run before any tests are.
You hook it up in your package.json's jest stanza.
This is an example from a project I'm working on.
"jest": {
// other stuff...
"setupFiles": [
"./js/jest-setup.js"
],
// ....
}
The actual js/jest-setup.js file looks like this (i.e. like your example).
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
Enzyme has a nifty guide on setup here: https://github.com/airbnb/enzyme/blob/master/docs/guides/jest.md
Though the initial step doesn't say it is the package.json.
Posting the relevant sections (with some minor tweaks) here so we don't lose it:
Configure with Jest
To run the setup file to configure Enzyme and the Adapter with Jest direct setupTestFrameworkScriptFile to literally the string <rootDir> and the path to your setup file.
package.json:
{
"jest": {
"setupTestFrameworkScriptFile": "<rootDir>src/setupTests.js"
}
}
Jest version 15 and up
Starting with version 15, Jest no longer mocks modules by default. Because of this, you no longer have to add any special configuration for Jest to use it with enzyme.
Install Jest, and its Babel integrations, as recommended in the Jest docs. Install enzyme. Then, simply require/import React, enzyme functions, and your module at the top of a test file.
setupTests.js:
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Foo from '../Foo';
What is this "setup file" referred to in the comment? :
It's a way of running something before your test starting (some config for instance)
If you create your React Project using react-create-app you need or eject your application or pass a command set up your file setupTest.js (The name does not matter), but you need to identify in your command line, like this:
package.json
"scripts": {
"test": "react-scripts test --env=jsdom --setupFiles=./src/test-setup.js",
},
test-setup.js
import './shim';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
shim.js (this is a hack to avoid the warning)
global.requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};
Jest & enzyme configuration :
Add following code in package.json
"jest": {
"testEnvironment": "jsdom",
"moduleDirectories": [
"src",
"node_modules"
],
"moduleNameMapper": {
"\\.(css|scss)$": "<rootDir>/__mocks__/styleMock.js",
"\\.(jpg|gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js"
},
"transform": {
"^.+\\.(js|jsx)$": "babel-jest",
".+\\.(css|styl|less|sass|scss)$": "<rootDir>/node_modules/jest-css-modules-transform"
},
"setupTestFrameworkScriptFile": "<rootDir>/setupTests.js",
"setupFiles": [
"<rootDir>setup.js"
],
"moduleFileExtensions": [
"css",
"scss",
"js",
"json",
"jsx"
],
"testRegex": "\/test\/spec\/.*\\.js$",
"transformIgnorePatterns": [
"/node_modules/(?!test-component).+\\.js$"
]
}
For setup of Enzyme => setup.js
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
configure({ adapter: new Adapter() })
For setupTestFrameworkScriptFile : setupTests.js
global.fetch = require('jest-fetch-mock')
const { JSDOM } = require('jsdom')
const jsdom = new JSDOM('<!doctype html><html><body></body></html>')
const { window } = jsdom
const exposedProperties = ['window', 'navigator', 'document']
const { document } = new JSDOM('').window
global.document = document
global.window = document.defaultView
global.HTMLElement = window.HTMLElement
global.HTMLAnchorElement = window.HTMLAnchorElement
Object.keys(document.defaultView).forEach(property => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property)
global[property] = document.defaultView[property]
}
})
global.navigator = {
userAgent: 'node.js',
}
I was just having this same issue and the easiest solution was to simply create a file named exactly setupTests.js, in the src/ directory with the contents:
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
Jest automatically detects it and the error goes away.
With enzyme 3 we need an adapter. Adapter allows us to specify exactly which version of react we are gonna test against. This allows core enzyme library to be smaller. It does not need to have all of the code for all of the various versions of react that supported. Instead you just specify which one you need by installing the adapter that keeps the core library light and keeps your entire code base more manageable.
this is how u configure it:
in tests directory create any .js file:
tests/setupTest.js
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
Enzyme.configure({ adapter: new Adapter() });
in the root directory create jest.config.json file and put this
{
"setupFiles": ["raf/polyfill", "<rootDir>/src/tests/setupTest.js"],
}
NOTE: We also need to install a polyfill module. Polyfill is known as request animation frame. Since we do not have it in test environment, we need to install.
npm i raf --save
finally in package.json :
"test": "jest --config=jest.config.json"

Categories