Jest: Ignoring a dependency - vue.js

Currently I have a Mixin that is called on mounted() hook in my Vue Component:
Component file:
mixins: [testMixin],
mounted () {
this.getMixin()
}
Mixin (testMixin) file:
// Test fails at the import because of `SyntaxError: Unexpected Identifier`
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import isEmpty from 'lodash.isempty';
import DependencyThatImportsLodash from ''
export default {
created () {
this.getMixin()
},
}
I have tried:
const wrapper = shallowMount(Component, {
localVue,
mocks: {
getMixin: () => {}
}
})
and
const localVue = createLocalVue()
localVue.mixin(testMixin)
But I still get the lodash error, how can I get past it? Thanks
This is my jest.config.js
module.exports = {
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: ['js', 'vue', 'json'],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
testPathIgnorePatterns: [
'/node_modules/',
'/vendors/'
]
}

Related

Jest import common plugins like Vee Validate before each test

I'm new to Jest and am testing my Nuxt JS application with unit testing. I have many test files set up and need to import various logic into each test file, such as my Vee Validate config.
I've tried adding it to a setup.js file and included this in setupFilesAfterEnv but it's not getting included.
What am I doing wrong?
tests/unit/setup.js
import Vue from 'vue'
import { ValidationProvider, ValidationObserver, extend, configure, localize } from 'vee-validate'
import * as rules from 'vee-validate/dist/rules';
import en from 'vee-validate/dist/locale/en.json'
const config = {
mode: 'lazy',
classes: {
valid: '',
invalid: 'tw-border-red-500 dark:tw-border-white'
}
}
Object.keys(rules).forEach(rule => {
extend(rule, rules[rule]);
});
configure(config)
// Register it globally
Vue.component('ValidationObserver', ValidationObserver)
Vue.component('ValidationProvider', ValidationProvider)
// // activate the locales
localize({
en
});
My jest.config.js file:
module.exports = {
silent: true,
testEnvironment: 'jsdom',
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
},
moduleFileExtensions: ['js', 'vue', 'json'],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
'vee-validate/dist/rules': 'babel-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue',
],
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!vee-validate/dist/rules)',
],
setupFilesAfterEnv: [
'<rootDir>/tests/unit/setup.js'
]
}
And one of my test files called LoanAmount is:
import { mount } from '#vue/test-utils'
import flushPromises from 'flush-promises';
import LoanAmount from '#/components/Form/Steps/Loan/LoanAmount'
describe('LoanAmount', () => {
test('is a Vue instance', () => {
const wrapper = mount(LoanAmount)
expect(wrapper.vm).toBeTruthy()
})
test('amount is available for value', async () => {
const wrapper = mount(LoanAmount)
await flushPromises()
const amount = wrapper.findAll('.jest__amount-input')
expect(amount.exists()).toBe(true)
})
})
If I include all of the contents from tests/unit/setup.js and include above my describe block then it works, but I can't be repeating this in each test file.
You can use the setupFiles property in jest.config.js:
module.exports = {
rootDir: path.resolve(__dirname, '../../'),
moduleFileExtensions: [
'js',
'json',
'vue'
],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'vee-validate/dist/rules': 'babel-jest'
},
transformIgnorePatterns: [
'<rootDir>/node_modules/(?!(vuetify)|(vue-material-design-icons)|(vee-validate/dist/rules)|(vue-picture-input/PictureInput.vue))'
],
setupFiles: [
'./tests/unit/jest.setup.js'
],
reporters: ['default', 'jest-junit'],
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!src/**/Application/*.js'
],
testPathIgnorePatterns: [
'<rootDir>/node_modules/',
'<rootDir>/vendor/',
'<rootDir>/web/'
],
coverageThreshold: {
global: {
branches: process.env.COVERAGE_THRESHOLD_GLOBAL_BRANCH || 37,
functions: process.env.COVERAGE_THRESHOLD_GLOBAL_FUNCTIONS || 40,
lines: process.env.COVERAGE_THRESHOLD_GLOBAL_LINES || 50
}
}
}

Nuxt: Module should export a function: #turf/helpers [ERROR]

Does anyone know why am I getting Module should export a function: #turf/helpers when I add #turf/helpers to my buildModules in nuxt.config.js?
nuxt.config.js
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
// https://go.nuxtjs.dev/tailwindcss
'#nuxtjs/tailwindcss',
'#turf/helpers'
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
],
Am I adding the module to the wrong array?
FYI: the module is present within my package.json / dependencies. Thus, the installation went through.
// Component where import { point } from '#turf/helpers' returns undefined
<script>
import { defineComponent } from '#vue/composition-api';
import mapboxgl from 'mapbox-gl';
import { point } from '#turf/helpers'
export default defineComponent({
data () {
return {
geojson: {
'type': 'FeatureCollection',
'features': []
},
map: null,
}
},
mounted() {
this.initMapBox();
},
methods: {
// Initialize MapBox map
initMapBox: function() {
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxleGFuZHJ1YW5hIiwiYSI6ImNrZTl3NzJ3bzIxNG4yc2w2aG03dHNkMDUifQ.xaSxrVMLZtfGAlWoGvB1PQ';
this.map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/alexandruana/cksxeq0637zjy17tcvd4h919d',
center: [22.253, 45.419],
zoom: 4
});
this.map.on('load', () => {
console.log('Map loaded.')
let point = point([22.253, 45.419]);
console.log(point)
this.map.addSource('points', {
type: 'geojson',
data: this.geojson
});
this.map.addLayer({
id: 'points',
type: 'circle',
source: 'points',
paint: {
'circle-radius': 8,
'circle-color': '#00a9e2'
},
filter: ['in', '$type', 'Point']
});
});
},
}
})
Importing it as a regular NPM package and using it without colliding with the same variable name fixed the issue!
Indeed, this was not a Nuxt module.

Why vue-jest doesn't install Bootstrap-vue correctly in my test file?

Thank you by advance for your answer !!
Here my problem : i want to do unit test with Jest.
And i test my component ( a login form) and i use in this component : Bootstrap-vue.
So in my test file, i include Bootrap-vue, createLocalVue from vue-test-utils.
But i get an error :
TypeError: Cannot read property 'installed' of undefined
12 | Vue.use(Vuetify);
13 | localVue.use(VueAxios,axios);
> 14 | localVue.use(BootstrapVue);
| ^
15 | localVue.use(IconsPlugin);
16 |
17 |
at Function.use (node_modules/#vue/test-utils/dist/vue-test-utils.js:13742:16)
at Object.<anonymous> (test/unit/specs/components/form/login.spec.js:14:10)
Here my file login.spec.js (test file) :
import 'es6-promise/auto';
import Vue from 'vue';
import Vuetify from 'vuetify';
import axios from 'axios';
import VueAxios from 'vue-axios';
import { shallowMount, createLocalVue, mount } from '#vue/test-utils';
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';
import FormLogin from '#/components/Form/login';
const localVue = createLocalVue();
Vue.use(Vuetify);
localVue.use(VueAxios,axios);
localVue.use(BootstrapVue);
localVue.use(IconsPlugin);
let wrapper = null;
describe('FormLogin', () => {
beforeEach(() => {
const vuetify = new Vuetify();
wrapper = shallowMount(FormLogin,{
localVue,
vuetify
});
});
afterEach(() => {
wrapper.destroy();
});
it('contains input text',() => {
const type = wrapper.find('input').map((node) =>node.props().type);
const text = type.filter((e) => e === 'text').length === 1;
expect(text).toBe(true);
});
it('contains input password',() => {
const type = wrapper.find('input').map((node) =>node.props().type);
const password = type.filter((e) => e === 'password').length === 1;
expect(password).toBe(true);
});
it('contains button', () => {
expect(wrapper.find('button').toBe(true));
})
});
And my config files :
jest.config.js :
const path = require('path')
module.exports = {
rootDir: path.resolve(__dirname, '../../'),
setupFiles: ['setup.js'],
moduleFileExtensions: [
'js',
'json',
'vue',
'ts'
],
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/src/$1',
'vue$': "vue/dist/vue.common.js",
},
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
testPathIgnorePatterns: [
'<rootDir>/test/coverage/',
'<rootDir>/dist/',
'<rootDir>/node_modules/'
],
//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/**'
],
transformIgnorePatterns: ['node_modules/core.js','node_modules/babel-runtime','node_modules/vue',"node_modules/(?!bootstrap-vue)"]
}
.babelrc
{
"presets": [
"#babel/preset-flow",
"#babel/preset-react",
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
/*{
"modules": false,
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
}*/
]
],
"plugins": [
"transform-vue-jsx",
[
"#babel/plugin-transform-runtime",
{
"corejs": 2
}
],
"babel-plugin-styled-components",
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-syntax-import-meta",
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-json-strings",
"transform-class-properties",
"syntax-class-properties",
[
"#babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"#babel/plugin-proposal-function-sent",
"#babel/plugin-proposal-export-namespace-from",
"#babel/plugin-proposal-numeric-separator",
"#babel/plugin-proposal-throw-expressions"
]
}
I searched for more 1 week but i did'nt find the same problem of mine. Or it wasn't the good solution. I tried to delete my node_modules and to re-install and it is the same problem.
I thank you for your answer.
Have a good day !!

