Why is my Jest code coverage report invalid? - javascript

When I generate a Jest code coverage report for my Vue 2.7.X app, the lines shown as covered/uncovered in the report don't make any sense:
The red sections in this report should indicate code that's not covered (executed) by the test suite, but obviously it makes no sense to show comments (lines 290, 291) as uncovered, or to show (part of) line 298 as uncovered when the lines before and after are covered.
I guess what's happening is that the lines which Jest detects as uncovered are not being correctly mapped back to the source code, so there may be a problem with the Babel transpilation.
I generate the code coverage report with yarn jest --coverage and the application source code is written in JavaScript (rather than TypeScript).
some of the dependencies from package.json which may be relevant to the problem are shown below:
"devDependencies": {
"#babel/core": "^7.20.5",
"#babel/preset-env": "^7.20.2",
"#vue/test-utils": "1.3.3",
"#vue/vue2-jest": "29.2.2",
"#vitejs/plugin-vue2": "^2.2.0",
"babel-jest": "^29.3.1",
"http-proxy": "^1.18.1",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"sass": "1.32.13",
"sass-lint": "^1.13.1",
"start-server-and-test": "^1.14.0",
"unplugin-vue-components": "^0.22.12",
"vite": "^4.0.1",
"vite-plugin-rewrite-all": "^1.0.1",
"vue-template-compiler": "^2.7.14"
}
Minimum Reproducible Example
I've created a minimal Git repo that demonstrates the problem.
Clone the repo
Run yarn install && yarn test:unit:coverage to generate the coverage report (or use npm instead)
Open the file coverage/lcov-report/index.html to see the report
If you open the page for components/toaster-message.vue, it says 1/2 branches and 2/3 functions are covered, but none of the lines are marked in red (hideAppMessage should be red because it's not tested).
If you open the page for views/login.vue the lines that are marked in red (uncovered) don't make any sense. There are no tests for this component.

What worked for me was adding coverageProvider: 'v8' to the jest.config.js. I'm not entirely sure why changing coverageProvider works, but seems like vue-jest is having general problems with collecting coverage correctly due to babel dependency changes.
Try adding this to your Jest configuration:
coverageProvider: 'v8'
Then npm run test:unit:coverage.
This worked on Node v16.16.0 and v18.12.1.

jest uses its own version of Babel to transpile your code, but the source map that generates it could be unnacurate or have a differrent version than the one you are using.
You can make sure that jest is using the same version of Babel that you're using in your app by adding the following configuration to your package.json file:
"jest": {
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
}
}
Also, could it be that even though your package.json has that version you have something else in the package-lock.json?

Looks like solution with coverageProvider: 'v8' added by #morganney works.
For the problem of generating a coverage report.
Failed to write coverage reports:
ERROR: Error: ENOENT: no such file or directory, open 'path\to\file\<<jsx-config-pragma.js>>.html'
Just remove the .ts("\\.(tsx|ts|jsx|js)$") files from configuration (package.json)
...
"transform": {
"\\.(tsx|jsx|js)$": [
"#swc-node/jest",
{
"dynamicImport": true
}
]
},
...

Related

How can I incorporate JS libraries into my NPM build script?

My current site is build with html+css (scss) and using a NPM build script (see below). I now want to add a few JS libraries to my website (for example: lozad).
So far I've downloaded the dependencies for it. As I'm not familiar with JS, I don't understand the other steps I need to take. I tried following the documentation but it's not working so far.
I now assume that this is because my current NPM build script doesn't track JS, so any JS wouldn't be shown on my devserver. So maybe it did work, but just not in test?
Can anyone point me in the direction of what I need to do to make it working, and/or how to update my NPM script?
"scripts": {
"watch:sass": "node-sass sass/main.scss css/style.css -w",
"devserver": "live-server --browser=firefox",
"start": "npm-run-all --parallel devserver watch:sass",
"compile:sass": "node-sass sass/main.scss css/style.comp.css",
"concat:css": "concat -o css/style.concat.css css/icon-font.css css/style.comp.css",
"prefix:css": "postcss --use autoprefixer -b 'last 10 versions' css/style.concat.css -o css/style.prefix.css",
"compress:css": "node-sass css/style.prefix.css css/style.css --output-style compressed",
"build:css": "npm-run-all compile:sass concat:css prefix:css compress:css"
},
"devDependencies": {
"autoprefixer": "^9.6.0",
"concat": "^1.0.3",
"node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"postcss-cli": "^6.1.2",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.6"
},
"dependencies": {
"aos": "^2.3.4",
"lozad": "^1.9.0",
}
}
You just need to give the relative path to the dependency and run the script like so:
"scripts": {
...
"lozad": "npm run ./node_modules/lozad/index.js --argument"
}
Note that this is only assumed data. The real path and file are probably called something else (Just look into the node:modules folder for lozad).
According to this article, you can also omit the path and the npm rum when there is a .bin folder for that dependency, but I have not tested that.
Edit
In case you meant on how to use the library locally.
You have to add the package to your dependencies (Like you did) and then call
npm install
in your project directory. It will install all your dependencies specified in package.json.
You can omit the manual "add dependency to file" step by simply calling:
npm install --save lozad
After that you can use it in your project like so:
// using ES6 modules
import lozad from 'lozad'
// using CommonJS modules
var lozad = require('lozad')
If you don't know which one to use, just try them - your IDE will tell you if something is wrong.
When you imported the library, you can use it like described at the Usage Description.

