Why doesn't my karma support for...of statement? - javascript

I have setup karma as my unit test framework. But it doesn't compile below code:
let {btnData} = this.props
let buttons = []
for (let btn of btnData) {
btn = {...btnCategories[btn.type], ...btn}
buttons.push(btn)
}
I got below error on the line of for loop. Why doesn't it recognise for...of statement?
Can't find variable: Symbol
Below is my karma config file. My project includes webpack, reactjs and use karma, mocha, chai, enzyme as test libraries.
var path = require('path')
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['mocha', 'chai'],
files: [
'../test/**/*.js'
],
preprocessors: {
// add webpack as preprocessor
'../src/**/*.js': ['webpack', 'sourcemap'],
'../test/**/*.js': ['webpack', 'sourcemap'],
'../src/**/*.less': ['webpack', 'sourcemap']
},
webpack: { //kind of a copy of your webpack config
devtool: 'inline-source-map', //just do inline source maps instead of the default
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
query: {
presets: ['airbnb']
}
},
{
test: /\.json$/,
loader: 'json',
},{
test: /\.less$/,
loader: "style!css!less",
},
]
},
externals: {
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true,
'react/addons': true
},
resolve: {
alias: {
app: path.join(__dirname, '../src/js')
}
}
},
webpackServer: {
noInfo: true //please don't spam the console when running in karma!
},
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-sourcemap-loader',
'karma-chrome-launcher',
'karma-phantomjs-launcher',
'karma-mocha',
'karma-chai',
'karma-mocha-reporter'
],
babelPreprocessor: {
options: {
presets: ['airbnb']
}
},
reporters: ['mocha'],
// reporter options
mochaReporter: {
colors: {
success: 'blue',
info: 'bgGreen',
warning: 'cyan',
error: 'red'
},
symbols: {
success: '+',
info: '#',
warning: '!',
error: 'x'
}
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
})
};

Related

How can I get hot reloading (HMR) running with Webpack 5?

I am trying to get HMR running with webpack v5, but it does not work. When I modify and save a file, webpack re-compiles the project correctly, but the frontend does not update.
I read this article and followed the instructions: https://webpack.js.org/guides/hot-module-replacement/
This is my webpack config:
{
mode: 'development',
entry: {
babelpoly: 'babel-polyfill',
app: [ './src/index.js', './src/app.js' ]
},
plugins: [
BundleStatsWebpackPlugin { ... },
DefinePlugin { ... },
HtmlWebpackPlugin { ... }
],
stats: { ... },
output: {
path: '[pathTo]/dist',
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
},
optimization: {
splitChunks: { chunks: 'all' },
runtimeChunk: 'single',
usedExports: true,
mergeDuplicateChunks: true
},
module: {
rules: [
{
test: /\.(s[ac]ss)$/i,
include: path.resolve(ROOT, 'src'),
use: [
'style-loader', // Creates `style` nodes from JS strings
{
loader: 'css-loader', // Translates CSS into CommonJS
options: {
modules: {
mode: 'local',
localIdentName: devMode
? '[name]_[local]-[hash:base64:3]'
: '[local]-[hash:base64:5]',
},
},
},
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
implementation: require('sass'),
},
},
],
},
{
test: /\.css$/,
include: [path.join(ROOT, 'node_modules')],
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader'],
},
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 3,
},
],
'#babel/preset-react',
],
plugins: [['#babel/plugin-proposal-class-properties', {loose: true}]],
},
},
},
],
},
resolve: {
extensions: [ ... ],
alias: {
...
},
modules: [
...
]
},
devtool: 'inline-source-map',
devServer: {
port: 3003,
contentBase: '[pathTo]/dist',
host: '0.0.0.0',
hot: true,
compress: true,
disableHostCheck: true,
historyApiFallback: true,
overlay: { warnings: true, errors: true },
stats: { ... }
}
}
I am using:
webpack 5.7.0
webpack-cli 4.2.0
react 16.13
node 14.15.1
npm 6.14.8
I start webpack with this command: webpack serve --host 0.0.0.0 --config config/webpack.dev.js
What do I do wrong? Thanks for your help. :)
I believe it's a bug in webpack-dev-server v3 https://github.com/webpack/webpack-dev-server/issues/2758 when you're using it with webpack 5 and browserslist. You can wait for webpack-dev-server v4 https://github.com/webpack/webpack-dev-server/pull/2592#issuecomment-734400875, it will come soon, or use target: 'web' for the moment under your development mode.

