Karma runner with Coverage - preprocessor not working on Javascript ES6 code

1.5k views Asked by At

I just recently started working with Karma runner in our UI5 app. Wrote some unit tests, ran them... all worked fine so far.

However, now I´ve decided to track the code coverage. To measure it, I need to run preprocessor on my source code. And this is where I stumbled upon a problems - I am currently trying to make it work and both have some kind of problems

  1. npm package karma-coverage as a preprocessor - after installing it, I set it up in karma.conf.js like this
preprocessors: {   
    "webapp/helpers/**/*.js": ['coverage'],  
    "webapp/controller/**/*.js": ['coverage'], 
},

This works fine on helpers folder since it contains only one file with simple javascript. However, when it tries to process controller folder which has files with some ES6 code, each file fails with errors such as these

Unexpected token function
Unexpected token ...
  1. As a second option, I tried to use karma-babel-preprocessor which should be able to handle also ES6 code. This is how my karma.conf.js file looks like

    preprocessors: { "webapp/helpers//.js": ['babel'], "webapp/controller//.js": ['babel'], },

    babelPreprocessor: {
      options: {
        presets: ['@babel/preset-env'],
        sourceMap: 'inline'
      } ,
      filename: function (file) {
        return file.originalPath.replace(/\.js$/, '.es5.js');
      },
      sourceFileName: function (file) {
        return file.originalPath;
      } 
    },
    

However, this one is not even able to find the js file (even though the address is the same as in the case of coverage preprocesor) and returns this error.

 Error: failed to load 'sbn/portal/helpers/formatter.js' from .webapp/helpers/formatter.js: 404 - Not Found
  at https://openui5.hana.ondemand.com/resources/sap-ui-core.js:86:37

Does someone have an idea how I can get the coverage data while using these packages or any other ones? There is a lots of conflicting info on the web, most of it several years old while various karma-related npm packages keep popping up each month so I am really not sure which one would be the best to use.

Thank a lot

1

There are 1 answers

2
Vlad Fernoaga On BEST ANSWER

We had the same problem and we managed to fix it integrating babel in a ui5-building-tool step.

This is how our package.json looks like:

 {
        "devDependencies": {
            "babel-core": "6.26.3",
            "babel-plugin-fast-async": "6.1.2",
            "babel-preset-env": "1.7.0",
            "karma": "^4.0.1",
            "karma-chrome-launcher": "^2.2.0",
            "karma-coverage": "^1.1.2",
            "karma-ui5": "^1.0.0",
            "karma-junit-reporter": "1.2.0",
            "rimraf": "^2.6.2",
            "start-server-and-test": "^1.4.1",
            "@ui5/cli": "^1.5.5",
            "@ui5/logger": "^1.0.0",
        }
        "scripts": {
            "start": "ui5 serve -o index.html",
            "lint": "eslint webapp",
            "test": "karma start",
            "build": "npm run test && rimraf dist && ui5 build --a --include-task=generateManifestBundle"
      }
    }

This is how the ui5.yaml is looking like

specVersion: '1.0'
metadata:
  name: app-name
type: application
builder:
    customTasks:
    - name: transpile
      afterTask: replaceVersion
---
specVersion: "1.0"
kind: extension
type: task
metadata:
    name: transpile
task:
    path: lib/transpile.js

This is how the transpile.js is looking like:

Be aware that this file should be placed in the root-dir/lib folder. root-dir is the folder where ui5.yaml is residing.

const path = require("path");
const babel = require("babel-core");
const log = require("@ui5/logger").getLogger("builder:customtask:transpile");

/**
 * Task to transpiles ES6 code into ES5 code.
 *
 * @param {Object} parameters Parameters
 * @param {DuplexCollection} parameters.workspace DuplexCollection to read and write files
 * @param {AbstractReader} parameters.dependencies Reader or Collection to read dependency files
 * @param {Object} parameters.options Options
 * @param {string} parameters.options.projectName Project name
 * @param {string} [parameters.options.configuration] Task configuration if given in ui5.yaml
 * @returns {Promise<undefined>} Promise resolving with undefined once data has been written
 */
module.exports = function ({
    workspace,
    dependencies,
    options
}) {
    return workspace.byGlob("/**/*.js").then((resources) => {
        return Promise.all(resources.map((resource) => {
            return resource.getString().then((value) => {
                log.info("Transpiling file " + resource.getPath());
                return babel.transform(value, {
                    sourceMap: false,
                    presets: [
                        [
                            "env",
                            {
                                exclude: ["babel-plugin-transform-async-to-generator", "babel-plugin-transform-regenerator"]
                            }
                        ]
                    ],
                    plugins: [
                        [
                            "fast-async",
                            {
                                spec: true,
                                compiler: {
                                    "promises": true,
                                    "generators": false
                                }
                            }
                        ]
                    ]
                });
            }).then((result) => {
                resource.setString(result.code);
                workspace.write(resource);
            });
        }));
    });
};

And finally this is the karma.conf.js setup:

module.exports = function (config) {
    var ui5ResourcePath = "https:" + "//sapui5.hana.ondemand.com/resources/";
    config.set({

        // the time that karma waits for a response form the browser before closing it
        browserNoActivityTimeout: 100000,

        frameworks: ["ui5"],

        // list of files / patterns to exclude
        exclude: [],

        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
           "root_to_to_files/**/*.js": ["coverage"],
        },

        // test results reporter to use
        // possible values: "dots", "progress"
        // available reporters: https://npmjs.org/browse/keyword/karma-reportery
        reporters: ["progress", "coverage"],

        // 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: false,

        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ["Chrome"],

        // Continuous Integration modey
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true,

        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity,

        // generates the coverage report
        coverageReporter: {
            type: "lcov", // the type of the coverage report 
            dir: "reports", // the path to the output directory where the coverage report is saved
            subdir: "./coverage" // the name of the subdirectory in which the coverage report is saved
        },

        browserConsoleLogOptions: {
            level: "error"
        }


    });
};

In our project this setup works fine with ES6 code and prints the coverage.

Hope this you help you. Please give me a feedback how this works.