How to find aliases in Global Jest setup? - javascript

I want to run some stuff only once before all test cases. Therefore, I have created a global function and specified the globalSetup field in the jest configuration:
globalSetup: path.resolve(srcPath, 'TestUtils', 'globalSetup.ts'),
However, within globalSetup, I use some aliases # and Jest complains it does not find them.
How can I run globalSetup once the aliases have been sorted out?
My Jest configuration is as follows:
module.exports = {
rootDir: rootPath,
coveragePathIgnorePatterns: ['/node_modules/'],
preset: 'ts-jest',
setupFiles: [path.resolve(__dirname, 'env.testing.ts')],
setupFilesAfterEnv: [path.resolve(srcPath, 'TestUtils', 'testSetup.ts')],
globalSetup: path.resolve(srcPath, 'TestUtils', 'globalSetup.ts'),
globals: {},
testEnvironment: 'node',
moduleFileExtensions: ['js', 'ts', 'json'],
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/' })
};
When I run testSetup before every test, it runs ok the aliases, but this does not happen with globalSetup.
Any clue what could I do?

I managed to get this work by including tsconfig-paths/register at the top of my globalSetup file:
// myGlobalSetupFile.ts
import 'tsconfig-paths/register';
import { Thing } from './place-with-aliases';
export default async () => {
await Thing.doGlobalSetup();
}
You have to make sure you have tsconfig-paths installed in your project.

Unfortunately I have found there is no solution for this based on the comments on this issue:
https://github.com/facebook/jest/issues/6048
The summary is that globalSetup runs outside of Jest ecosystem and therefore it will not recognize the aliases, etc.
There are several workarounds, for example, if your npm run test command is something like this:
"test": "jest --config config/jest.config.js --detectOpenHandles --forceExit"
Then you can do something like:
"test": "node whateverBeforeJest.js && jest --config config/jest.config.js --detectOpenHandles --forceExit"

Related

Jest or Mocha with Vue: SyntaxError: Cannot use import statement outside a module

Edit: This post got out of hand with edits, please follow this link to a new Stackoverflow post which is clearer:
SyntaxError: Cannot use import statement outside a module when following vue-test-utils official tutorial
There are thousands of posts and threads about this issue and I still can't fix my problem.
I followed the "Getting started" portions of Jest AND Mocha and get the same error both times:
SyntaxError: Cannot use import statement outside a module but their provided link doesn't help at all.
Theres a new edit at the bottom with steps for a clean new project with jest for you to follow along which results in an error.
"vue-jest": "^3.0.7",
"vue": "^2.6.12",
"#vue/test-utils": "^1.2.2"
package.json
"mocha": "mocha 'tests/Frontend/**/*.test.js'"
example.test.js:
import { mount } from "#vue/test-utils"
import Dashboard from "../../resources/js/views/Dashboard";
import * as assert from "assert";
describe('test example', () => {
it('should work', () => {
assert.equal([1, 2, 3].indexOf(4), -1); // doesn't matter what I do here
})
})
What I've tried:
Using the --require #babel/register flag with mocha
Setting "transformIgnorePatterns": [] and thus allowing all node_modules to be considered
Adding a .babelrc file with the following content: This resulted in following error on building the app though:
Error: Multiple configuration files found. Please remove one:
- package.json
- C:\Users\f.marchi\workspace\projects\sanctum-test\.babelrc
{
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}
Can someone confirm, that those docs are missing some very important steps? I really don't know what I'm doing wrong, I'm just following the tutorials.
Edit: jest.config.js:
module.exports = {
clearMocks: true,
collectCoverage: true,
coverageDirectory: "coverage",
moduleFileExtensions: [
"js",
"json",
"vue"
],
transform: {
".*\\.(vue)$": "vue-jest"
},
transformIgnorePatterns: []
};
Edit:
I just tried again, you can follow along if you want:
vue create jest-test
npm install --save-dev jest #vue/test-utils vue-jest
Added jest config to package.json:
{
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
".*\\.(vue)$": "vue-jest"
}
}
}
npm install --save-dev babel-jest #babel/core #babel/preset-env babel-core#^7.0.0-bridge.0
Adjusted jest config to:
{
"jest": {
"transform": {
// process `*.js` files with `babel-jest`
".*\\.(js)$": "babel-jest" //<-- changed this
}
}
}
Adjusted babel config to:
module.exports = {
presets: [
'#vue/cli-plugin-babel/preset',
'#babel/preset-env' //<-- added this
]
};
You should use vue-cli API.
In your package.json add to scripts this:
"test:unit": "vue-cli-service test:unit"
You have vue-cli and test-utils installed so it should now work.