Exporting Vue components as npm module

I have problem to make Vue component export work properly.
I can export the component successfully and when I try to import it in different project I get this error:
[Vue warn]: Failed to mount component: template or render function not defined.
This is the Webpack config that I use for export:
const webpack = require('webpack');
const path = require('path');
const utils = require('./utils');
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
var config = {
entry: path.resolve(__dirname + '/../src/components/index.js'),
output: {
path: path.resolve(__dirname + '/../dist/timer-comp/'),
filename: 'timer-component.js',
},
resolve: {
extensions: ['.vue', '.js', '.json']
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
]
},
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
sourceMap: false,
mangle: true,
compress: {
warnings: false
}
})
]
};
module.exports = config;
This is the code that I use to export the components:
import TimerComponent from './timer-component';
export {
TimerComponent,
};
And finally the component code:
<template>
<div>
<div class="time">{{time}}</div>
</div>
</template>
<script>
export default {
name: 'TimerComponent',
data() {
return {
time: ''
};
},
created() {
setInterval(() => {
let now = new Date();
this.time = now.getHours() + " : " + now.getMinutes() + " : " + now.getSeconds();
}, 1000);
}
}
</script>
<style scoped>
</style>
Does someone have a clue why I get this error Failed to mount component ?
by the way this is how I call the component in a different project:
import TimerComponent from 'timer-comp';
It seems that the issue is caused by the build somehow, but I can't figure out what could be the exact problem.
add output property in production webpack config file:
output: {
path: path.resolve(__dirname + '/../dist/timer-comp/'),
filename: 'timer-component.js',
libraryTarget: 'umd',
libraryExport: 'default',
library: 'TimerComponent',
umdNamedDefine: true
}