Karma + Jasmine - Can't find variable require

i'm trying to implement some tests in my VueJS project using karma and jasmine. I can launch basic test such as:
describe('canary', function () {
// asserting JavaScript options
it('should run', function () {
expect(true).toBe(true)
})
it('should run 2', function () {
expect(false).toBe(false)
})
})
which return (I'm not allowed to display image on my post yet):
But when it comes to testing my components (So when i require them) it says to me:
PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
ReferenceError: Can't find variable: require
at history.spec.js:1
Here is my karma.conf.js:
module.exports = function(config) {
var tests = './**/*.js';
config.set({
frameworks: ['jasmine'],
files: [tests],
reporters: ['dots'],
singleRun: true,
autoWatch: false,
browsers: ['PhantomJS'],
preprocessors: {
tests: ['webpack'],
'../src/main.js': ['webpack']
},
webpack: {
module: {
loaders: [
{ test: /\.js/, exclude: /node_modules/, loader: 'babel-loader' }
]
},
watch: true
},
webpackServer: {
noInfo: true
}
});
};
Here's my test file:
var Vue = require('vue')
var ComponentA = require('../src/Log.vue')
describe('Log.vue', function () {
// asserting JavaScript options
it('should have correct message', function () {
expect(ComponentA.data().msg).toBe('Hello from Log!')
})
})
EDIT - New karma.conf.js file
I managed to make it work, so i post my config files here, it might help.
webpack.test.config.js:
const path = require('path')
module.exports = {
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*$|$)/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: ['es2015']
},
include: [
path.resolve(__dirname, '../')
],
exclude: /node_modules/
},
],
rules: [
{
// Maybe just use vue-loader on html template files in components directory only
// Like /components\/.*\.html$/
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*$|$)/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
]
},
resolve: {
extensions: ['.js', '.vue']
}
}
karma.conf.js
module.exports = function(config) {
var tests = '*.js';
config.set({
frameworks: ['jasmine'],
files: [tests],
reporters: ['dots'],
singleRun: true,
autoWatch: false,
browsers: ['PhantomJS'],
preprocessors: {
tests: ['webpack'],
'../src/main.js': ['webpack']
},
webpack: {
module: {
loaders: [
{ test: /\.js/, exclude: /node_modules/, loader: 'babel-loader' }
]
},
watch: true
},
webpackServer: {
noInfo: true
}
});
};
Some basic test:
import { expect } from 'chai'
describe('canary', function () {
// asserting JavaScript options
it('should run', function () {
expect(true).to.be.true
})
it('should run 2', function () {
expect(false).to.be.false
})
})

Coverage reports with karma and a mix of javascript and typescript src files