Eslint: warning File ignored by default. Use a negated ignore pattern

I am new in using Eslint.
So far I have installed Eslint in my local project and configured it. The eslintrc.js file contains
module.exports = {
env: {
node: true,
commonjs: true,
es6: true,
mocha: true,
},
extends: [
'airbnb-base',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
},
rules: {
},
};
And in package.json I have
"scripts": {
"lint": "eslint .eslintrc.js --fix",
}
In terminal I run
npm run lint
And the output is
> apigateway#1.0.0 lint C:\nodeprojects\restapi
> eslint .eslintrc.js --fix
C:\nodeprojects\restapi\.eslintrc.js
0:0 warning File ignored by default. Use a negated ignore pattern (like "--ignore-pattern '!<relative/path/to/filename>'") to override
But if I run
eslint <foldername> --fix then it works.
I am using webstorm IDE and in windows os.
Any help is highly appreciated.
ESlint default behaviour is ignoring file/folders starting with . - https://github.com/eslint/eslint/issues/10341.
In case for example you want to lint .storybook folder, ESLint will ignore it by default. To lint it, .eslintrc.js must include:
{
...
// Lint ".storybook" folder (don't ignore it)
"ignorePatterns": ["!.storybook"],
...
}
Because of that default ESLint behaviour, I do in all my projects like this (lint whole project from the root) :
{
...
// ESlint default behaviour ignores file/folders starting with "." - https://github.com/eslint/eslint/issues/10341
"ignorePatterns": ["!.*", "dist", "node_modules"],
...
}
Where I first don't ignore any file/folder starting with . and then I exclude folders that I actually want to ignore.
Your npm script runs the linter on the .eslintrc.js file and this file is as the comment says File ignored by default.
You need to change the lint script from:
"lint": "eslint .eslintrc.js --fix",
to:
"lint": "eslint <foldername> --fix"
Where <foldername> is the correct folder.
I ran into this issue where the pre-commit Husky hook would try to scan this file when trying to commit merges (where someone changed .eslintrc.js previously), then this would fail the merge commit in team members' local envs (file ignored by default)
You can create a .eslintignore file next to .eslintrc.js. Then in .eslintignore put:
!.eslintrc.js

How to use ESLint with Jest

