jest coverageDirectory configuration for project inside monorepo - jestjs

I have a typescript monorepo with jest. Their jest.config.js is
module.exports = {
clearMocks: true,
projects: ['<rootDir>/packages/**/jest.config.js'],
collectCoverage: true,
coverageReporters: [
"text-summary",
"lcov",
],
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['*.spec.ts', '*.spec.tsx']
}
At the server package I create the jest.config.js with
const { name } = require('./package.json');
module.exports = {
displayName: name,
name,
'transform': {
'^.+\\.ts$': 'ts-jest'
},
collectCoverageFrom: [
'<rootDir>/src/**/*.ts'
],
coverageDirectory: '<rootDir>/packages/server/src/tests/coverage',
}
But when I run jest it creates the coverage directory at the root of my monorepo.
I just try to use coverageDirectory: '<rootDir>/src/tests/coverage',, coverageDirectory: 'src/tests/coverage', and coverageDirectory: [__dirname, 'src', 'tests', 'coverage'].join('/'), without success.
The only way I could change the path of coverage directory was to specify it at the jest.config.js of the monorepo, but with this I am unable to specify a coverage directory to each project.
Somebody knows how can I specify a different coverage directory for each project at a monorepo?

You can only specify a different coverage directory for each project if you are running jest for each product individually. If you are using a global config (the jest.config.js at the root of your monorepo) then the same coverage settings are applied across them all, including the coverage output directory.

Related

Jest - Cannot generate cobertura coverage report for my projects

I'm using jest in a monorepo. I would like to generate a Cobertura report when testing a some of my projects.
Jest.config.base.js
module.exports = {
preset: '#vue/cli-plugin-unit-jest/presets/typescript-and-babel',
transform: {
'vee-validate/dist/rules': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
'^.+\\.(ts|tsx)$': 'ts-jest',
},
testMatch: [
'**/*.(spec|test).(js|jsx|ts|tsx)',
],
testEnvironmentOptions: {
// Allow test environment to fire onload event
// See https://github.com/jsdom/jsdom/issues/1816#issuecomment-355188615
resources: 'usable',
},
reporters: [
'default',
[
'jest-trx-results-processor',
{
outputFile: './coverage/test-results.trx',
defaultUserName: 'user name to use if automatic detection fails',
},
],
],
moduleFileExtensions: [
'js',
'ts',
'json',
'vue',
],
testURL: 'http://localhost/',
snapshotSerializers: [
'jest-serializer-vue',
],
runner: 'groups',
};
Jest.config (root)
const baseConfig = require('./jest.config.base')
module.exports = {
...baseConfig,
projects: [
'<rootDir>/apps/my-app',
'<rootDir>/apps/my-app-copy',
'<rootDir>/libs/my-lib',
],
coverageDirectory: '<rootDir>/coverage/',
};
Jest.config (my-app)
const baseConfig = require('../../jest.config.base');
const packageJson = require('./package.json');
module.exports = {
...baseConfig,
transformIgnorePatterns: [],
roots: [
'<rootDir>/src',
],
name: packageJson.name,
displayName: packageJson.name,
};
I did not paste other jest.config to save space, but they are similar.
What works
If I run jest --coverage --coverageReporters=cobertura, it will generate a Cobertura report, but all my projects will be tested.
What does not work
If I run jest --projects apps/my-app apps/my-app-copy --coverage --coverageReporters=cobertura, only test-results.trx is generated.
Question
How could I test only 2 projects out of 3, and generate a single Cobertura report for those?
I'm working on something similar in our monorepo and I was able to generate the cobertura report installing jest-junit and defining the reporters in the root jest.config like this
coverageReporters: ['html', 'text', 'text-summary', 'cobertura'],
Then I run jest --coverage

include a config file in webpack bundle

