Jasmine 中的测试失败了
Test's are getting failed in Jasmine
我想在 Typescript 项目中测试一个没有主体的函数。我创建了一个运行良好的实用 JS 函数。给出如下:
function isEmpty(f) {
// Get content between first { and last }
const m = f.toString().match(/\{([\s\S]*)\}/m);
// Strip comments
const l = m && m[1].replace(/^\s*\/\/.*$/mg, '').trim();
if (l.length === 0) {
return true;
} else {
return false;
}
};
function doSeatMouseClick(_event, _seat) {
//do nothing, read only
}
var bool = isEmpty(doSeatMouseClick);
console.log(bool)
在 Spec 文件中,当我访问此 isEmpty 函数时。测试失败,在控制台记录该函数时,我看到了一些额外的代码,我猜 webpack 预处理器正在添加这些代码。
describe('doSeatMouseClick()', () => {
it('should be empty', () => {
console.log(selectionTool.doSeatMouseClick.toString());
const bool = isEmpty(selectionTool.doSeatMouseClick);
expect(bool).toBeTruthy();
});
});
测试失败截图:
下面添加必要的配置:
Webpack 配置:
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const commonConfig = require('./base.js');
const merge = require('webpack-merge');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PACKAGE = require('../package.json');
const appVersion = PACKAGE.version;
const rootpath = path.resolve(__dirname, '..');
console.log("Creating for development");
var ENV = process.env.NODE_ENV;
module.exports = merge(commonConfig, {
mode: 'development',
devtool: 'eval-cheap-module-source-map', //eval-cheap-source-map
output: {
library: "Library",
libraryTarget: 'umd',
libraryExport: "default",
umdNamedDefine: true,
path: path.resolve(rootpath, 'dist'),
// publicPath: '/',
filename: '[name].js',
pathinfo: false
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'assets/[name].[hash:8].[ext]'
}
},
{
test: /\.worker\.ts$/,
loader: 'worker-loader',
options: {
inline: true,
fallback: false
}
},
{
// Include ts, tsx, js, and jsx files.
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
loader: require.resolve('babel-loader'),
query: { compact: false }
},
{
test: /(\.scss|\.css)$/,
use: [{
loader: MiniCssExtractPlugin.loader
}, {
loader: 'css-loader',
options: {
sourceMap: true,
modules: {
localIdentName: '[name]-[hash:base64:5]'
}
}
},
{
loader: 'postcss-loader' //PostCSS plugins go here
}, {
loader: 'sass-loader',
options: {
sourceMap: true
}
}]
}
]
},
plugins: [
new LodashModuleReplacementPlugin,
new htmlWebpackPlugin({ //create html file to serve the bundle
template: path.join(rootpath, '', 'index.html'), //webpack build html file for us in dist folder(will take this index.html file and inject main.js file)
inject: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(ENV),
app_version: JSON.stringify(appVersion)
}),
new MiniCssExtractPlugin({
filename: '[name].css'
})
// new BundleAnalyzerPlugin()
],
optimization: {
//some code
},
devServer: {
port: 3000,
open: true,
inline: true,
stats: 'errors-only'
}
});
业力配置:
const webpackConfig = require('./webpack/test');
const testPattern = 'src/**/*.spec.ts';
// const testPattern = 'src/models/tools/*.spec.ts';
module.exports = function (config) {
config.set({
basePath: '',
// frameworks to use
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
{ pattern: testPattern, watched: false }
],
// list of files / patterns to exclude
exclude: [
'src/**/*.d.ts',
'src/**/*.scss'
],
// preprocess matching files before serving them to the browser
// Source maps can be found on clicking DEBUG btn
// Preprocessor will convert Typescript to Javascript
preprocessors: {
[testPattern]: ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only'
},
webpackServer: {
noInfo: true
},
coverageIstanbulReporter: {
fixWebpackSourcePaths: true,
reports: ['html', 'text-summary'],
// enforce percentage thresholds
// anything under these percentages will cause karma to fail with an exit code of 1 if not running in watch mode
// thresholds: {
// emitWarning: true, // set to `true` to not fail the test command when thresholds are not met
// // thresholds for all files
// global: {
// statements: 100,
// lines: 100,
// branches: 100,
// functions: 100
// },
// // thresholds per file
// each: {
// statements: 100,
// lines: 100,
// branches: 100,
// functions: 100
// // overrides: {
// // 'baz/component/**/*.js': {
// // statements: 98
// // }
// // }
// }
// },
// Omit files with no statements, no functions and no branches covered from the report
skipFilesWithNoCoverage: true,
verbose: true // output config used by istanbul for debugging
},
// Enable or disable failure on running empty test-suites. If disabled the program will return exit-code 0 and display a warning.
failOnEmptyTestSuite: false,
// test results reporter to use
reporters: ['spec', 'coverage-istanbul'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
browsers: ['ChromeHeadless'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
});
};
我不知道如何解决这个问题,或者我在这里做错了什么。任何建议都会有所帮助。
看起来函数不为空的原因是您的覆盖跟踪器,因此是 cov_10clr7afd6.f[9]++
的“cov”部分。这是检查任何经过编译步骤的代码的问题之一,它可能不是您合理期望的。
这里有一些选项:
在您的正则表达式替换中说明插入内容
function isEmpty(f) {
// Get content between first { and last }
const m = f.toString().match(/\{([\s\S]*)\}/m);
// Strip comments
const l = m && m[1]
.replace(/^\s*\/\/.*$/mg, '')
.replace(/cov_\w*\.f\[[0-9]+\]\+\+;?/g, '')
.trim();
if (l.length === 0) {
return true;
} else {
return false;
}
};
function doSeatMouseClick(_event, _seat) {
//do nothing, read only
cov_10clr7afd6.f[9]++;
cov_10clr7afd6.f[500]++
}
var bool = isEmpty(doSeatMouseClick);
console.log(bool)
此解决方案也是如此,因为您的 codecov 工具中的任何更改都可能破坏此解决方案。
改用 ESLint
有一个 lint 规则 https://eslint.org/docs/rules/no-empty-function 可以执行此操作,但有意忽略带有注释的函数。您可以采取这种行为,也可以通过简化其源代码中的 reportIfEmpty
函数来基于它编写自己的行为。
// https://github.com/eslint/eslint/blob/master/lib/rules/no-empty-function.js
function reportIfEmpty(node) {
const kind = getKind(node);
const name = astUtils.getFunctionNameWithKind(node);
if (allowed.indexOf(kind) === -1 &&
node.body.type === "BlockStatement" &&
node.body.body.length === 0
) {
context.report({
node,
loc: node.body.loc,
messageId: "unexpected",
data: { name }
});
}
}
您可以使用以下 Create custom ESLint rules in 2 minutes.
将此新规则添加到您的 eslint 配置中
这应该是一个更可靠的解决方案,但可能会突出显示您不想处理的其他错误。您可以使用 eslint override 来帮助将规则定位到您想要的文件。
// .eslintrc
{
"overrides": [
{
"files": ["some/path/*.ts"],
"rules": {
"my-project/no-empty-functions": "error"
}
}
]
}
我想在 Typescript 项目中测试一个没有主体的函数。我创建了一个运行良好的实用 JS 函数。给出如下:
function isEmpty(f) {
// Get content between first { and last }
const m = f.toString().match(/\{([\s\S]*)\}/m);
// Strip comments
const l = m && m[1].replace(/^\s*\/\/.*$/mg, '').trim();
if (l.length === 0) {
return true;
} else {
return false;
}
};
function doSeatMouseClick(_event, _seat) {
//do nothing, read only
}
var bool = isEmpty(doSeatMouseClick);
console.log(bool)
在 Spec 文件中,当我访问此 isEmpty 函数时。测试失败,在控制台记录该函数时,我看到了一些额外的代码,我猜 webpack 预处理器正在添加这些代码。
describe('doSeatMouseClick()', () => {
it('should be empty', () => {
console.log(selectionTool.doSeatMouseClick.toString());
const bool = isEmpty(selectionTool.doSeatMouseClick);
expect(bool).toBeTruthy();
});
});
测试失败截图:
下面添加必要的配置:
Webpack 配置:
const path = require('path');
const webpack = require('webpack');
const htmlWebpackPlugin = require('html-webpack-plugin');
const commonConfig = require('./base.js');
const merge = require('webpack-merge');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PACKAGE = require('../package.json');
const appVersion = PACKAGE.version;
const rootpath = path.resolve(__dirname, '..');
console.log("Creating for development");
var ENV = process.env.NODE_ENV;
module.exports = merge(commonConfig, {
mode: 'development',
devtool: 'eval-cheap-module-source-map', //eval-cheap-source-map
output: {
library: "Library",
libraryTarget: 'umd',
libraryExport: "default",
umdNamedDefine: true,
path: path.resolve(rootpath, 'dist'),
// publicPath: '/',
filename: '[name].js',
pathinfo: false
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'assets/[name].[hash:8].[ext]'
}
},
{
test: /\.worker\.ts$/,
loader: 'worker-loader',
options: {
inline: true,
fallback: false
}
},
{
// Include ts, tsx, js, and jsx files.
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
loader: require.resolve('babel-loader'),
query: { compact: false }
},
{
test: /(\.scss|\.css)$/,
use: [{
loader: MiniCssExtractPlugin.loader
}, {
loader: 'css-loader',
options: {
sourceMap: true,
modules: {
localIdentName: '[name]-[hash:base64:5]'
}
}
},
{
loader: 'postcss-loader' //PostCSS plugins go here
}, {
loader: 'sass-loader',
options: {
sourceMap: true
}
}]
}
]
},
plugins: [
new LodashModuleReplacementPlugin,
new htmlWebpackPlugin({ //create html file to serve the bundle
template: path.join(rootpath, '', 'index.html'), //webpack build html file for us in dist folder(will take this index.html file and inject main.js file)
inject: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(ENV),
app_version: JSON.stringify(appVersion)
}),
new MiniCssExtractPlugin({
filename: '[name].css'
})
// new BundleAnalyzerPlugin()
],
optimization: {
//some code
},
devServer: {
port: 3000,
open: true,
inline: true,
stats: 'errors-only'
}
});
业力配置:
const webpackConfig = require('./webpack/test');
const testPattern = 'src/**/*.spec.ts';
// const testPattern = 'src/models/tools/*.spec.ts';
module.exports = function (config) {
config.set({
basePath: '',
// frameworks to use
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
{ pattern: testPattern, watched: false }
],
// list of files / patterns to exclude
exclude: [
'src/**/*.d.ts',
'src/**/*.scss'
],
// preprocess matching files before serving them to the browser
// Source maps can be found on clicking DEBUG btn
// Preprocessor will convert Typescript to Javascript
preprocessors: {
[testPattern]: ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only'
},
webpackServer: {
noInfo: true
},
coverageIstanbulReporter: {
fixWebpackSourcePaths: true,
reports: ['html', 'text-summary'],
// enforce percentage thresholds
// anything under these percentages will cause karma to fail with an exit code of 1 if not running in watch mode
// thresholds: {
// emitWarning: true, // set to `true` to not fail the test command when thresholds are not met
// // thresholds for all files
// global: {
// statements: 100,
// lines: 100,
// branches: 100,
// functions: 100
// },
// // thresholds per file
// each: {
// statements: 100,
// lines: 100,
// branches: 100,
// functions: 100
// // overrides: {
// // 'baz/component/**/*.js': {
// // statements: 98
// // }
// // }
// }
// },
// Omit files with no statements, no functions and no branches covered from the report
skipFilesWithNoCoverage: true,
verbose: true // output config used by istanbul for debugging
},
// Enable or disable failure on running empty test-suites. If disabled the program will return exit-code 0 and display a warning.
failOnEmptyTestSuite: false,
// test results reporter to use
reporters: ['spec', 'coverage-istanbul'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
browsers: ['ChromeHeadless'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
});
};
我不知道如何解决这个问题,或者我在这里做错了什么。任何建议都会有所帮助。
看起来函数不为空的原因是您的覆盖跟踪器,因此是 cov_10clr7afd6.f[9]++
的“cov”部分。这是检查任何经过编译步骤的代码的问题之一,它可能不是您合理期望的。
这里有一些选项:
在您的正则表达式替换中说明插入内容
function isEmpty(f) {
// Get content between first { and last }
const m = f.toString().match(/\{([\s\S]*)\}/m);
// Strip comments
const l = m && m[1]
.replace(/^\s*\/\/.*$/mg, '')
.replace(/cov_\w*\.f\[[0-9]+\]\+\+;?/g, '')
.trim();
if (l.length === 0) {
return true;
} else {
return false;
}
};
function doSeatMouseClick(_event, _seat) {
//do nothing, read only
cov_10clr7afd6.f[9]++;
cov_10clr7afd6.f[500]++
}
var bool = isEmpty(doSeatMouseClick);
console.log(bool)
此解决方案也是如此,因为您的 codecov 工具中的任何更改都可能破坏此解决方案。
改用 ESLint
有一个 lint 规则 https://eslint.org/docs/rules/no-empty-function 可以执行此操作,但有意忽略带有注释的函数。您可以采取这种行为,也可以通过简化其源代码中的 reportIfEmpty
函数来基于它编写自己的行为。
// https://github.com/eslint/eslint/blob/master/lib/rules/no-empty-function.js
function reportIfEmpty(node) {
const kind = getKind(node);
const name = astUtils.getFunctionNameWithKind(node);
if (allowed.indexOf(kind) === -1 &&
node.body.type === "BlockStatement" &&
node.body.body.length === 0
) {
context.report({
node,
loc: node.body.loc,
messageId: "unexpected",
data: { name }
});
}
}
您可以使用以下 Create custom ESLint rules in 2 minutes.
将此新规则添加到您的 eslint 配置中这应该是一个更可靠的解决方案,但可能会突出显示您不想处理的其他错误。您可以使用 eslint override 来帮助将规则定位到您想要的文件。
// .eslintrc
{
"overrides": [
{
"files": ["some/path/*.ts"],
"rules": {
"my-project/no-empty-functions": "error"
}
}
]
}