I've gotten the basic setup for unit testing VueJS with Jest configured, and have successfully tested other components in a similar fashion, but for one particular file I'm importing the file to be tested and it's being logged as undefined.
/* Test */
import transition from '#/components/mixins/transition'
/* The '#' aliases the src directory which has been validated
for other components */
describe('transition mixin', () => {
it('should invoke transition correctly', () => {
console.log('transition: ', transition)
/* logs transition: undefined when suite is run */
})
})
Directory structure:
src
-components
--mixins
---transition.js
This is what transitions.js looks like:
/* transitions.js, not much to see here */
export const transition = {
props: {...},
computed: {...},
methods: {...}
}
Here is the jest.conf.js file although there's nothing here (to me) that suggests the transition.js mixin file to be tested would be excluded:
/* jest.conf.js */
const path = require('path')
module.exports = {
rootDir: path.resolve(__dirname, '../../'),
browser: true,
moduleFileExtensions: [
'js',
'json',
'vue'
],
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/src/$1'
},
transform: {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
},
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
setupFiles: ['<rootDir>/test/unit/setup'],
coverageDirectory: '<rootDir>/test/unit/coverage',
collectCoverage: true,
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!src/main.js',
'!src/router/index.js',
'!**/node_modules/**'
]
}
Related
First time writing tests in typescript for my expo project. I've got some errors in my Typescript (the actual typing), but the functionality works. When I run my tests, ts-jest doesnt allow the tests to run since the types are incorrect (even though the functionality works). Is there some setting to allow ts-jest to run regardless of type errors?
App.test.tsx
import React from "react";
import renderer from "react-test-renderer";
import SignUp from "../screens/Auth/screens/SignUp";
describe("<App />", () => {
it("has 1 child", () => {
const tree = renderer.create(<SignUp />).toJSON();
console.log(tree);
});
});
jest.config.js
const { defaults: tsjPreset } = require("ts-jest/presets");
/** #type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: "react-native",
transform: {
"^.+\\.jsx$": "babel-jest",
"^.+\\.tsx?$": [
"ts-jest",
{
tsconfig: "tsconfig.spec.json",
},
],
},
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
};
babel.config.js
/** #type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
}
So I'm using vite to build my Vue 3 application for a legacy website which still uses jQuery and a few other JS frameworks.
I'm using the esm bundler as I would still like to boot it up and use it with slotted components.
<div id="app">
<vue-component-name></vue-component-name>
</div>
And it works perfectly. But when jQuery is used on the page, no where near my components it seems the esm bundled version of Vue has set a global variable named $ which breaks jQuery.
Has anyone had this issue or know of a way to fix it?
import { defineConfig } from 'vite';
import type { UserConfig as VitestUserConfigInterface } from 'vitest/config';
import svgLoader from 'vite-svg-loader';
import vue from '#vitejs/plugin-vue';
import path from 'path';
const vitestConfig : VitestUserConfigInterface = {
test: {
globals: true,
include: ['./tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
};
export default defineConfig({
test: vitestConfig.test,
plugins: [vue(), svgLoader()],
base: '/',
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
'#': path.resolve(__dirname, '/src'),
},
},
build: {
outDir: '../wwwroot/dist',
emptyOutDir: true,
manifest: true,
rollupOptions: {
input: {
main: './src/main.ts',
},
output: {
entryFileNames: 'assets/js/[name].js',
chunkFileNames: 'assets/js/[name].js',
assetFileNames: ({ name }) => {
if (/\.(gif|jpe?g|png|svg)$/.test(name ?? '')) {
return 'assets/images/[name][extname]';
}
if ((name ?? '').endsWith('.css')) {
return 'assets/css/[name][extname]';
}
return 'assets/[name][extname]';
},
globals: {
vue: 'Vue',
},
},
},
},
server: {
hmr: {
protocol: 'ws',
},
},
});
EDIT:
More information, I've tracked this down to using
#input="handleInput($event.target, index)"
This right here breaks existing jQuery. Still no idea how to get around it
For anyone interested, How to wrap Vite build in IIFE and still have all the dependencies bundled into a single file?
I have a typescript project and I setup aliases in ts.config.json
{
"compilerOptions": {
"paths": {
"#pkg/*": ["./packages/*"],
},
}
}
in my ts files I can shorten my import paths
// example.ts
import {someThing} from '#pkg/mypackage'
it works fine with tsc and vscode can recognize the alias path correctly.
but when I run npm t whitch runs jest it fails
Cannot find module '#pkg/mypackage' from 'example.ts'
jest.config.js
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
transform: {
"^.+\\.tsx?$": "ts-jest",
},
};
I added this to my package.json file
"jest": {
"moduleNameMapper": {
"#pkg/(.*)": "<rootDir>/packages/$1"
}
}
I managed to use pathsToModuleNameMapper, but I had this issue
https://github.com/kulshekhar/ts-jest/issues/2709
I had the same problem, but managed to get it working by using a couple of plugins. I also have some extra matchers at the end for some additional test types.
My Jest-base.config.js has the tsconfig-paths-jest plugin installed and running. This plugin solved my tsconfig path issues.
I use a common base file for common configuration between unit tests and end to end tests, both of which I run via Jest currently.
jest-base.config.ts
const tsconfig = require('./tsconfig.json');
const moduleNameMapper = require('tsconfig-paths-jest')(tsconfig);
module.exports = {
moduleNameMapper,
preset: 'ts-jest',
testEnvironment: 'node',
rootDir: './',
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/**/*.ts',
'!<rootDir>/**/*.interface.ts',
'!<rootDir>/**/*.mock.ts',
'!<rootDir>/**/*.module.ts',
'!<rootDir>/**/__mock__/*',
'!<rootDir>/src/main.ts'
],
coverageProvider: 'v8',
coverageReporters: [
'clover',
'json',
'lcov',
'text',
'text-summary'
],
resetModules: true,
setupFiles: [
'dotenv/config'
],
// Add the community jest-extended matchers
setupFilesAfterEnv: [
'jest-extended'
],
verbose: false
};
My jest.config.js (for unit tests) will extend my jest-base.config.js to add unit test specific code such as coverage requirements, where to store output for coverage etc.
jest.config.js
const JestBaseConfiguration = require('./jest-base.config');
module.exports = Object.assign(JestBaseConfiguration, {
moduleFileExtensions: ['js', 'json', 'ts'],
testRegex: '.e2e-spec.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest'
},
...
The problem
I created the frontend of a project in Vue2. I used a plugin called 'vue-svg-inline-loader' to convert my svg images to inline svg code. In order to get the script to work I had to add this config code to my vue.config.js.
The team has now implemented the frontend on the backend (Laravel) using Laravel-mix. This broke my "vue-svg-inline-loader" as it does not have the config anymore to figure out what to target.
Code that I've tried
I read a lot of questions and answers on StackOverflow but this kind of configuration seem so vast I cannot seem to put my finger on how shoul I write it. I believe that from my attempt, I am missing the rule(vue) from my previous file and the use("vue-svg-inline-loader") which was pointing to the plugin.
My previous vue.config.js which was working
module.exports = {
css: {
loaderOptions: {
sass: {
data: `#import "#/css/all.scss";`
}
}
},
chainWebpack: config => {
config.module
.rule("vue")
.use("vue-svg-inline-loader")
.loader("vue-svg-inline-loader")
.options({ /* ... */ });
}
}
My attempt at webpack.mix.js
mix.webpackConfig({
module : {
rules : [
'vue',
{
use : [
'vue-svg-inline-loader',
{
loader: 'vue-svg-inline-loader',
options : {}
},
]
},
]
},
});
Updates
Update 26 Aug: I managed to get in touch with the dev of vue-svg-inline-loader. We worked on some leads and managed to get to this:
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.copy('resources/assets', 'public/assets', true)
.webpackConfig({
module: {
rules: [
{
use: [
{
loader: "vue-svg-inline-loader",
options: {
inline: {
keyword: "svg-inline",
strict: true
}
}
}
]
}
]
}
});
With this it loads all the SVGs properly but it does not load any img that uses an image in a different format than SVG. I thought it's a rule or a test problem, therefore I added test: /\.vue$/,. With this I encountered errors of missing vue-loader so I added vue-loader as well. With vue-loader declared, the code compiled. When I accessed the app only a blank page returned along with the following console error:
[Vue warn]: Failed to mount component: template or render function not defined.
The final, not working code looks like:
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.copy('resources/assets', 'public/assets', true)
.webpackConfig({
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: "vue-loader",
options: { /* ... */ }
},
{
loader: "vue-svg-inline-loader",
options: {
inline: {
keyword: "svg-inline",
strict: true
}
}
}
]
}
]
}
});
Managed to get to a solution along with the Laravel Mix team. I have also informed the developer of vue-svg-inline-loader and this solution should be now featured in their documentation.
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css')
.copy('resources/assets', 'public/assets', true)
.override(config => {
config.module.rules.push({
test: /\.vue$/,
use: [{ loader: 'vue-svg-inline-loader' }]
})
});
I'm trying to integrate Lit-element into brunch. However, it seems like Babel plugin doesn't try to compile the lit-element module into the output, as it still use the original ES6 syntax of import / export.
Here's my brunch config :
`
exports.config = {
// See http://brunch.io/#documentation for docs.
files: {
javascripts: {
// joinTo: 'js/app.js'
joinTo: {
'js/app.js': [
/^node_modules/,
/\app.js$/
],
'js/editor.js': [
/\editor.js$/
],
'js/select.js': [
/select.js$/,
]
}
},
stylesheets: {
joinTo: 'css/app.css',
order: {
after: ['../priv/static/css/app.scss'] // concat app.css last
}
},
templates: {
joinTo: 'js/app.js'
}
},
conventions: {
// This option sets where we should place non-css and non-js assets in.
// By default, we set this to '/web/static/assets'. Files in this directory
// will be copied to `paths.public`, which is 'priv/static' by default.
assets: /^(web\/static\/assets)/
},
// Phoenix paths configuration
paths: {
// Dependencies and current project directories to watch
watched: [
'static', 'css', 'js', 'vendor'
],
// Where to compile files to
public: '../priv/static'
},
// Configure your plugins
plugins: {
babel: {
// Do not use ES6 compiler in vendor code
},
sass: {
mode: 'native'
},
uglify: {
mangle: false,
compress: {
global_defs: {
DEBUG: false
}
}
}
},
modules: {
autoRequire: {
"js/app.js": ["js/app"]
}
},
npm: {
enabled: true
}
}
Here is my app.js code
import {LitElement, html} from '#polymer/lit-element'
function autoComplete(options){ ... }
export var App = {
autoComplete
}
And last is the compiled code, along with console log :
...
require.register("#polymer/lit-element/lit-element.js", function(exports, require, module) {
require = __makeRelativeRequire(require, {}, "#polymer/lit-element");
(function() {
import { PropertiesMixin } from '#polymer/polymer/lib/mixins/properties-mixin.js';
// "Uncaught SyntaxError: Unexpected token {" on above line
import { camelToDashCase } from '#polymer/polymer/lib/utils/case-map.js';
import { render } from 'lit-html/lib/shady-render.js';
export { html, svg } from 'lit-html/lib/lit-extended.js';
...