ESLint doesn't recognize node.js's 'global' object - javascript

The error:
3:5 error 'global' is not defined no-undef
My current ESLint config:
module.exports = {
parser: "babel-eslint",
env: {
browser: true,
es6: true,
"jest/globals": true,
jest: true
},
extends: ["eslint:recommended", "plugin:react/recommended", "prettier", "prettier/react"],
parserOptions: {
ecmaFeatures: {
experimentalObjectRestSpread: true,
jsx: true
},
sourceType: "module"
},
globals: {
testGlobal: true
},
plugins: ["react", "prettier", "jest"],
rules: {
"prettier/prettier": 1,
"no-console": 0
}
};
An simplified example test file that causes the ESLint error:
describe("Jest global:", () => {
it("should not cause ESLint error", () => {
global.testGlobal = {
hasProp: true
};
});
});
I expected this Jest feature to be covered by having the env: { jest: true } in the eslint config. I can of course disable the rule or line in the file, but then I'd need to do that every time I use global.

The global object is part of Node.js. It is not specific to Jest and therefore it's not included in the jest environment. In fact, you are running your unit tests in Node and you happen to use the global object for your tests. In general the globals defined for specific libraries are the ones they provide to make it more convenient to use them without having to import them. A counterexample would be AVA, which requires you to import it instead of defining globals.
If you want to use ESLint for the tests as well, you would have to add the node environment.
env: {
browser: true,
es6: true,
node: true,
jest: true
},

Related

Error: ESLint configuration in .eslintrc.js is invalid: - Unexpected top-level property "files"

I want to specify which files are to be linted in my eslintrc.js, so I've added files: ...
module.exports = {
extends: [
'react-app',
'react-app/jest',
'eslint:recommended',
'plugin:#typescript-eslint/recommended',
'prettier',
],
files: ['*.ts', '*.jsx', '*.ts', '*.tsx'],
parser: '#typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'testing-library/no-node-access': 'off',
},
};
But getting the following error when my precommit runs:
precommit: BABEL_ENV=development eslint src --ext .js,.jsx,.ts,.tsx --fix'*.ts', '*.tsx'
Error: ESLint configuration in .eslintrc.js is invalid:
- Unexpected top-level property "files".
The top-level rules and config apply to all the matched files according to your command line options (--ext etc.)
You only use "files" inside nested "overrides" blocks when you want to specify which files the overrides apply to.
See https://eslint.org/docs/latest/user-guide/configuring/configuration-files#how-do-overrides-work

How to not include mocha (TDD) functions like "describe" and "it" in my src folder and only contain them in test folder? [TS]