I have a project where I use webpack for development/testing and karma as my test runner. This project has source files written half in js and half in ts/tsx. The test suite is written completely in js. I currently use karma-coverage, which shows coverage reports for all my js source files, but it does not support typescript files. All my tests run, there is no problem there, I just would like coverage reports for all my test files. Can anyone point me in the right direction?
Here is my karma.conf.js if this helps.
'use strict';
const webpackCfg = require('./webpack.config')('test');
module.exports = function karmaConfig(config) {
config.set({
browsers: ['Chrome'],
files: [
'test/loadtests.js'
],
port: 8080,
captureTimeout: 60000,
frameworks: [
'mocha',
'chai',
'sinon'
],
client: {
mocha: {}
},
singleRun: true,
reporters: ['mocha', 'coverage', 'junit'],
mochaReporter: {
output: 'autowatch'
},
preprocessors: {
'test/loadtests.js': ['webpack', 'sourcemap']
},
webpack: webpackCfg,
webpackServer: {
noInfo: true
},
junitReporter: {
outputDir: 'coverage',
outputFile: 'junit-result.xml',
useBrowserName: false
},
coverageReporter: {
dir: 'coverage/',
watermarks: {
statements: [70, 80],
functions: [70, 80],
branches: [70, 80],
lines: [70, 80]
},
reporters: [
{ type: 'text' },
{
type: 'html',
subdir: 'html'
},
{
type: 'cobertura',
subdir: 'cobertura'
},
{
type: 'lcovonly',
subdir: 'lcov'
}
]
}
});
};
And the relevant part of my webpack test config
{
devtool: 'inline-source-map',
externals: {
cheerio: 'window',
'react/lib/ExecutionEnvironment': true,
'react/addons': true,
'react/lib/ReactContext': true,
},
module: {
preLoaders: [
{
test: /\.(js|jsx)$/,
loader: 'isparta-loader',
include: [
this.srcPathAbsolute
]
}
],
loaders: [
{
test: /\.cssmodule\.css$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[name]-[local]-[hash:base64:5]'
]
},
{
test: /^.((?!cssmodule).)*\.css$/,
loader: 'null-loader'
},
{
test: /\.(sass|scss|less|styl|png|jpg|gif|mp4|ogg|svg|woff|woff2)$/,
loader: 'null-loader'
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
loader: ['babel', 'ts-loader']
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
query: {
presets: ['airbnb']
},
include: [].concat(
this.includedPackages,
[
this.srcPathAbsolute,
this.testPathAbsolute
]
)
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"test"'
})
]
}
After a couple days of soul and google searching amongst hundreds of browser tabs, I have found a working solution. This is using TypeScript 2.x and Webpack 2.x. test.js is my entry point. It could just as easily be test.ts (and it will be eventually). In that entry point, I load my *.spec.js and *.spec.ts files. And then those files import whichever source they need to test from. I have put all the webpack config in the karma.conf.js so it's easier to see:
let myArgs = require('yargs').argv;
let path = require('path');
let webpack = require('webpack');
module.exports = function(config) {
const REPORTS_PATH = myArgs.reportsPath ? myArgs.reportsPath :path.join(__dirname, 'build');
config.set({
basePath: '',
frameworks: ['jasmine', 'es6-shim'],
files: [
'./test.js'
],
exclude: [],
reporters: ['progress', 'spec', 'coverage', 'junit', 'coverage-istanbul'],
preprocessors: {
'./test.js': ['webpack', 'sourcemap']
},
webpackServer: {
noInfo: true // prevent console spamming when running in Karma!
},
webpack: {
devtool: 'inline-source-map',
resolve: {
modules: [
path.resolve('./node_modules'),
path.resolve('./')
],
extensions: ['.js', '.ts', '.css', '.scss']
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
],
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
use: 'source-map-loader',
exclude: [/node_modules/]
},
{
test: /\.ts$/,
use: [{
loader: 'awesome-typescript-loader',
options: {
module: 'commonjs'
},
}]
},
{
test: /\.js$/,
use: [{
loader: 'awesome-typescript-loader',
options: {
entryFileIsJs: true,
transpileOnly: true
}
}],
exclude: [/node_modules/],
},
{
enforce: 'post',
test: /\.(js|ts)$/,
use: [{
loader: 'istanbul-instrumenter-loader',
options: {
esModules: true
}
}],
exclude: [/node_modules/, /\.spec\.(js|ts)$/, /test/]
},
{ test: /\.html/, use: 'raw-loader' },
{ test: /\.(s)?css$/, use: 'null-loader' },
{ test: /\.(png|jpg|jpeg|gif|svg|pdf)$/, use: 'null-loader' },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
{ test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
{ test: /\.json$/, use: 'null-loader' }
]
}
},
coverageReporter: {
type: 'in-memory'
},
coverageIstanbulReporter: {
//TODO: Figure out why the 'html' reporter blows up with istanbul-reports (something with absolute path copying files)
reports: ['text-summary', 'cobertura'],
// base output directory
dir: REPORTS_PATH,
fixWebpackSourcePaths: true,
'report-config': {
cobertura: {
file: 'coverage.xml'
},
'text-summary': {
file: null
}
}
},
junitReporter: {
outputDir: `${REPORTS_PATH}/junit/`,
outputFile: 'jasmine-results.xml'
},
// Hide webpack build information from output
webpackMiddleware: {
stats: {
chunkModules: false,
colors: true
},
noInfo: 'errors-only'
},
colors: true,
logLevel: config.LOG_ERROR,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
autoWatchBatchDelay: 400
});
};
So, the key pieces here are awesome-typescript-loader, karma-coverage-istanbul-reporter, source-map-loader, and in the tsconfig.json, you want to set these in compilerOptions:
"inlineSourceMap": true,
"sourceMap": false,
I indicated a TODO about the html report. It DOES work but I couldn't get it to output to a custom directory (subdir) with TypeScript files as a part of it. JavaScript only worked fine. Could be a windows-specific problem with istanbul-reports. If you add html to the reports array under coverageIstanbulReporter, you should see it in your project dir but may have problems putting it in REPORTS_PATH.
It's also worth noting that I had a lot of luck using karma-remap-coverage instead of karma-coverage-istanbul-reporter but the former would not correctly generate cobertura reports for coverage which is what I needed for Jenkins.

