Webpack alias & config in Jest tests - testing

I'm updating an older Webpack2 project to Webpack4 and switching the tests over to Jest but have a seemingly simple problem with a couple of the webpack related bits.
Specifically, the project structure for the troublesome bits look like this:
src
- constants
- index.js
- config
- base.js
- test.js
- dev.js
- dist.js
During testing, the classes under test use import config from 'config' so issue number one is allowing them to find the right config file. With Webpack2 this is subbed in by webpack itself, but obviously not during Jest tests.
I can resolve this by hard coding the specific test config into the moduleNameMapper in the jest config in package.json like so:
"jest": {
"moduleNameMapper": {
"^config$": "<rootDir>/src/config/test.js"
}
}
This appears to work.
The second part of my issue is allowing Jest to find named exports src/constants/index.js using syntax like import { SOME_CONST } from 'constants'.
When I try to use moduleNameMapper I get back undefined from anything that uses the constants and I believe this is because moduleNameMapper is largely used to mock out dependencies rather than supply them.
With this in mind I think I need to use modulePaths or moduleDirectories to allow the constants to be located.
I've tried the following configurations (not simultaneously) without any luck:
"modulePaths": [
"<rootDir>/src/constants",
"src/constants"
],
"moduleDirectories": [
"node_modules",
"src",
"src/constants",
"/src/constants"
"/src/constants/",
"./src/constants"
],
What should the correct config be for Jest to locate my constants?
If it's any help I'm trying to mimic this Webpack2 config in Jest
resolve: {
alias: {
constants: `${this.srcPathAbsolute}/constants/`
}
}

Related

Importing react-native package when running Vite

I am new to Vite and Vitest. I am experimenting a little bit, trying to add Vitest to a React-native app. I know Vite doesn't really support React Native but I would like to trying running just the tests with Vitest.
I get an error when trying to import React-native modules:
Module .../node_modules/react-native/index.js:14 seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package "react-native" asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
As a temporary workaround you can try to inline the package by updating your config:
// vitest.config.js
export default {
test: {
deps: {
inline: [
"react-native"
]
}
}
}
When adding the suggested config the tests break inside React-native instead, as if the modules in fact is not supported.
What is going on here? Is React-Native only published as commonjs modules, while only esm-modules is supported by Vite? Is there a way around it?
Thanks in advance,
M.

How can I configure Webpack and Vue-Loader to treat warnings as errors?

QUESTION: How can I configure Webpack to treat warnings as errors when using Vue-Loader?
BACKGROUND: My Webpack configuration is using Vue-Loader to build an app that uses Vue single-file components. I'd like the build to fail and produce an error when warnings such as the below occur:
WARNING in ./{SOME_COMPONENT}.vue ({BOILERPLATE_PATHS}) 107:6-34
"export '{SOME_FUNCTION}' was not found in '../../{SOME_MODULE}'
The warning above surfaces when I'm trying to import a "named" export from a module that only contains a default export.
I've reviewed the docs at the links below, but I don't see anything that would allow me to achieve my goal:
https://vue-loader.vuejs.org/options.html
https://vue-loader-v14.vuejs.org/en/options.html
For non-watch builds, I suppose it would be possible to parse the build output for warnings using a regex and trigger an action that could fail a CI build, but I'd ideally like to be able to fail watch builds as well. Maybe there's a post-build Webpack hook or something? I'm open to suggestions.
My current Vue-Loader/Webpack config is basically:
{
test: /\.vue$/,
loader: 'vue-loader',
include: [
path.resolve(__dirname, './SomeFolder/')
],
exclude: [
path.resolve(__dirname, './node_modules/'),
path.resolve(__dirname, './SomeFolder/Tests/')
],
},

Problem using jest with storybook snapshot testing in react native

What I have
I'm trying to use jest and Storybook with Storyshots addon for snapshot test in my react-native/typescript app, but I'm having some issues when I try to run simple test.
According to Snapshot testing section in storybook documentation, the only thing you need to do is create an storybook.test.js file with the following:
storybook.test.js
import initStoryshots from '#storybook/addon-storyshots';
initStoryshots();
After this, everything is supposed to work as expected, but the console throws the following error:
● 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, ign
oring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Mo
dules, see https://jestjs.io/docs/en/ecmascri
pt-modules for how to enable it.
• To have some of your "node_modules" fi
les transformed, you can specify a custom "tr
ansformIgnorePatterns" in your config.
• If you need a custom transformation sp
ecify a "transform" option in your config.
• If you simply want to mock your non-JS
modules (e.g. binary assets) you can stub th
em out with the "moduleNameMapper" config opt
ion.
You'll find more details and examples of
these config options in the docs:
https://jestjs.io/docs/en/configuration.h
tml
Details:
C:\Users\myuser\Desktop\myapp\node_m
odules\react-native-swipe-gestures\index.js:3
import React, { Component } from "react";
^^^^^^
SyntaxError: Cannot use import statement
outside a module
at Runtime.createScriptFromCode (node_m
odules/jest-runtime/build/index.js:1350:14)
at Object.<anonymous> (node_modules/#st
orybook/react-native/dist/preview/components/
OnDeviceUI/navigation/index.js:29:53)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 11.468 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
jest.config.js
module.exports = {
preset: 'react-native',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
};
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset']
};
If I remove #storybook/addon-storyshots relate things from my tests, everything is working normally without any problem. So I don't know if I need some extra configuration to make work storybook/jest snapshoot testing with react native.
It's enough. Add react-native-swipe-gestures to transformIgnorePatterns of your jest.config.js.
transformIgnorePatterns: ['node_modules/(?!(react-native|#react-navigation|#react-native|react-native-swipe-gestures)/)'],
This did a trick for me.