Mocha.js functions like describe() and it() are available everywhere in my project, but I only want them to be only accessible and callable in my "test" folder. Is there any way to do that?
P.S. I'm using typescript if that makes a difference.
I think your question is really vague. Still I am going to try to answer assming that you use eslint...
In your .eslintrc.js (or eslint config file), you may have:
module.exports = {
env: {
browser: true,
es6: true,
node: true,
mocha: true
}
(...)
Where you should have:
module.exports = {
env: {
browser: false,
es6: true,
node: true
},
(...)
overrides: [
{
files: 'test/**/*.spec.js',
env: {
mocha: true,
},
},
],

ESLint throws error when using mandatory file extensions in import in Node

In latest Node 16.8, file extensions are now mandatory in import (e.g. import { getFoo } from './api.js';). At the same time ESLint throws an error Unexpected use of file extension "js" for "./api.js".
This is my config file:
module.exports = {
env: {
node: true,
es2021: true,
},
extends: [
'airbnb-base',
],
parserOptions: {
ecmaVersion: 12,
},
rules: {
'no-console': 'off',
},
};
What's the best practice at the moment? Or at least the best walkaround?
If not, can I at least disable that rule?

Rollup is not generating typescript sourcemap

I am using rollup with svelte + typescript + scss. My problem is that I am not able to generate source maps.
Following is my rollup config file:
import svelte from 'rollup-plugin-svelte'
import resolve from '#rollup/plugin-node-resolve'
import commonjs from '#rollup/plugin-commonjs'
import livereload from 'rollup-plugin-livereload'
import { terser } from 'rollup-plugin-terser'
import typescript from '#rollup/plugin-typescript'
import alias from '#rollup/plugin-alias'
const production = !process.env.ROLLUP_WATCH
const path = require('path').resolve(__dirname, 'src')
const svelteOptions = require('./svelte.config')
function serve() {
let server
function toExit() {
if (server) server.kill(0)
}
return {
writeBundle() {
if (server) return
server = require('child_process').spawn(
'yarn',
['run', 'start', '--', '--dev'],
{
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
}
)
process.on('SIGTERM', toExit)
process.on('exit', toExit)
},
}
}
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js',
},
plugins: [
alias({
entries: [
{ find: '#app', replacement: `${path}` },
{ find: '#components', replacement: `${path}/components` },
{ find: '#includes', replacement: `${path}/includes` },
{ find: '#styles', replacement: `${path}/styles` },
{ find: '#pages', replacement: `${path}/pages` },
],
}),
svelte(svelteOptions),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte'],
}),
commonjs(),
typescript({ sourceMap: !production }),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser(),
],
watch: {
clearScreen: false,
},
}
I am not sure what exactly am I doing wrong. Here is the link to code I am using.
Any help will be deeply appreciated!
This is what worked for me: you need to set sourceMap: false in the typescript rollup plugin options.
export default {
input: 'src/main.ts',
output: {
sourcemap: true,
format: 'iife',
...
},
plugins: [
...
svelte(...),
typescript({ sourceMap: false }),
...
]
}
It turns out rollup's sourcemap collapser conflicts with the typescript's plugin sourcemap generator. That's why it works on prod builds but not in dev builds (because originally it is sourceMap: !production). Just let rollup do the heavy lifting.
As also mentioned by others, it seems like the combination of TypeScript and Rollup leads to the problem. Disabling the source map in TypeScript only fixes the problem of mapping Svelte to TypeScript. However you only receive a source map showing source in the compiled JavaScript, not in the original TypeScript. I finally found a solution, that worked for me: Just add the Option inlineSources: true to the TypeScript options:
typescript({ sourceMap: !production, inlineSources: !production }),
This circumvents the problem by simply not creating a duplicate SourceMap, but by copying the source code from TypeScript into the SourceMap.
For anyone using terser, not svelte, this solved the same problem for me:
import sourcemaps from 'rollup-plugin-sourcemaps';
import { terser } from 'rollup-plugin-terser';
import typescript from '#rollup/plugin-typescript';
export default [
{
input: 'dist/index.js',
output: [
{
file: 'dist/cjs/index.js',
format: 'cjs'
},
{
file: 'dist/fesm2015/index.js',
format: 'es'
}
],
plugins: [
sourcemaps(),
terser(),
typescript({ sourceMap: true, inlineSources: true })
]
}
];
Apparently rollup-plugin-sourcemaps is needed to do the magic necessary to utilize the map files generated by the TypeScript compiler and feed them to terser.
For me, I am able to map, by making sourcemap: "inline"
In the /build/index.esm.js file will have mapping inside.
export default {
input: "src/index.ts",
output: [
{
file: 'build/index.esm.js',
format: 'es',
sourcemap: "inline"
},
],
plugins: [
typescript({ sourceMap: false, inlineSources: true }),
]
}
I was having a similar issue with Karma, rollup, and typescript. I fixed it by adding "sourceRoot":"/base/" to my tsconfig.json file.
Before: map file entries pointed to /src/.
After: map file entries pointed to /base/src/ and everything worked.
// tsconfig.rollup.json
"compilerOptions": {
"module": "ES2022",
"esModuleInterop": true,
"target": "ES2022",
"moduleResolution": "classic",
"sourceMap": true,
"sourceRoot": "/base/"
...
}
// rollup.config.js
import typescript from '#rollup/plugin-typescript';
export default [
{
input: './src/test/test_context.spec.ts',
output: {
file: './dist/test/test_context.spec.js',
format: 'es',
sourcemap: 'inline'
},
plugins: [
typescript({
tsconfig: './tsconfig.rollup.json'
})
]
}
];