In my webpack project I want to bundle my project and include an example usage file with it. However when I bundle my project in this form
module.exports = {
entry: {
main: './src/main.js',
about: './src/pages/config.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'report' //makes this a global variable we can call from basic javascript page,
devtool: 'source-map',
devServer: {
port: 3001,
clientLogLevel: 'none',
stats: 'errors-only'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] //npm install --save-dev style-loader css-loader
}
]
},
plugins: [
new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
new HtmlWebpackPlugin({
title: 'ESS Map Learning',
}),
],
};
},
The outputted file in the dist is converted or loaded into bundled code and is unreadable as an example. I am trying to find a way to load this file so it is not changed and sits in the bundle in its original format
If you want to include an example usage file along with your bundle, you can try the following two ways:
1. use CopyWebpackPlugin
With this plugin, you can copy specific files from your source project into your output folder.
First you need to install the plugin:
npm install --save-dev copy-webpack-plugin
Then in your webpack configuration file:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin([
{
from: "path/to/some-example.js",
to: "" // leave blank if you want to keep the folder hierachy as in the source code, otherwise specify an output path
},
]),
]
}
More about the plugin:
Webpack Plugins: CopyWebpackPlugin
2. use the "Asset Modules" configuration
module.exports = {
module: {
rules: [
{
test: /example\.js/, // regex to match your source example file path
type: 'asset/resource', // files with this type will be copied to your output folder
generator: {
filename: 'examples/[name][ext]', // you can give a desired name for your output file, or webpack will defaultly name it with hash value
}
}
]
},
// rest of your webpack configuration
// ...
}
Caveats: I think webpack will never process your example file if it is not a dependency of any of your entry points (which is very likely the case). In this sense I guess using the CopyWebpackPlugin is more reliable.
More about asset modules:
Webpack Guides: Asset Management
Webpack Guides: Asset Modules

How to include only specific module in webpack without transpiling its dependencies?

I'm working with a monorepo node.js project with the following structure:
rootDir
packageA
packageB
packageC
I want to produce a bundle of packageB code using webpack and babel.js. packageA has a lot of exports however only one export is used by packageA, let's call the export utils.
When I run webpack it recognizes that packageB depends on packageA so webpack dependecnies graph now includes all modules exported by packageA in its index.js although only one is really needed. So all of the modules in packageA are being transpiled by babel.js which even includes the node_modules of packages included by files in packageA. I've run into numerous issues with transpiling node_modules with babel.js. They range from babel.js not being able to deal with non-Javascript files for which loaders do not exist, webpack not finding certain modules, having mixed esm and commonjs syntax inside some files and many others*.
Other issues could only be solved by commenting out 2 problematic modules exported by packageA.
As you can see the solution is not ideal and perhaps not sustainable for long. Is there a way to have webpack transpile packageA without transpiling its node_modules? I couldn't achieve this despite my numerous regex attempts. Below are my config files:
*I managed to solve the issue by adding modules: "commonjs" in babel config however this will disable webpack tree shaking mechanism which means that I need to use a separate babelrc for my project.
webpack.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'development',
target: 'node',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
devtool: 'source-map',
plugins: [
new webpack.IgnorePlugin(/^(hiredis|transifex)$/)
],
module: {
rules: [
{
test: /node_modules\/datauri\/index\.js$/,
loaders: ['shebang-loader', 'babel-loader']
},
{
test: /node_modules\/needle\/lib\/needle\.js$/,
loaders: ['file-loader', 'babel-loader']
},
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
},
include: [
path.resolve(__dirname, 'src'),
"/path/to/packageA",
"/path/to/packageC",
]
}
]
}
}
babel.config.js
module.exports = {
plugins: [
[
'#babel/plugin-proposal-decorators',
{
legacy: true
}
],
'#babel/plugin-syntax-dynamic-import',
'#babel/plugin-syntax-import-meta',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-proposal-json-strings',
'#babel/plugin-proposal-function-sent',
'#babel/plugin-proposal-export-namespace-from',
'#babel/plugin-proposal-numeric-separator',
'#babel/plugin-proposal-throw-expressions',
'#babel/plugin-proposal-export-default-from',
'#babel/plugin-proposal-logical-assignment-operators',
'#babel/plugin-proposal-optional-chaining',
[
'#babel/plugin-proposal-pipeline-operator',
{
proposal: 'minimal'
}
],
'#babel/plugin-proposal-nullish-coalescing-operator',
'#babel/plugin-proposal-do-expressions',
'#babel/plugin-proposal-function-bind'
],
presets: [
[
'#babel/preset-env',
{
targets: {
node: 'current'
},
corejs: 3,
useBuiltIns: 'usage',
modules: "commonjs"
}
],
'#babel/preset-typescript'
],
env: {
debug: {
sourceMaps: 'inline',
retainLines: true
}
}
}
UPDATE: I just noticed that I'm not ignoring node_modules in babel.config.js so I added:
ignore: [
/node_modules/
]
to my babel.config.js. This allowed me to stop using modules: 'commonjs' so I guess this did have some effect but I still get errors when trying to run the bundle, errors that resulted from transpiling node_modules for example this error.

Using paths in TypeScript in a NodeJS project

