How to use Vue Testing Library with Nuxt.js? - vue.js

I want to use Vue Testing Library in my Nuxt.js app. But straight after installing the package, launching a test triggers this error:
'vue-cli-service' is not recognized as an internal or external
command, operable program or batch file.
This is presumably because Nuxt.js does not use vue-cli-service.
Despite that, is there a simple way to use Vue Testing Library with Nuxt.js?

It sounds like you might have an NPM script that includes vue-cli-service (as shown below), but that's intended for Vue CLI scaffolded projects:
{
"scripts": {
"test:unit": "vue-cli-service test:unit" ❌ not for Nuxt projects
}
}
However, you could setup Vue Testing Library using one of the methods outlined below.
Setup on new project
When generating a new Nuxt project, select Jest for testing, and install Vue Testing Library on top of that:
Scaffold a Nuxt project with create-nuxt-app, and select Jest at the Testing framework prompt:
npx create-nuxt-app nuxt-testing-library-demo
Sample output:
$ npx create-nuxt-app nuxt-testing-library-demo
create-nuxt-app v3.5.2
✨ Generating Nuxt.js project in nuxt-testing-library-demo
[...]
? Testing framework: Jest
Install Vue Testing Library (v5 required for Nuxt 2):
npm install -D #testing-library/vue#5
Run tests with the test NPM script (scaffolded from step 1):
npm run test
Setup on existing Nuxt project
For an already existing Nuxt project that has no testing framework, mimic the jest template from #nuxt/create-nuxt-app to add Vue Testing Library support:
Install the prerequisite NPM packages:
npm install -D #testing-library/vue#5 \
vue-jest#^3 \
jest#^26 \
babel-core#7.0.0-bridge.0 \
babel-jest#^26
npm install -D ts-jest#^26 # if using TypeScript
For Nuxt v2, install #testing-library/vue#5.
Add an NPM script to run Jest CLI:
// <rootDir>/package.json
{
"scripts": {
"test": "jest"
}
}
Add a Jest config:
// <rootDir>/jest.config.js
module.exports = {
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: [
'ts', // if using TypeScript
'js',
'vue',
'json'
],
transform: {
"^.+\\.ts$": "ts-jest", // if using TypeScript
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
]
}
Add a Babel config:
// <rootDir>/.babelrc
{
"env": {
"test": {
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
}
}
Create a test directory, containing the example test file shown below (taken from Vue Testing Library example). Note the location of the test files can be configured with the testMatch or testRegex setting in jest.config.js.
Example component:
<!-- <rootDir>/components/Counter.vue -->
<template>
<div>
<p>Times clicked: {{ count }}</p>
<button #click="increment">increment</button>
</div>
</template>
<script>
export default {
data: () => ({
count: 0,
}),
methods: {
increment() {
this.count++
},
},
}
</script>
Example test:
// <rootDir>/test/Counter.spec.js
import {render, screen, fireEvent} from '#testing-library/vue'
import Counter from '#/components/Counter.vue'
test('increments value on click', async () => {
render(Counter)
expect(screen.queryByText('Times clicked: 0')).toBeTruthy()
const button = screen.getByText('increment')
await fireEvent.click(button)
await fireEvent.click(button)
expect(screen.queryByText('Times clicked: 2')).toBeTruthy()
})
Run tests with the test NPM script (added in step 2):
npm run test
GitHub demo

Related

Why tailwind ui not rendered correctly in vue?

I have installed tailwind according to the documentation in tailwindcss.com with vue in laravel. But its rendered like this below -
Why ?
Configuration:
Installed tailwindcss using commands
npm install -D tailwindcss
npx tailwindcss init
2)In tailwind.config.js added
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
extend: {},
},
plugins: [],
}
3)In input.css added
#tailwind base;
#tailwind components;
#tailwind utilities;
For extra plugins ran this command
npm install #headlessui/vue #heroicons/vue
In main.js:
import { createApp } from 'vue'
import store from './store'
import App from './App.vue'
import './input.css'
createApp(App)
.use(store)
.mount('#app')
Try using PostCSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
https://tailwindcss.com/docs/installation/using-postcss
on tailwind.config.js:
module.exports = {
purge:
"./src/**/*.html",
"./src/**/*.vue",
"./src/**/*.jsx",
],
//
};
it's simply adding the ones in the purge, after that, the vue is rendered properly, I think that the problem is that we haven't included vue on the tailwind configuration.
There are two tailwind.config.js files, one at the project level and the other at the vue directory. Copy and paste the following at the vue directory level
/** #type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{html,js,vue,js,ts,jsx,tsx}"
],
theme: {
extend: {},
},
plugins: [
require('#tailwindcss/forms')
],
}

TypeError: Cannot read properties of null (reading 'isCE') - Custom Component Library

I am having trouble building a custom component library for Vue 3 using ViteJS and NPM. I have included a basic illustration of my issue below, can someone please tell me what I am doing wrong or point me in the right direction, I have been stuck on this for 2 days :(.
My folder structure:
dist
node_modules
src
components
Paragraph.vue
paragraph.js
.gitignore
package.json
README.md
vite.config.js
package.json
{
"name": "paragraph",
"private": true,
"version": "0.0.0",
"description": "The paragraph test component.",
"main": "./dist/paragraph.umd.js",
"module": "./dist/paragraph.es.js",
"exports": {
".": {
"import": "./dist/paragraph.es.js",
"require": "./dist/paragraph.umd.js"
},
"./dist/style.css": "./dist/style.css"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.25"
},
"devDependencies": {
"#vitejs/plugin-vue": "^2.3.1",
"vite": "^2.9.5"
}
}
vite.config.js
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
build: {
lib: {
entry: fileURLToPath(new URL('./src/paragraph.js', import.meta.url)),
name: 'Paragraph',
fileName: (format) => `paragraph.${format}.js`,
},
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
},
},
},
},
plugins: [vue()],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url))
},
},
})
paragraph.js
import Paragraph from './components/Paragraph.vue';
export default {
install: (app) => {
app.component('Paragraph', Paragraph);
},
};
Paragraph.vue
<script setup>
console.log('Test');
</script>
<template>
<p class="paragraph">
<slot />
</p>
</template>
<style>
.paragraph
{
color: black;
}
</style>
When I run npm run build it works successfully and creates the correct files, I then include the es file into my test Vue project as a plugin.
import { createApp } from 'vue'
import App from './App.vue'
import Paragraph from '../../paragraph/dist/paragraph.es.js'
createApp(App).use(Paragraph).mount('#app')
The component doesn't work when used liked this.
<Paragraph>Hello World 2!</Paragraph>
The following error is reported back in the console.
TypeError: Cannot read properties of null (reading 'isCE')
I have looked into the issue and it seems a lot of people have had the same issue, although I cannot find a fix for myself.
I have tried the solutions mentioned in the following links:
https://github.com/vuejs/core/issues/4344
When Importing Self Made Vue 3 Library Into Vue 3 Project: "Uncaught TypeError: Cannot read properties of null (reading 'isCE')"
Neither of the solutions mentioned here are working.
Can someone please help!!!
I have noticed if I exclude the <slot /> it works fine, but slots are vital to components.
I know it is bundling the Vue code into the build file, but how do I stop it doing so.
Thanks in advance.
I've also encountered this very frustrating issue. According to this answer, it is caused by having Vue imported from multiple packages instead of using just one singleton, as you do suspect.
Presumably, you are building your consumer application using Vite. In that case, setting the dedupe option in its vite.confg.js should solve it.
resolve: {
dedupe: [
'vue'
]
},
I've also encountered this issue :) the problem is you have two distinct copies of the Vue package being used
just read this and you will find your answer. for me, changing the workspace to yarn was the solution.
https://github.com/vuejs/core/issues/4344
Try to remove node_modules + yarn.lock
And then reinstall packages (yarn)

Got error when testing vue-echarts component with Jest

I have problem with component testing when using 'vue-echarts'
InfoBoard.spec.ts
import { render } from '#testing-library/vue'
import InfoBoard from '#/components/InfoBoard.vue'
describe('InfoBoard', () => {
test('Should be truthy', () => {
const wrapper = render(InfoBoard, {
stubs: {
'v-charts': true
},
})
expect(wrapper).toBeTruthy()
})
})
InfoBoard.vue
<template>
<div>
<v-chart></v-chart>
</div>
</template>
<script>
import { defineComponent } from '#nuxtjs/composition-api'
import VChart from 'vue-echarts'
export default defineComponent({
components: {
VChart
},
setup() {}
})
</script>
jest.config.js
module.exports = {
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: [
'ts',
'js',
'vue',
'json'
],
transform: {
"^.+\\.ts$": "ts-jest",
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
],
transformIgnorePatterns: [
"<rootDir>/node_modules/(?!echarts)",
"<rootDir>/node_modules/(?!echarts\/core)",
"<rootDir>/node_modules/(?!vue-echarts)"
],
testEnvironment: 'jsdom',
setupFilesAfterEnv: ["./jest-setup.js"]
}
Got Error:
FAIL components/InfoBoard.spec.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/admin/Documents/THIP/node_modules/echarts/core.js:20
export * from './lib/export/core';
^^^^^^
SyntaxError: Unexpected token 'export'
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1479:14)
at Object.<anonymous> (node_modules/vue-echarts/dist/index.cjs.min.js:1:179)
I think the problem is in 'transformIgnorePatterns', maybe I write wrong patterns.
I searching for many day, I tried many anwser like change 'testEnviroment' or add plugin in .babelrc but don't found the solution.
I ran into the same problem and was just able to get it working by adding the following setting to my jest.config.js:
module.exports = {
transformIgnorePatterns: ["/node_modules/(?!(echarts|zrender)/)"],
}
If you wrote your configuration as provided here, I assume you wouldn't have to include the root directory in the ignore-pattern. It didn't work either when having more than one ignore-pattern; but this might be because of the way I wrote the ignore-pattern.

Using lang="pug" with Quasar CLI

I've started a brand new Quasar CLI project and I'd like to use Pug in the way I'm used to doing: incorporating a lang="pug" tag in some of my .vue files:
<template lang="pug">
q-page(class="flex flex-center")
p Well hello there
...
This throws this error:
Component template requires a root element, rather than just text
The advice given by Quasar is to add this configuration:
// quasar.conf.js
build: {
extendWebpack (cfg) {
cfg.module.rules.push({
test: /\.pug$/,
loader: 'pug-plain-loader'
})
}
}
But that presupposes that all my pug files are in files called .pug, which isn't my preference.
Is there a way to have lang="pug" work like normally in my vue-cli projects?
Quasar CLI........ v0.17.24
Quasar Framework.. v0.17.20
This should work as it is. I have set up a new quasar project and added pug to the webpack rules like so
extendWebpack (cfg) {
cfg.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/
})
cfg.module.rules.push({
test: /\.pug$/,
loader: 'pug-plain-loader'
})
}
My app.vue looks like this
<template lang="pug">
div(id="q-app")
router-view
</template>
And everything works. Im using quasar 1.0 beta and its the default project format created when you create using the CLI.
In my case Ben solution didn't work: what I figured out was to setup that block as follows, in the quasar.conf.js file:
extendWebpack (cfg) {
cfg.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/
})
},
chainWebpack (chain) {
chain.module.rule('pug')
.test(/\.pug$/)
.use('pug-plain-loader')
.loader('pug-plain-loader')
}
With that, I just require to add the atribute lang="pug" in any template where I use the pug syntax.
Ben's solution triggered me a lot of errors with existing Vue files, and js files.

Usage webpack with bower

I have a basic ReactJS application. I use webpack and would like to use moduls from bower. I installed bower-webpack-plugin and add jquery library in bower.
webpack.config.js
var BowerWebpackPlugin = require("bower-webpack-plugin");
var webpack = require("webpack");
module.exports = {
entry: './index.jsx',
output: {
filename: 'bundle.js',
publicPath: 'http://localhost:8090/assets'
},
module: {
loaders: [
{
//tell webpack to use jsx-loader for all *.jsx files
test: /\.jsx$/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony'
}
]
},
plugins: [
new BowerWebpackPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
})
],
externals: {
//don't bundle the 'react' npm package with our bundle.js
//but get it from a global 'React' variable
'react': 'React'
},
resolve: {
extensions: ['', '.js', '.jsx'],
alias: {
jquery: "./bower_components/jquery/dist/jquery.js"
}
}
}
Edit: Now I am using this webpack config with bower dependencies and without bower-webpack-plugin
bower.json
{
"name": "jquery",
"version": "2.1.4",
"main": "dist/jquery.js",
"license": "MIT",
"ignore": [
"**/.*",
"build",
"dist/cdn",
"speed",
"test",
"*.md",
"AUTHORS.txt",
"Gruntfile.js",
"package.json"
],
"devDependencies": {
"sizzle": "2.1.1-jquery.2.1.2",
"requirejs": "2.1.10",
"qunit": "1.14.0",
"sinon": "1.8.1"
},
"keywords": [
"jquery",
"javascript",
"library"
]
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>Basic Property Grid</title>
<!-- include react -->
<script src="./node_modules/react/dist/react-with-addons.js"></script>
</head>
<body>
<div id="content">
<!-- this is where the root react component will get rendered -->
</div>
<!-- include the webpack-dev-server script so our scripts get reloaded when we make a change -->
<!-- we'll run the webpack dev server on port 8090, so make sure it is correct -->
<script src="http://localhost:8090/webpack-dev-server.js"></script>
<!-- include the bundle that contains all our scripts, produced by webpack -->
<!-- the bundle is served by the webpack-dev-server, so serve it also from localhost:8090 -->
<script type="text/javascript" src="http://localhost:8090/assets/bundle.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("body").append("This is Hello World by JQuery");
});
</script>
</body>
</html>
When I open main page, I get error message: "$ is not defined".
project structure
First, maybe you just forgot, but to be sure, I want to point out that it seems you showed us the jquery bower.json file in your question.
Your project doesn't actually seem to have a bower.json file at its root.
If you want to use Bower to manage dependencies, make sure you have a bower.json by running bower init at the root of your project and then run for instance bower install --save jquery.
See the bower doc for more info ;)
Besides that, the problem is that you're trying to use jQuery in index.html, so not in a webpack-managed module.
Webpack is not actually processing anything on your index.html.
What I mean is, put your jQuery code in index.jsx, instead of putting it in index.html:
// index.jsx
$(document).ready(function(){
$("body").append("This is Hello World by JQuery");
});
And it should work!
You can also remove this code, since the BowerWebpackPlugin handles that for you:
alias: {
jquery: "./bower_components/jquery/dist/jquery.js"
}
How does it work?
index.jsx is loaded through Webpack.
$ is used as a free variable, but thanks to the ProvidePlugin, it will resolve to require("jquery")
require("jquery") resolves to import jQuery from the bower components folder
thanks to the BowerWepackPlugin.
Without the ProvidePlugin and only the BowerWebpackPlugin, you would have had to write:
// index.jsx
var $ = require("jquery");
$(document).ready(function(){
$("body").append("This is Hello World by JQuery");
});
add a resolve field:
resolve: {
alias: {
jquery:"/your/path/to/jquery"
}
}
and add this to your plugin:
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
})
]
hope it helped