Can't find source maps for Karma + Jasmine + TypeScript + Webpack

I'm trying to test (with coverage) my TypeScript application using Karma, Jasmine, and Webpack. With the following, I'm able to successfully run tests, but am unable to generate coverage properly. I'm using karma-remap-coverage (https://github.com/sshev/karma-remap-coverage) and it seems simple enough.
It looks as though something interesting is happening (and I'm getting some kind of coverage report) but with a few tweaks here and there, the numbers change drastically and I can never actually load the sourcemaps.
Here's the basic setup:
I have a src directory that contains 10 .ts files. Only one has a corresponding .spec file at the moment.
The spec file is pretty simple and was just enough to prove that I could run tests:
import ComponentToTest from './componentToTest';
describe('ComponentToTest', () => {
it('should run a test', () => {
expect(1+1).toBe(2);
});
it('should be able to invoke the a method', () => {
spyOn(ComponentToTest, 'foo').and.callThrough();
ComponentToTest.foo('testing foo');
expect(ComponentToTest.foo).toHaveBeenCalled();
});
});
This works like a charm when paired with my tsconfig.json file:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"sourceMap": true,
"lib": ["es6", "dom"],
"experimentalDecorators": true
},
"exclude": [
"node_modules"
]
}
and karma.conf.js file:
module.exports = config => config.set({
frameworks: ['jasmine'],
mime: { 'text/x-typescript': ['ts','tsx'] },
// if I make this a generic './src/**/*.ts' it seems to freeze up
// without throwing any errors or running any tests, but that seems
// like a separate issue...
files: [
'./src/lib/componentToTest.ts',
'./src/lib/componentToTest.spec.ts'
],
preprocessors: {
'./src/**/*.spec.ts': ['webpack'],
'./src/**/*.ts': ['webpack', 'sourcemap', 'coverage']
},
webpack: {
devtool: "source-map",
module: {
rules: [
{
test: /\.ts?$/,
loader: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [".ts", ".js"]
}
},
webpackMiddleware: {
quiet: true,
stats: {
colors: true
}
},
// add both "karma-coverage" and "karma-remap-coverage" reporters
reporters: ['progress', 'coverage', 'remap-coverage'],
// save interim raw coverage report in memory
coverageReporter: {
type: 'in-memory'
},
// define where to save final remaped coverage reports
remapCoverageReporter: {
'text-summary': null,
html: './coverage/html',
cobertura: './coverage/cobertura.xml'
},
colors: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
});
And finally, I'm launching the tests with a simple Gulp task:
gulp.task('test', function (done) {
new Server({
configFile: __dirname + '/karma.conf.js',
singleRun: true
}, (exitCode) => {
done();
process.exit(exitCode);
}).start();
});
When run, I get an output that seems (mostly) promising:
Chrome 58.0.3029 (Mac OS X 10.12.3): Executed 1 of 2 SUCCESS (0 secs / 0.002 secs)
Chrome 58.0.3029 (Mac OS X 10.12.3): Executed 2 of 2 SUCCESS (0.026 secs / 0.004 secs)
[Error: Could not find source map for: "app/src/lib/componentToTest.ts"]
[Error: Could not find source map for: "app/src/lib/componentToTest.spec.ts"]
========================= Coverage summary =========================
Statements : 43.69% ( 322/737 )
Branches : 15.7% ( 38/242 )
Functions : 35.47% ( 61/172 )
Lines : 44.91% ( 322/717 )
====================================================================
So something is happening! Which makes me feel like I'm close. When I browse to my coverage report in a browser, I see both the .spec.ts file and the .ts file listed (which is again, getting closer) but I'm not quite there for a couple of reasons:
The .spec.ts file is being included in the coverage report. Since this is the test file, I do not want to include it.
Source maps are not being properly generated - this is clear from the errors in the console and also from the inability to browse to the specific file's coverage report.
I do feel like I'm pretty darn close. Is there anything simple that I'm missing or suggestions?
Update:
I realized I was using an older version of Node and thought that may be causing some issues. I upgraded to 6.11.0 and while that didn't solve anything, it did provide slightly more context:
The errors are being reported by remap-istanbul (no surprise there, really):
CoverageTransformer.addFileCoverage (/app/node_modules/remap-istanbul/lib/CoverageTransformer.js:148:17)
I am using karma-remap-coverage#0.1.4 which uses remap-istanbul#0.8.4 - it seems like there have been issues with remap-istanbul in the past, but not at the version I'm using.
Also using Webpack 2.6.1 and TypeScript 2.3.2
Well, after several days of trying different things, I've finally found a solution that works. I'm not sure specifically what was causing the issue in my first post, but here's where I've ended up. This may be helpful for someone else looking for a really simple TypeScript, Karma, Jasmine, Webpack (with coverage) setup.
My file structure and spec file stayed the same.
My tsconfig.json updated to:
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"inlineSourceMap": true, // this line
"sourceMap": false, // and this one
"experimentalDecorators": true,
"lib": ["es6", "dom"]
},
"exclude": [
"node_modules"
]
}
I switched to using the awesome-typescript-loader instead of ts-loader.
And finally, my karma.conf.js file now looks like:
module.exports = config => config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
frameworks: ['jasmine'],
mime: { 'text/x-typescript': ['ts','tsx'] },
files: [
'node_modules/angular/angular.min.js',
'./src/**/*.ts'
],
preprocessors: {
'./src/**/*.ts': ['webpack']
},
webpack: {
devtool: 'inline-source-map',
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader',
exclude: [
'node_modules',
/\.spec\.ts$/
]
},
{
test: /\.ts?$/,
use: [
{
loader: 'awesome-typescript-loader',
query: {
/**
* Use inline sourcemaps for "karma-remap-coverage" reporter
*/
sourceMap: false,
inlineSourceMap: true,
compilerOptions: {
removeComments: true
}
},
}
]
},
{
enforce: 'post',
test: /\.(js|ts)$/,
loader: 'istanbul-instrumenter-loader',
exclude: [
/node_modules/,
/\.spec\.ts$/
]
},
{ test: /\.html$/, loader: 'html-loader' }
]
},
resolve: {
extensions: [".ts", ".js", ".html"]
},
externals: {
angular: "angular"
}
},
webpackMiddleware: {
quiet: true,
stats: {
colors: true
}
},
// add both "karma-coverage" and "karma-remap-coverage" reporters
reporters: ['progress', 'coverage', 'remap-coverage'],
// save interim raw coverage report in memory
coverageReporter: {
type: 'in-memory'
},
// define where to save final remaped coverage reports
remapCoverageReporter: {
'text-summary': null,
html: './coverage/html',
cobertura: './coverage/cobertura.xml'
},
colors: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
});
Final package versions include:
node 4.2.6 (I was also able to get this to work with a newer version of node, but need to be here for other reasons)
awesome-typescript-loader 3.1.2
istanbul-instrumenter-loader 2.0.0
jasmine-core 2.5.2
karma 1.6.0
karma-chrome-launcher 2.0.0
karma-coverage 1.1.1
karma-jasmine 1.1.0
karma-remap-coverage 0.1.4
karma-webpack 2.0.3
typescript 2.3.2
webpack 2.6.1
Now my tests run, there are no errors in the console, and I have a coverage report of the original TypeScript files!
Lots of credit to the folks who put this together (it ended up guiding quite a bit of my final solution): https://github.com/AngularClass/angular-starter/tree/master/config

Categories