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"
            }
        }
    ]
}