fetch-mock Response Does Not Have JSON Method

I'm trying to get fetch-mock to work in my testing setup, but the response object looks different than expected.
Specifically, it does not have a json method.
Here's the class I'm calling with the actual call to fetch:
import 'whatwg-fetch';
export class Store {
load() {
return fetch("/api", {
method: "get",
headers: {'Content-Type': 'application/json'}
});
}
}
Here is a snippet from the test code:
import fetchMock from 'fetch-mock';
fetchMock.get("*", {code: "1", name: "cde", image: 'hello.jpeg'})
this.store = new Store;
this.store.load().then(response => console.log(response._bodyInit()));
console.log('hello', this.brandStore.brands[0]);
fetchMock.restore();
The console will print:
Response{
type: 'default',
status: 200,
ok: true,
statusText: 'OK',
headers: Headers{map: Object{content-type: ...}},
url: '/api',
_bodyInit: '{"code":"1","name":"cde","image":"hello.jpeg"}',
_bodyText: '{"code":"1","name":"cde","image":"hello.jpeg"}'
}
This error also gets output:
'Unhandled promise rejection', TypeError{line: 4005, sourceURL: 'http://localhost:9876/base/test/stores/BrandStore.spec.js?572679e0c28b63839a5f5829ef1a60b8d62f8b84', stack: 'http://localhost:9876/base/test/stores/BrandStore.spec.js?572679e0c28b63839a5f5829ef1a60b8d62f8b84:4005:168
run#http://localhost:9876/base/node_modules/babel-polyfill/dist/polyfill.js?00cf5c53ec5ebd52d0521aed551c593eef05a0d6:3911:29
http://localhost:9876/base/node_modules/babel-polyfill/dist/polyfill.js?00cf5c53ec5ebd52d0521aed551c593eef05a0d6:3924:31
flush#http://localhost:9876/base/node_modules/babel-polyfill/dist/polyfill.js?00cf5c53ec5ebd52d0521aed551c593eef05a0d6:1209:11'}
My Karma (with Webpack config) looks like:
const webpack = require('webpack');
var argv = require('yargs').argv;
var path = require('path');
let srcPath = path.join(__dirname, '/../src/');
const webpackConfig = {
devtool: 'inline-source-map',
resolve: {
// allow us to import components in tests like:
// import Example from 'components/Example';
root: path.resolve(__dirname, './src'),
// allow us to avoid including extension name
extensions: ['', '.js', '.jsx', '.css', '.scss', '.json'],
// required for enzyme to work properly
alias: {
'sinon': 'sinon/pkg/sinon',
}
},
module: {
// don't run babel-loader through the sinon module
noParse: [
/node_modules\/sinon\//
],
isparta: {
embedSource: true,
noAutoWrap: true,
// these babel options will be passed only to isparta and not to babel-loader
babel: {
presets: ['es2015', 'stage-0', 'react']
}
},
// run babel loader for our tests
loaders: [
{
test: /\.(js|jsx)$/,
loader: 'babel',
exclude: path.resolve(__dirname, 'node_modules'),
query: {
plugins: ['transform-decorators-legacy'],
presets: ['es2015', 'airbnb', 'stage-1', 'react']
}
},
{
test: /\.json$/, loader: 'json'
},
{
test: /\.scss$/,
exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[local]',
'postcss',
'sass'
]
},
{
test: /\.css$/,
exclude: /[\/\\](node_modules|bower_components|public)[\/\\]/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[local]'
]
}
],
preLoaders: [ { //delays coverage til after tests are run, fixing transpiled source coverage error
test: /\.(jsx|js)$/,
include: path.resolve('src/'),
loader: 'isparta',
} ]
},
plugins: [
new webpack.IgnorePlugin(/node-fetch/)
],
// required for enzyme to work properly
externals: {
'jsdom': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': 'window',
'react/addons': true
},
};
module.exports = function(config) {
config.set({
browsers: ['PhantomJS'],
singleRun: !argv.watch,
frameworks: ['mocha', 'chai'],
reporters: ['spec', 'coverage'],
// include some polyfills for babel and phantomjs
files: [
'node_modules/whatwg-fetch/fetch.js',
'node_modules/babel-polyfill/dist/polyfill.js',
'./node_modules/phantomjs-polyfill/bind-polyfill.js',
'test/**/*.js'
],
preprocessors: {
// add webpack as preprocessor
'src/**/*.js': ['webpack', 'sourcemap'],
'test/**/*.js': ['webpack', 'sourcemap']
},
// A lot of people will reuse the same webpack config that they use
// in development for karma but remove any production plugins like UglifyJS etc.
// I chose to just re-write the config so readers can see what it needs to have
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
coverageReporter: {
dir: 'coverage/',
reporters: [
{ type: 'html' },
{ type: 'text' }
]
},
// tell karma all the plugins we're going to be using to prevent warnings
plugins: [
'karma-mocha',
'karma-chai',
'karma-webpack',
'karma-phantomjs-launcher',
'karma-spec-reporter',
'karma-sourcemap-loader',
'karma-coverage'
]
});
};