Webpack error from UglifyJS when creating production assets

I am using Webpack Encore (similar to Webpack) to create asset files.
Everything works well when creating the development files, however when running to command to generate the minified files for production I get an error.
ERROR Failed to compile with 1 errors
app.js from UglifyJS .
Invalid assignment [app.js:131,42]
Unexpected character '`' [app.js:10953,9]
It seems like the issue is caused by two plugins:
jquery-asScrollable and jquery-asScrollbar
In fact commenting out the following lines, the process completes successfully
require('jquery-asScrollable');
require('jquery-asScrollbar');
My package.json file
{
"devDependencies": {
"#symfony/webpack-encore": "^0.17.1",
"animsition": "^4.0.2",
"bootstrap": "4.0.0-beta.2",
"jquery": "^3.2.1",
"jquery-asScrollable": "^0.4.10",
"jquery-asScrollbar": "^0.5.7",
"jquery-mousewheel": "^3.1.13",
"node-sass": "^4.7.2",
"popper.js": "^1.12.9",
"sass-loader": "^6.0.6",
"webpack-notifier": "^1.5.0"
}
}
UPDATE:
app.js
require('jquery-asScrollable');
require('jquery-asScrollbar');
require('jquery-mousewheel');
Any ideas of what the problem might be?
The two plugins make use of ES6 syntax - in this case template literals. Uglify is incompatible with large parts of ES6. You need to either copy those plugins to your project code (so they get transpiled by your Babel) or un-exclude their respective node_modules folders in your Babel transpilation process.
See the template literals (and more ES6) being used here (line 90-93):
Another option is to import/require the minified versions of the plugins from their dist folders.
Example:
require('node_modules/jquery-asScrollable/dist/jquery-asScrollable.min.js')

How do I use the ES6 import function with a symbolic path to the source file?