I'm attempting to use the ESLint linter with the Jest testing framework.
Jest tests run with some globals like jest, which I'll need to tell the linter about; but the tricky thing is the directory structure, with Jest the tests are embedded with the source code in __tests__ folders, so the directory structure looks something like:
src
foo
foo.js
__tests__
fooTest.js
bar
bar.js
__tests__
barTest.js
Normally, I'd have all my tests under a single dir, and I could just add an .eslintrc file there to add the globals... but I certainly don't want to add a .eslintrc file to every single __test__ dir.
For now, I've just added the test globals to the global .eslintrc file, but since that means I could now reference jest in non-testing code, that doesn't seem like the "right" solution.
Is there a way to get eslint to apply rules based on some pattern based on the directory name, or something like that?
The docs show you are now able to add:
"env": {
"jest/globals": true
}
To your .eslintrc which will add all the jest related things to your environment, eliminating the linter errors/warnings.
You may need to include plugins: ["jest"] to your esconfig, and add the eslint-plugin-jest plugin if it still isn't working.
ESLint supports this as of version >= 4:
/*
.eslintrc.js
*/
const ERROR = 2;
const WARN = 1;
module.exports = {
extends: "eslint:recommended",
env: {
es6: true
},
overrides: [
{
files: [
"**/*.test.js"
],
env: {
jest: true // now **/*.test.js files' env has both es6 *and* jest
},
// Can't extend in overrides: https://github.com/eslint/eslint/issues/8813
// "extends": ["plugin:jest/recommended"]
plugins: ["jest"],
rules: {
"jest/no-disabled-tests": "warn",
"jest/no-focused-tests": "error",
"jest/no-identical-title": "error",
"jest/prefer-to-have-length": "warn",
"jest/valid-expect": "error"
}
}
],
};
Here is a workaround (from another answer on here, vote it up!) for the "extend in overrides" limitation of eslint config :
overrides: [
Object.assign(
{
files: [ '**/*.test.js' ],
env: { jest: true },
plugins: [ 'jest' ],
},
require('eslint-plugin-jest').configs.recommended
)
]
From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724
You can also set the test env in your test file as follows:
/* eslint-env jest */
describe(() => {
/* ... */
})
To complete Zachary's answer, here is a workaround for the "extend in overrides" limitation of eslint config :
overrides: [
Object.assign(
{
files: [ '**/*.test.js' ],
env: { jest: true },
plugins: [ 'jest' ],
},
require('eslint-plugin-jest').configs.recommended
)
]
From https://github.com/eslint/eslint/issues/8813#issuecomment-320448724
As of 2021, I think the correct way or at least the one that works is to install #types/jest and eslint-plugin-jest:
npm i -D eslint-plugin-jest #types/jest
And adding the Jest plugin into .eslintrc.js with the overrides instruction mentioned by #Loren:
module.exports = {
...
plugins: ["jest"],
...
overrides: [
{
files: ["**/*.test.js"],
env: { "jest/globals": true },
plugins: ["jest"],
extends: ["plugin:jest/recommended"],
},
],
...
};
This way you get linting errors in your source files as well as in test files, but in test files you don't get linting errors for test and other Jest's functions, but you will get them in your source files as they will appear as undefined there.
I solved the problem REF
Run
# For Yarn
yarn add eslint-plugin-jest -D
# For NPM
npm i eslint-plugin-jest -D
And then add in your .eslintrc file
{
"extends": ["airbnb","plugin:jest/recommended"],
}
some of the answers assume you have eslint-plugin-jest installed, however without needing to do that, you can simply do this in your .eslintrc file, add:
"globals": {
"jest": true,
}
First install eslint-plugin-jest
Running:
yarn add eslint-plugin-jest or npm install eslint-plugin-jest
Then edit .eslintrc.json
{
"env":{
"jest": true
}
}
As of ESLint V 6 (released in late 2019), you can use extends in the glob based config as follows:
"overrides": [
{
"files": ["*.test.js"],
"env": {
"jest": true
},
"plugins": ["jest"],
"extends": ["plugin:jest/recommended"]
}
]
Add environment only for __tests__ folder
You could add a .eslintrc.yml file in your __tests__ folders, that extends you basic configuration:
extends: <relative_path to .eslintrc>
env:
jest: true
If you have only one __tests__folder, this solution is the best since it scope jest environment only where it is needed.
Dealing with many test folders
If you have more test folders (OPs case), I'd still suggest to add those files. And if you have tons of those folders can add them with a simple zsh script:
#!/usr/bin/env zsh
for folder in **/__tests__/ ;do
count=$(($(tr -cd '/' <<< $folder | wc -c)))
echo $folder : $count
cat <<EOF > $folder.eslintrc.yml
extends: $(printf '../%.0s' {1..$count}).eslintrc
env:
jest: true
EOF
done
This script will look for __tests__ folders and add a .eslintrc.yml file with to configuration shown above. This script has to be launched within the folder containing your parent .eslintrc.
Pattern based configs are scheduled for 2.0.0 release of ESLint. For now, however, you will have to create two separate tasks (as mentioned in the comments). One for tests and one for the rest of the code and run both of them, while providing different .eslintrc files.
P.S. There's a jest environment coming in the next release of ESLint, it will register all of the necessary globals.
I got it running after spending some time trying out different options. Hope this helps anyone else getting stuck.
.eslintrc.json (in root project folder):
{
"env": {
"browser": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"standard",
"plugin:jest/all"
],
"parser": "#babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"jest/no-hooks": [
"error",
{
"allow": [
"afterEach",
"beforeEach"
]
}
]
},
"plugins": [
"jest"
]
}
Empty .babelrc (in root project folder):
{}
.package.json (in root project folder):
{
"scripts": {
"test": "jest",
"lint": "npx eslint --format=table .",
"lintfix": "npx eslint --fix ."
},
"devDependencies": {
"#babel/core": "^7.15.0",
"#babel/eslint-parser": "^7.15.0",
"aws-sdk-mock": "^5.2.1",
"eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.24.0",
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"jest": "^27.0.6"
}
}
VS Code settings.xml (editor configuration: enables auto fix on save + babel parser):
"eslint.alwaysShowStatus": true,
"eslint.format.enable": true,
"eslint.lintTask.enable": true,
"eslint.options": {
"parser": "#babel/eslint-parser"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript"
]
In your .eslintignore file add the following value:
**/__tests__/
This should ignore all instances of the __tests__ directory and their children.

