jeudi 5 septembre 2019

How to send CircleCI test glob to karma/webpack?

I am using CircleCI 2.1 to split my tests based on filesize. My goal is to take advantage of Circle's parallelism feature where each test glob runs in parallel. (So if I have four containers, the tests are evenly split across all four).

I can pass a glob via npm command to my karma config - but from that point it is unclear how to tell karma and/or webpack that I have a specific array of filepaths (strings) that I want to test on each container. I've tried to strip out from my config examples props that I felt were pretty irrelevant.

Here's my ci command

TESTFILES=$(circleci tests glob "./src/app/**/*.spec.ts" | circleci tests split --split-by=filesize)

// writing array of str to a js file that karmaConfig.files can use
mkdir -p ~/project/globs
touch ~/project/globs/globs.js 
echo ${TESTFILES} >> ~/project/globs/globs.js 

//OR passing as arg

npm run circle-test:ng1 -- ${TESTFILES}

here is a barebones karma config


function getWebpackConfig(coverage) {
  const webpackOpts = {
    target: 'dev',
    framework: 'ng1',
    coverage,
    output: {
      pathinfo: false,
    },
    paths: undefined,
  };
  const configureWebpack = require('./webpack.tests.config');
  const webpackConfig = configureWebpack(webpackOpts);
  webpackConfig.devtool = 'cheap-eval-source-map';
  delete webpackConfig.entry;

  return webpackConfig;
}

module.exports = function(config) {
  const coverage = config.coverage;
  const headless = config.headless;
  const browser = headless ? 'ChromeHeadless' : 'Chrome';
  let webpackConfig;


  const karmaConfig = {
    bail: true,
    basePath: '',
    files: [
      { pattern: './test/testVendor.js', watched: false },
      { pattern: './test/testIndex-ng1.js', watched: false },
      { pattern: './test/helpers.js', watched: false },
    ],
    preprocessors: {
      './test/testVendor.js': ['webpack', 'sourcemap'],
      './test/testIndex-ng1.js': ['webpack', 'sourcemap'],
      './test/helpers.js': ['webpack', 'sourcemap'],
    },
    webpack: webpackConfig,   
  };


  // if  receiving command line  argsget array of filepath strings
  const glob = process.argv.slice(7, process.argv.length);

  // WHAT NOW? what to pass to karma / webpack / both?

if (glob) {
    const paths = _.map(glob, str => {
      return `./${str}`;
    });
    webpackConfig = getWebpackConfig(coverage);
    //webpackConfig.entry = paths;
  } else {
    webpackConfig = getWebpackConfig(coverage);
  }

  config.set(karmaConfig);
};



and here is the webpack config:

const path = require('path');
const webpack = require('webpack');
const getWebpackOpts = require('./webpack.opts');

module.exports = function(env) {
  const { babelOptions, devtool } = getWebpackOpts(env);

  const config = {

    resolve: {
      extensions: ['.js', '.ts'],
      alias: {
        // This alias is a shortcut for the root of the app (the './src' folder). Don't use this for new require or
        // import statements. It is just to make migrating template urls easier.
        Src: path.resolve(__dirname, './src'),
      },
    },
    output: {
      pathinfo: false,
    },
    optimization: {
      removeAvailableModules: false,
      removeEmptyChunks: false,
      splitChunks: false,
    },
    module: {
      rules: [
        // --- TypeScript Files
        {
          test: /\.ts$/,
          exclude: /(node_modules)/,
          use: [
            {
              loader: 'ts-loader',
              options: {
                transpileOnly: true,
                experimentalWatchApi: true,
              },
            },
            'angular2-template-loader',
          ],
        },
        // --- Javascript Files
        {
          test: /\.js$/,
          exclude: /(node_modules)/,
          use: [{ loader: 'babel-loader?cacheDirectory', options: babelOptions }],
        },
        // --- HTML templates
        {
          test: /\.html$/,
          // exclude: path.resolve(__dirname, './src/index.html.ejs'),
          use: ['raw-loader'],
        },
        // -- CSS templates
        {
          test: /\.css$/,
          use: ['to-string-loader', { loader: 'css-loader', options: { sourceMap: true, minimize: false } }],
        },

        // -- SCSS templates
        {
          test: /\.scss$/,
          use: [
            'to-string-loader',
            { loader: 'css-loader', options: { sourceMap: true, minimize: false } },
            { loader: 'sass-loader', options: { sourceMap: true, minimize: false } },
          ],
        },
        {
          // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
          // Removing this will cause deprecation warnings to appear.
          test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
          parser: { system: true }, // enable SystemJS
        },
        // --- Images
        {
          test: /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
          loader: 'file-loader',
        },
      ],
    }
  };

  return config;
};


The desired result would be that each container takes a percentage of the tests. What is actually happening is that the full test suite is being run within each container.

Aucun commentaire:

Enregistrer un commentaire