Bundling a plugin with Rollup but having duplicate Vue.js package imported in the client app's bundle (Nuxt)

Dear Stack Overflow / Vue.js / Rollup community
This could be a noob question for the master plugin developers working with Vue and Rollup. I will write the question very explicitly hoping that it could help other noobs like me in the future.
I have simple plugin that helps with form validation. One of the components in this plugin imports Vue in order to programatically create a component and append to DOM on mount like below:
import Vue from 'vue'
import Notification from './Notification.vue' /* a very simple Vue component */
...
mounted() {
const NotificationClass = Vue.extend(Notification)
const notificationInstance = new NotificationClass({ propsData: { name: 'ABC' } })
notificationInstance.$mount('#something')
}
This works as expected, and this plugin is bundled using Rollup with a config like this:
import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import { terser } from 'rollup-plugin-terser'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
export default {
input: 'src/index.js',
output: {
name: 'forms',
globals: {
vue: 'Vue'
}
},
plugins: [
vue(),
babel(),
resolve(),
commonjs(),
terser()
],
external: ['vue']
}
As you can see, Vue.js is getting externalised in this bundle. The aim (and the assumption) is that the client app that imports this plugin will be running on Vue, therefore there's no need to bundle it here (assumption).
The very simple src/index.js that the bundler uses is below:
import Form from './Form.vue'
export default {
install(Vue, _) {
Vue.component('bs-form', Form)
}
}
Rollup creates 2 files (one esm and one umd) and references them in in the plugins package.json file like below:
"name": "bs-forms",
"main": "./dist/umd.js",
"module": "./dist/esm.js",
"files": [
"dist/*"
],
"scripts": {
"build": "npm run build:umd & npm run build:es",
"build:es": "rollup --config rollup.config.js --format es --file dist/esm.js",
"build:umd": "rollup --config rollup.config.js --format umd --file dist/umd.js"
}
Everything works as expected up to this point and the bundles are generated nicely.
The client app (Nuxt SSR) imports this plugin (using npm-link since it's in development) with a very simple import in a plugin file:
/* main.js*/
import Vue from 'vue'
import bsForms from 'bs-forms'
Vue.use(bsForms)
This plugin file (main.js) is added to nuxt.config.js as a plugin:
// Nuxt Plugins
...
plugins: [{src: '~/plugins/main'}]
...
Everything still works as expected but here comes the problem:
Since the clients is a Nuxt app, the Vue is imported by default of course but the externalised Vue module (by the forms plugin) is also imported in the client. Therefore there is a duplication of this package in the client bundle.
I guess the client app can configure its webpack config in order to remove this duplicated module. Perhaps by using something like a Dedupe plugin or something? Can someone suggests how to best handle situation like these?
But what I really want to learn, is the best practice of bundling the plugin at the first place, so that the client doesn't have to change anything in its config and simply imports this plugin and move on.
I know that importing the Vue.js in the plugin may not be a great thing to do at the first place. But there could be other reasons for an import like this as well, for example imagine that the plugin could be written in Typescript and Vue.js / Typescript is written by using Vue.extend statements (see below) which also imports Vue (in order to enable type interface):
import Vue from 'vue'
const Component = Vue.extend({
// type inference enabled
})
So here's the long question. Please masters of Rollup, help me and the community out by suggesting best practice approaches (or your approaches) to handle situations like these.
Thank you!!!!
I had the same problem and I found this answer of #vatson very helpful
Your problem is the combination of "npm link", the nature of nodejs module loading and the vue intolerance to multiple instances from different places.
Short introduction how import in nodejs works. If your script has some kind of library import, then nodejs initially looks in the local node_modules folder, if local node_modules doesn't contain required dependency then nodejs goes to the folder above to find node_modules and your imported dependency there.
You do not need to publish your package on NPM. It is enough if you generate your package locally using npm pack and then install it in your other project npm install /absolute_path_to_your_local_package/your_package_name.tgz. If you update something in your package, you can reinstall it in your other project and everything should work.
Here is the source about the difference between npm pack and npm link https://stackoverflow.com/a/50689049/6072503.
I have sorted this problem with an interesting caveat:
The duplicate Vue package doesn't get imported when the plugin is used via an NPM package (installed by npm install -save <plugin-name> )
However, during development, if you use the package vie npm link (like npm link <plugin-name>) then Vue gets imported twice, like shown in that image in the original question.
People who encounter similar problems in the future, please try to publish and import your package and see if it makes any difference.
Thank you!

Cannot get my head around this web-pack path error

My project structure is as follows:
I have the following webpack config file:
module.exports = {
context: __dirname + "/resources",
entry: "./js/entry.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
}
};
and open up my entry.js file with
require('./style.scss');
I understand this specific arrangement might not be working, but i have been trying different permutations and setups and configurations for over an hour and just can't seem to get webpack to find my .scss file.
Can someone please tell me how the webpack config file should be set up in my case?
Cheers.
edit,
trying to go up two levels in my require,
require('../../scss/style.scss')
still gives me,
Similarly for
require('../scss/style.scss');
The problem is in the require statement
require('./style.scss');
It will search for your style file inside the resources/js directory in reference to your entry.js file try requiring your style using this:
require('../scss/style.scss');
Try to use path module for resolving the context path:
var path = require('path');
...
context: path.resolve("resources"),
...
Let me know if the problem resolved.
Well I feel like a complete idiot, after renaming files and folders numerous times and trying different permutations of my require statement, I noticed the error seems to constantly state
Can't resolve 'style' in ...
Turns out i had not installed style-loader and css-loader into my project having though they were bundled with the sass-loader. (it's actually noted on the npm page), running
npm install css-loader style-loader -D
in my project directory solved the issue.
Still, thanks for your suggestions, and I hope this might help someone in the future.