How to cover React jsx files in Istanbul?

I'm trying to integrate my existing test processes to now include React, but am struggling on the code coverage part. I've been able to get my unit tests working fine by following this project/tutorial - https://github.com/danvk/mocha-react - http://www.hammerlab.org/2015/02/14/testing-react-web-apps-with-mocha/
I've been using Istanbul to cover my node code and it's working pretty well. However, I'm having trouble getting it to cover the jsx files that I'm using in my tests.
Here's an example of an existing Istanbul task, which also runs fine on vanilla js (node backend code)
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
gulp.task('test-api', function (cb) {
gulp.src(['api/**/*.js'])
.pipe(istanbul()) // Covering files
.pipe(istanbul.hookRequire()) // Force `require` to return covered files
.on('finish', function () {
gulp.src(['test/api/*.js'])
.pipe(mocha())
.pipe(istanbul.writeReports()) // Creating the reports after tests runned
.on('end', cb);
My issue ( i think ) is I can't get Istanbul to recognize the jsx files or they're not being compared to what was run in the tests. I tried using the gulp-react module to precompile the jsx to js so it can be used by Istanbul, but I'm not sure if it's working. It's not being covered somehow and I'm not sure where the issue is.
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
var react = require('gulp-react');
gulp.task('test-site-example', function (cb) {
gulp.src(["site/jsx/*.jsx"]) //Nothing is being reported by Istanbul (not being picked up)
.pipe(react()) //converts the jsx to js and I think pipes the output to Istanbul
.pipe(istanbul())
.pipe(istanbul.hookRequire()) // Force `require` to return covered files
.on('finish', function () {
gulp.src(['test/site/jsx/*.js'], { //tests run fine in mocha, but nothing being shown as reported by mocha (not covered)
read: false
})
.pipe(mocha({
reporter: 'spec'
}))
.pipe(istanbul.writeReports())
.on('end', cb);
});
;
});
Any ideas what I'm doing wrong? Or any clue on how to integrate a test runner (preferably Istanbul) into a Gulp-Mocha-React project?
Add a .istanbul.yml file to your app root and add .jsx to extensions "extension"...
Here is what I did.
// File .istanbul.yml
instrumentation:
root: .
extensions: ['.js', '.jsx']
To kickstart istanbul and mocha with jsx
$ istanbul test _mocha -- test/**/* --recursive --compilers js:babel/register
This will convert your .jsx files to .js and then istanbul will cover them.
I hope this helps. It worked for me.
There is a library you can take a look at, gulp-jsx-coverage (https://github.com/zordius/gulp-jsx-coverage).
In case someone else is having the same problem and solutions above don't work, I found that adding a simple "-e .jsx" tag worked:
"scripts": {
"start": "meteor run",
"test": "NODE_ENV=test mocha --recursive --compilers js:babel-register --require tests/index.js ./tests/**/*.test.js",
"coverage": "NODE_ENV=test nyc -all -e .jsx npm test"
}
This solution was found at: http://www.2devs1stack.com/react/tape/testing/nyc/coverage/2016/03/05/simple-code-coverage-with-nyc.html
A great tutorial can be found at https://istanbul.js.org/docs/tutorials/es2015/
I just slightly modified it to include react. (I also used 'env' instead of 'es2015', but either should work.) Here are my configurations:
npm i babel-cli babel-register babel-plugin-istanbul babel-preset-env babel-preset-react cross-env mocha nyc --save-dev
.babelrc
{
"presets": ["env", "react"],
"env": {
"test": {
"plugins": [
"istanbul"
]
}
}
}
package.json
"scripts": {
"test": "cross-env NODE_ENV=test nyc mocha test/**/*.spec.js --compilers js:babel-register"
}
"nyc": {
"require": [
"babel-register"
],
"reporter": [
"lcov",
"text"
],
"sourceMap": false,
"instrument": false
}

React and Grunt - Envify NODE_ENV='production' and UglifyJS

I am using Grunt to build a React project and I want to have 'dev' and 'prod' flavours. As react docs says:
To use React in production mode, set the environment variable NODE_ENV to production.
A minifier that performs dead-code elimination such as UglifyJS is
recommended to completely remove the extra code present in development mode.
I am very new using grunt, browserify and stuff but let's see. First problem I have is with envify, I use it as a transform:
browserify: {
options: {
transform: ['reactify'],
extensions: ['.jsx']
},
dev:{
options: {
watch: true //Uses watchify (faster)
},
src: ['js/app.js'],
dest: 'js/bundle.js'
},
/**
* To use React in production mode, set the environment variable NODE_ENV to production.
* A minifier that performs dead-code elimination such as UglifyJS is
* recommended to completely remove the extra code present in development mode.
**/
prod: {
options: {
transform: ['envify'] //How to set up NOD_ENV='production' ?
},
src: ['js/app.js'],
dest: 'js/bundle.js'
}
},
Ok, doing grunt:dev works just fine. So when running grunt:prod... How can I set NODE_ENV: 'production'? I mean, I know I am passing 'envify' as a transform but... No idea how to use that.
After this, I also have an uglify task:
uglify: {
prod: {
files: {
'js/bundle.min.js': ['js/bundle.js']
}
}
}
So after calling grunt:prod, what it creates is two files (bundle.js and bundle-min.js). In production I will like to only have bundle.min.js. I know I can do:
js/bundle.js': ['js/bundle.js']
But mmm I don't know if there is a way to just rename it to bundle.min.js, I guess so... the problem is that in the html I have:
<script src="js/bundle.js"></script>
Is there here also a trick to make it accepts either bundle.js or bundle.min.js?
Thanks in advance.
Transforms are local, and well made packages put their transforms in their package.json file. Unless you're using envify in your own code, you don't need to do anything with it.
What you do need is grunt-env, or another way to set environmental variables.
Here's an alternative by using package.json:
{
"scripts": {
"build": "NODE_ENV=development grunt build-dev",
"dist": "NODE_ENV=production grunt dist"
}
},
"devDependencies": {
"grunt": "...",
"grunt-cli": "..."
}
The benefit here is that the person using your package doesn't even need to install grunt globally. npm run build will run ./node_modules/.bin/grunt build-dev with the correct environmental variable set.
Both John Reilly's and FakeRainBrigand 's answers did not work for me. What worked for me was the following:
Step 1 - Run this command where your package.json is
npm i grunt-env --save-dev
Step 2 - Add the code in "evn:" to your Gruntfile.js within grunt.initConfig like so:
grunt.initConfig({
...
env: {
prod: {
NODE_ENV: 'production'
}
},
...
});
Step 3 - Add the grunt task to your Gruntfile.js
grunt.loadNpmTasks('grunt-env');
Step 4 - Call it before browserify like so:
grunt.registerTask("default", ["env", "browserify"]);
Just an addition to the great answer by FakeRainBrigand, if you're running on Windows (like me) then you need a subtly different syntax in your scripts section:
{
"scripts": {
"build": "SET NODE_ENV=development&&grunt build-dev",
"dist": "SET NODE_ENV=production&&grunt dist"
}
},
"devDependencies": {
"grunt": "...",
"grunt-cli": "..."
}

Categories