Karma reload debug.html on test file changes

When running Karma with autoWatch: true and singleRun: false, any change to my unit test files causes the tests to be re-run, and refreshes the Karma webpage at localhost:9876:
The problem is that the page athttp://localhost:9876/debug.html (the page you reach by clicking the DEBUG button) doesn't autorefresh, which is a pity since it prints more detailed information to the browser console and allows you to use breakpoints.
Is there a way to auto-refresh http://localhost:9876/debug.html on test file changes, and not just http://localhost:9876? I read through Karma's configuration file page and couldn't find any options for this. Setting up this page to auto-reload through means outside of Karma is perfectly acceptable.
Edit: Here's my karma.config.js file:
var webpack = require('webpack');
var path = require('path');
var environment = getEnvironment();
function getEnvironment() {
console.log('NODE_ENV: ' + process.env.NODE_ENV);
if(process.env.NODE_ENV === 'dev') {
return {
browsers: ['Chrome'],
singleRun: false
};
}
else if(process.env.NODE_ENV === 'staging') {
return {
browsers: ['PhantomJS2'],
singleRun: true
};
}
else if(process.env.NODE_ENV === 'production') {
return {
browsers: ['PhantomJS2'],
singleRun: true
};
}
return {};
}
module.exports = function (config) {
config.set({
browsers: environment.browsers,
singleRun: environment.singleRun,
frameworks: ['mocha'],
files: [
'tests.webpack.js',
{pattern: 'assets/img/*.jpg', watched: false, included: false, served: true, nocache: false},
{pattern: 'assets/img/*.png', watched: false, included: false, served: true, nocache: false},
{pattern: 'assets/img/*.gif', watched: false, included: false, served: true, nocache: false}
],
proxies: {
'/assets/img/': '/base/assets/img/'
},
preprocessors: {
'tests.webpack.js': ['webpack']
},
reporters: ['progress', 'clear-screen', 'dots'],
webpack: {
entry: {
app: ['./src/front.jsx']
},
devServer: {
historyApiFallback: true
},
output: {
// publicPath: 'http://localhost:8080/',
filename: './dist/[name].js'
},
module: {
loaders: [{
test: /\.(js|jsx)$/,
loaders: ['react-hot', 'jsx'],
include: /src/,
exclude: /(node_modules)/
},
{
test: /\.(js|jsx)$/,
include: /src/,
exclude: /(node_modules)/,
loader: 'babel',
query: {
presets:['react', 'es2015']
}
},
{
test: /\.scss$/,
include: /src/,
exclude: /(node_modules)/,
loaders: ['style', 'css', 'sass']
},
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
{ test: /\.(woff|woff2)$/, loader:"url?prefix=font/&limit=5000" },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" }
]
},
plugins: [
new webpack.ProvidePlugin({
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
})
],
resolve: {
root: path.resolve(__dirname) + "/src/",
extensions: ['', '.js', '.jsx']
},
resolveLoader: {
root: path.join(__dirname, "node_modules")
}
},
webpackServer: {
noInfo: true
}
});
};
And tests.webpack.js:
var context = require.context('./src', true, /-test\.jsx?$/);
context.keys().forEach(context);
Set usePolling to true.
usePolling = true;
This works fine for me.

Categories

Resources