I'm trying to use the paths property in tsconfig.json in a NodeJS project.
In tsconfig.json I have something like this:
"baseUrl": ".",
"paths": {
"#myApp/server/*": [
"server/src/*"
],
"#myApp/common/*": [
"common/src/*"
]
},
Running tsc outputs all JS files as expected, but they retain the #myApp... imports. As a result, node won't run as it can't resolve all modules having as path #myApp....
I can't find a way to convert the paths I've set in tsconfig.json to a value that can be used by node. I've only found this question on SO, but it's quite outdated and it does not lead to a clean solution.
Do we have a way to transpile TS to JS in a way in which we are able to use paths?
If anyone out here is using with nodejs and tsconfig-paths. You can use the following commands to make the absolute paths work:
// With ts-node
ts-node -r tsconfig-paths/register src/main.js
// With node
node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/main.js
Got this from here:
https://github.com/dividab/tsconfig-paths/issues/61
Until today I was using tspath as suggested in the accepted answer, but I started to get some issues with relative paths having as baseUrl: '../'.
I switched to a webpack based approach, with this webpack.config.ts config:
import { TsConfigPathsPlugin } from 'awesome-typescript-loader';
import * as fs from 'fs-extra';
import { join } from 'path';
import * as webpack from 'webpack';
const packageConfig = fs.readJSONSync('./package.json', { encoding: 'utf-8' });
const externals = {};
for (const packageName in packageConfig.dependencies)
externals[packageName] = packageName;
const serverConfig: webpack.Configuration = {
entry: {
index: './src/index.ts'
},
resolve: {
extensions: ['.ts', '.js'],
plugins: [
new TsConfigPathsPlugin({ configFileName: 'tsconfig.json' })
]
},
target: 'node',
node: {
__dirname: false
},
externals,
output: {
path: join(__dirname, 'dist'),
filename: '[name].js',
library: '[name]',
libraryTarget: 'umd'
},
module: {
rules: [{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
}]
},
plugins: [
new webpack.BannerPlugin(`Copyright © 2018-${new Date().getFullYear()} BOHR. All rights reserved.`)
],
mode: 'production',
optimization: {
minimize: false
}
};
// tslint:disable-next-line:no-default-export
export default [serverConfig];
Note the imports, you will need to add few packages to use this configuration.
I've found this npm package that converts all absolute paths to relative paths: https://www.npmjs.com/package/tspath.
Running tsc will produce the files with the absolute paths (e.g. #myApp/server/my-library). Then run tspath will convert all paths to the relative path.
Why won't you just use the path module in the code and resolve the path to rest of the directories relative to the one where you started the server from?
Take a look at the line 6 in this example:
https://github.com/Farata/angulartypescript/blob/master/code-samples/Angular6/chapter12/server/rest-server-angular.ts.
The __dirname points at the directory where the server was started from, and public is a subdirectory of this directory. I didn't use the paths option of tsc.

What's the proper way to set NODE_ENV in Karma for running webpack?

I'm building my project with Webpack and using Karma for running tests.
I want to configure Karma to set process.env.NODE_ENV to "test" for Webpack to perform conditional build of the project for testing environment with URLs mapped to localhost, not production domain name.
For that purpose I make use of Webpack's env-replace-loader, which reads its configuration file environments.json and sets variables, such as API_URL, depending on the values of process.env.NODE_ENV. In production build I use Gulp to set process.env.NODE_ENV and start webpack. It works.
I want to set process.env.NODE_ENV = 'test' in testing build, initiated by running karma start karma.conf.js. Currently I just say process.env.NODE_ENV = "test" in karma.conf.js.
Is there a better way to do that?
Besides, I tried to use DefinePlugin of webpack in webpack.config.js to set this variable like this:
const webpackConfig = {
...
plugins: [
new webpack.DefinePlugin({
process.env: {'NODE_ENV': 'test'}
}),
...
],
...
}
and it won't work: webpack env-replace-loader curses that Module build failed: TypeError: Cannot read property 'URL' of undefined - I suppose, it can not access the node reports that it doesn't see
In your webpack config try this JSON.stringify('name') instead. Try something like this:
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
APP_ENV: JSON.stringify('browser')
},
})
],
That works with the webpack running a example or something like that. For example, I'm using that to require CSS when running an example but it get ignored when compiling for production.
I got the same problem with Karma config but I fix that adding the plugin into the webpack part of the Karma config file. It's my file for example:
const webpack = require('webpack');
module.exports = function(config) {
config.set({
browsers: ['PhantomJS'],
files: [
'tests.webpack.js',
{
pattern: 'src/**/__tests__/*.js',
included: false,
served: false,
watched: true
}
],
frameworks: ['jasmine'],
preprocessors: {
'tests.webpack.js': ['webpack', 'sourcemap', 'coverage'],
},
reporters: ['progress', 'notification'],
webpack: {
devtool: 'inline-source-map',
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader' }
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('test')
}
})
],
watch: true
},
webpackServer: {
noInfo: true,
}
});
};
I hope that's helpfull for you too!

Resources