I am trying to understand the ES6 import function better, and I need your help.
The Scenario
Let's assume that I have a subset of code within my application that is used frequently, and I arrange all that code into a folder so that it is together.
So now, in three separate files, I have something like the following (note: I'm using TypeScript, so the file names in the example end in '.ts'):
file0.ts:
import {AbstractCoreCommunicationClass} from '../../../core-packages/communication/abstract-core-communication'
file1.ts:
import {AbstractCoreCommunicationClass} from '../communication/abstract-core-communication'
file2.ts:
import {AbstractCoreCommunicationClass} from '../../../../../core-packages/communication/abstract-core-communication'
My Hope
It is my hope that I could clean up these references to something like this:
file0.ts:
import {AbstractCoreCommunicationClass} from '#my-communication-core/abstract-core-communication'
file1.ts:
import {AbstractCoreCommunicationClass} from '#my-communication-core/abstract-core-communication'
file2.ts:
import {AbstractCoreCommunicationClass} from '#my-communication-core/abstract-core-communication'
Things I have Tried
I know that in Laravel (a different framework) that modules can be created and loaded by editing one of the core loader definition files such as composer.json or the main config/app.php file.
I have looked for a similar kind of protocol that can be used in the package.json file to reference non-npm packages, but I have not found any such information. The closest information that I have found is a tutorial in which NPM explains how to use NPM private packages, which would accomplish the same goal as long as I want to pay $7/month for the rest of my life to have my package hosted on their servers.
There must be a way to handle this kind of package management locally, but I have not discovered what it is, and that is why I need YOUR help!
All help is appreciated. There are no wrong answers. Even a bad answer can sometimes point me in the right direction, so give me your thoughts and let's figure this out together so that everyone can benefit!
The solution is specific to the language and the environment. It's currently impossible to address this issue with ES modules alone.
TypeScript allows to specify paths configuration entry for path aliases.
Webpack allows to specify alias configuration entry for path aliases.
The same thing can be achieved in Rollup with a plugin.
NPM allows to specify local dependencies without a need for a repository. There's also a number of solutions for local NPM repositories, e.g. sinopia.
Given that there is TypeScript project that installs NPM dependencies and is being built with Webpack, any of listed solutions is applicable.
HOW TO USE LOCAL PACKAGES IN NPM
It turns out that NPM has a feature that allows me to do exactly what I need to do. I reread the package.json documentation after writing the question above and found that NPM now allows for a local file directory reference to a package.
How it looks in pacakge.json
I used npm to create the linkages (see next section), and then I inspected the package.json file to find the following:
"dependencies": {
"#angular/animations": "^4.0.0",
"#angular/common": "^4.0.0",
"#angular/compiler": "^4.0.0",
"#angular/core": "^4.0.0",
"#angular/forms": "^4.0.0",
"#angular/http": "^4.0.0",
"#angular/platform-browser": "^4.0.0",
"#angular/platform-browser-dynamic": "^4.0.0",
"#angular/router": "^4.0.0",
"core-js": "^2.4.1",
//###THIS IS MY NEW LINE###
"data-structures": "file:src/app/medface/data-structures",
"intl": "^1.2.5",
"ng2-cookies": "^1.0.12",
"rxjs": "^5.1.0",
"showdown": "^1.8.0",
"to-markdown": "^3.1.0",
"web-animations-js": "^2.2.5",
"zone.js": "^0.8.4"
},
Notice how the file: string prepends the source. I then designed a unit test to load one of the files from this directory using the name I assigned.
import {VisitDataStructure} from 'data-structures/visit';
describe( "The data structure package", ()=>{
fit("loads without failure and allows the user to import classes within the folder.", ()=>{
let visit = new VisitDataStructure();
expect(visit).not.toBeNull();
} );
} );
The test runs with flying colors!
(Note: the function fit is just like it, except it tells the testing system that it should "focus" only on that one test and ignore all the rest.)
How to achieve this using npm
To achieve this local package reference setup, several things must occur in order.
Step 1: Create a package using npm init
Navigate to the sub-folder in the terminal and type npm init (this assumes that you are already using npm, as I am).
Follow the on screen prompts to create your package.json file. The file will ask for a name, this name is how you will refer to the package within your system. In my case, I assigned the name 'data-structures' to the test package.
Step 2: Install the sub package using npm intall --save [pathToLocalFile]
From the root of your application, the same folder that holds the package.json file for your whole application, find the relative path to your new folder. In my case, it was src/app/medface/data-structures.
If your relative path is correct, then you should be able to use ls or dir to show a file at [relativePath]/package.json (linux/mac) or [relativePath]\package.json (windows)
Then run the command npm install --save [relativePath].
You will see npm do its thing. If it gives you an error, read the error and go back to step #1. (When I ran it the first time, I got an error and realized that I had to use npm init in the directory before I could install it).
Note: for the terminal command alternative, yes, you CAN use npm install -S [relativePath] -- it is the same command as above.
Step 3: Use your new package name in the code.
Now that it is installed, you can use the name you assigned anywhere within your code, and the package.json file will tell your pre-processor where to find the reference files.
GREAT WORK! Now go do some awesome coding!

Grunt not including javascript file

This is an angular app. I have a bower.json with a lot of libraries put like this:
"dependencies": {
"angular": "^1.4.0",
"bootstrap": "^3.2.0",
...
"angular-socket-io": "^0.7.0",
"socket.io-client": "^1.7.2"
I run
bower install
and I can see that in the "bower_components"-folder there are folders and files for both "angular-socket-io" and "socket.io-client".
When I then run this command:
grunt serve
I can see that this one is included:
<script src="bower_components/angular-socket-io/socket.js"></script>
However, I cannot find any trace of "socket.io-client". Why? Am I supposed to include this manually? I wonder why then. All the other bower cmopoenents are beeing added autmatically of "grunt serve".
PS: This causes the error "io is not defined" when I try to instantiate a socket frmo a factory.
I guess it was an issue with versions.
Im running angular 1.4.
Having this line:
"socket.io-client": "^0.7.10",
seems made the trick. Before I used latest version of socket.io-client (1.7). And I got incompatibility error.
But now the socket-client is being loaded.

setup.js is deleted in react-boilerplate when running npm run setup

I have a very strange problem. I have cloned the react-boilerplate repository from here:
https://github.com/mxstbr/react-boilerplate
I add the following dependencies:
"body-parser": "^1.15.0",
"cors": "^2.7.1",
"feathers-client": "^1.6.1",
"feathers-rest": "^1.5.0",
"material-ui": "^0.16.0-rc2",
"node-uuid": "^1.4.7",
"react-json-viewer": "^1.1.0",
"request-promise": "^4.1.1",
"rest-client": "^0.1.5",
"socket.io-client": "^1.4.8"
When I run 'npm run setup' the file internals/scripts/setup.js is deleted which means that I get an error the next time I run 'npm run setup'.
Any suggestion as to how this can happen will be appreciated.
It turns out that
npm run setup
is only intended to run once. Afterwards I assume I should
run npm install
I found out after reading this article:
https://github.com/mxstbr/react-boilerplate/issues/339
In the boiler plate you are working there will be a file setup.js that will be missing in your boilerplate and the path where it should be will be provided in the error, Copy that setup.js file from original boiler plate and paste there where it is missing. This solution worked for me perfectly

Categories

Resources