Cannot Find Children When Using Enzyme JS Mount

My expectation is that when I use Enzyme's mount function, I should be able to not only query for nodes in the top level element, but also nodes/elements that are rendered in child components.
Here are the tests exhibited in the matter:
import React from 'react';
import chai from 'chai'
import chaiEnzyme from 'chai-enzyme'
chai.use(chaiEnzyme());
const expect = chai.expect;
import {
shallow,
mount
} from 'enzyme';
class Child extends React.Component {
render() {
return <div id='child'>
CHILD
<button onClick={() => console.log('hit me')}>HIT ME</button>
</div>
}
}
class Parent extends React.Component {
render() {
return <div id='root'>
<Child aprop={1}/>
</div>
}
}
describe('example', function() {
describe('mounted', function() {
it('should find the button', function() {
const wrapper = mount(<Parent/>);
expect(wrapper.find('button').length).to.equal(1);
});
it('should find Child component', function() {
const wrapper = mount(<Parent/>);
console.log(wrapper.debug());
expect(wrapper.find(Child).length).to.equal(1);
});
});
describe('shallow', function() {
it('should not find the button', function() {
const wrapper = shallow(<Parent/>);
expect(wrapper.find('button').length).to.equal(0);
});
it('should find Child component', function() {
const wrapper = shallow(<Parent/>);
expect(wrapper.find(Child).length).to.equal(1);
});
});
});
The output is:
example
mounted
✗ should find the button
expected 0 to equal 1
AssertionError#webpack:///~/assertion-error/index.js?6193**:74:0 <- test/components/mount.spec.js:373:25
assert#webpack:///~/chai/lib/chai/assertion.js?fee1**:107:0 <- test/components/mount.spec.js:4705:32
assertEqual#webpack:///~/chai/lib/chai/core/assertions.js?b343**:487:0 <- test/components/mount.spec.js:5222:19
webpack:///~/chai/lib/chai/utils/addMethod.js?ca90**:41:0 <- test/components/mount.spec.js:4292:31
webpack:///test/components/mount.spec.js:35:53 <- test/components/mount.spec.js:153:54
LOG LOG: '<Parent />'
✗ should find Child component
expected 0 to equal 1
AssertionError#webpack:///~/assertion-error/index.js?6193**:74:0 <- test/components/mount.spec.js:373:25
assert#webpack:///~/chai/lib/chai/assertion.js?fee1**:107:0 <- test/components/mount.spec.js:4705:32
assertEqual#webpack:///~/chai/lib/chai/core/assertions.js?b343**:487:0 <- test/components/mount.spec.js:5222:19
webpack:///~/chai/lib/chai/utils/addMethod.js?ca90**:41:0 <- test/components/mount.spec.js:4292:31
webpack:///test/components/mount.spec.js:41:50 <- test/components/mount.spec.js:159:51
shallow
✓ should not find the button
✓ should find Child component
Either mount is not working as expected, or my understanding isn't correct.
Here is my Karma/Webpack file if it helps:
const webpack = require('webpack');
var argv = require('yargs').argv;
var path = require('path');
let srcPath = path.join(__dirname, '/../src/');
const webpackConfig = {
devtool: 'inline-source-map',
resolve: {
// allow us to import components in tests like:
// import Example from 'components/Example';
root: path.resolve(__dirname, './src'),
// allow us to avoid including extension name
extensions: ['', '.js', '.jsx', '.css', '.scss', '.json'],
// required for enzyme to work properly
alias: {
'sinon': 'sinon/pkg/sinon',
}
},
module: {
// don't run babel-loader through the sinon module
noParse: [
/node_modules\/sinon\//
],
isparta: {
embedSource: true,
noAutoWrap: true,
// these babel options will be passed only to isparta and not to babel-loader
babel: {
presets: ['es2015', 'stage-0', 'react']
}
},
// run babel loader for our tests
loaders: [
{
test: /\.(js|jsx)$/,
loader: 'babel',
exclude: path.resolve(__dirname, 'node_modules'),
query: {
plugins: ['transform-decorators-legacy'],
presets: ['es2015', 'airbnb', 'stage-1', 'react']
}
},
{
test: /\.json$/, loader: 'json'
},
{
test: /\.scss$/,
exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[local]',
'postcss',
'sass'
]
},
{
test: /\.css$/,
exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[local]'
]
}
],
preLoaders: [ { //delays coverage til after tests are run, fixing transpiled source coverage error
test: /\.(jsx|js)$/,
include: path.resolve('src/'),
loader: 'isparta',
} ]
},
plugins: [
new webpack.IgnorePlugin(/node-fetch/)
],
// required for enzyme to work properly
externals: {
'jsdom': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': 'window',
'react/addons': true
},
};
module.exports = function(config) {
config.set({
browsers: ['PhantomJS'],
singleRun: !argv.watch,
frameworks: ['mocha', 'chai'],
reporters: ['spec', 'coverage'],
// include some polyfills for babel and phantomjs
files: [
'node_modules/whatwg-fetch/fetch.js',
'node_modules/babel-polyfill/dist/polyfill.js',
'./node_modules/phantomjs-polyfill/bind-polyfill.js',
'test/**/*.js'
],
preprocessors: {
// add webpack as preprocessor
'src/**/*.js': ['webpack', 'sourcemap'],
'test/**/*.js': ['webpack', 'sourcemap']
},
// A lot of people will reuse the same webpack config that they use
// in development for karma but remove any production plugins like UglifyJS etc.
// I chose to just re-write the config so readers can see what it needs to have
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
coverageReporter: {
dir: 'coverage/',
reporters: [
{ type: 'html' },
{ type: 'text' }
]
},
// tell karma all the plugins we're going to be using to prevent warnings
plugins: [
'karma-mocha',
'karma-chai',
'karma-webpack',
'karma-phantomjs-launcher',
'karma-spec-reporter',
'karma-sourcemap-loader',
'karma-coverage'
]
});
};