Loading Externals & Vendors in Webpack Files array causes tests to run multiple times

79 views Asked by At

I'm upgrading from Webpack v4 to Webpack v5, and my tests are running 4 times. (only ran once in Webpack v4)

Narrowed it down to this files array in the karma config:

config.set({
    files: [
        {
            pattern: "public/dist/js/global/knockout-bundle.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "node_modules/jquery/dist/jquery.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/global/portal.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/global/foundation.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/models/user.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "js/tests/unit/modern.testContext.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/common/images/**/*.+(jpg|png|svg)",
            watched: false,
            included: false,
            served: true,
            nocache: false,
        },
    ],
})

If I remove these following first set of files, (all but the last included: true), then the tests only run once:

        {
            pattern: "public/dist/js/global/knockout-bundle.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "node_modules/jquery/dist/jquery.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/global/portal.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/global/foundation.min.js",
            watched: false,
            included: true,
        },
        {
            pattern: "public/dist/js/models/user.min.js",
            watched: false,
            included: true,
        },

The problem is these globals are needed for this PHP SSR app. Many of the tests need this code/ these packages. I know it has something to do with the included flag being true for all these. However, we need all these to be included or else jquery, knockout etc will not work.

I have tried using bowerOptions in the karma config like so, did not work:

        bowerOptions: [
            "jquery",
            "knockout",
        ],

Note, also have externals in the webpack config section like so:

{
    webpack:    
        externals: {
            moment: "moment",
            jquery: "jQuery",
            knockout: "ko",
        },
    },
}

How do I keep the externals, and not have the tests run more than once?

The tests only run one time in Webpack v4.

--------------------

Here's the full setup:

MAIN CONFIG:

const applyDefaultConfig = require("./karma.default.conf");
const webpackTestingConfig = require("./webpack.config.test");

module.exports = (config) => {

    applyDefaultConfig(config);

    config.set({
        files: [
            {
                pattern: "public/dist/js/global/knockout-bundle.min.js",
                watched: false,
                included: true,
            },
            {
                pattern: "node_modules/jquery/dist/jquery.min.js",
                watched: false,
                included: true,
            },
            {
                pattern: "public/dist/js/global/portal.min.js",
                watched: false,
                included: true,
            },
            {
                pattern: "public/dist/js/global/foundation.min.js",
                watched: false,
                included: true,
            },
            {
                pattern: "public/dist/js/models/user.min.js",
                watched: false,
                included: true,
            },
            {
                pattern: "js/tests/unit/modern.testContext.js",
                watched: false,
                included: true,
            },
            {
                pattern: "public/common/images/**/*.+(jpg|png|svg)",
                watched: false,
                included: false,
                served: true,
                nocache: false,
            },
        ],

        proxies: {
            "/api/image/": "",
            "/common/images/": "",
        },

        preprocessors: {
            "js/tests/unit/modern.testContext.js": ["webpack", "sourcemap"],
        },

        webpack: webpackTestingConfig,

        reporters: ["mocha", "coverage-istanbul", "junit"],

        coverageIstanbulReporter: {
            reports: ["html", "text-summary"],
            dir: __dirname + "/../../../tests/_output/coverage-js/modern/",
            fixWebpackSourcePaths: true,
        },

        junitReporter: {
            outputDir: __dirname + "/../../../tests/_output/junit/",
            outputFile: "JunitTestOutput.xml",
        },

        webpackMiddleware: {
            stats: "errors-only",
        },

        webpackServer: {
            noInfo: false,
            progress: true,
        },

    });

};

DEFAULT CONFIG:

const { Browser } = require("selenium-webdriver");
require("dotenv").config();

module.exports = function(config) {
    "use strict";

    const hostname = process.env.JS_KARMA_HOSTNAME || "webhost";

    config.set({

        basePath: process.env.JS_TESTS_ROOT_DIR || process.env.APPLICATION_ROOT,

        hostname,

        frameworks: ["mocha", "chai", "sinon", "webpack"],

        plugins: [
            "karma-webpack",
            "karma-mocha",
            "karma-chai",
            "karma-coverage",
            "karma-coverage-istanbul-reporter",
            "karma-junit-reporter",
            "karma-mocha-reporter",
            "karma-sinon",
            "karma-sourcemap-loader",
            "karma-webdriver-launcher",
        ],

        files: [],

        preprocessors: {},

        reportSlowerThan: 100,

        webpackMiddleware: {
            stats: "errors-only",
        },

        webpackServer: {
            noInfo: true,
        },

        exclude: [],

        reporters: ["mocha"],

        mochaReporter: {
            showDiff: true,
        },

        port: 9876,

        colors: true,

        logLevel: config.LOG_INFO,

        browserConsoleLogOptions: {
            level: "warn",
            format: "%b %T: %m",
            terminal: false,
        },

        browsers: ["Chrome_no_sandbox"],
        browserDisconnectTimeout: 60000,
        browserNoActivityTimeout: 30000,
        processKillTimeout: 10000,

        concurrency: Infinity,

        client: {
            captureConsole: true,
            args: [`hostname_karma_server=${hostname}`],
        },

        failOnEmptyTestSuite: true,

        customLaunchers: {
            Chrome_no_sandbox: {
                base: "WebDriver",
                browserName: Browser.CHROME,
                config: {
                    hostname: "chromium",
                    port: 4444,
                },
                
                "goog:chromeOptions": {
                    args: [
                        "--no-sandbox",
                        "--disable-setuid-sandbox",
                        "--headless=chrome",
                        "--disable-gpu",
                        "--remote-debugging-port=9222",
                        "--no-default-browser-check",
                        "--no-first-run",
                        "--disable-default-apps",
                        "--disable-popup-blocking",
                        "--disable-translate",
                        "--disable-background-timer-throttling",
                        "--disable-renderer-backgrounding",
                        "--disable-device-discovery-notifications",
                    ],
                },
                pseudoActivityInterval: 30000,
            },
        },
    });
};

WEBPACK CONFIG:

require("dotenv").config();

const webpackUtils = require("../../../webpack/webpack.config.utils");
const { DefinePlugin } = require("webpack");
const { VueLoaderPlugin } = require("vue-loader");
const VueTemplateCompiler = require("vue-template-compiler");

module.exports = {

    target: "web",

    mode: "development",

    devtool: "eval-cheap-module-source-map",

    plugins: [

        new DefinePlugin({
            APP_ENV: JSON.stringify(process.env.APP_ENV),
        }),

        new VueLoaderPlugin(),

    ],

    resolve: {

        alias: {
            main: webpackUtils.getAbsolutePath("js/main"),
        },

        modules: [
            "node_modules",
        ],

        extensions: [".ts", ".js"],

    },

    module: {

        rules: [

            {
                // for parsing .vue files
                test: webpackUtils.VUE_FILE_REGEX,
                loader: "vue-loader",
                options: {
                    compiler: VueTemplateCompiler,
                },
            },

            {
                // convert javascript from es6 to es5
                test: webpackUtils.JS_BABEL_REGEX,
                exclude: webpackUtils.VENDORS_REGEX,
                use: {
                    loader: "babel-loader",
                    options: {
                        cacheDirectory: true,
                        cacheCompression: false,
                        presets: [
                            [
                                "@babel/preset-env",
                                {
                                    targets: "defaults, node >= 12",
                                    useBuiltIns: "usage",
                                    corejs: "3.25",
                                },
                            ],
                        ],
                    },
                },
            },

            {
                // for code coverage
                test: webpackUtils.JS_FILE_REGEX,
                exclude: webpackUtils.JS_TESTS_REGEX,
                use: "@jsdevtools/coverage-istanbul-loader",
            },

            {
                test: /\.ts$/,
                use: "babel-loader",
                exclude: webpackUtils.VENDORS_REGEX,
            },

        ],

    },

    externals: {
        moment: "moment",
        jquery: "jQuery",
        knockout: "ko",
    },

};

TESTCONTEXT:

const importAll = (r) => {
    r.keys().forEach(r);
};

importAll(require.context("./modern/features", true, /\.(spec|test)\.js$/));
importAll(require.context("./modern/main", true, /\.(spec|test)\.js$/));

WEBPACK UTILS:

const resolve = require("path").resolve;

module.exports = {

    VENDORS_REGEX: /(node_modules)/,

    JS_TESTS_REGEX: /(\.test\.js|\.spec\.js|\.testContext.js$)/,

    JS_FILE_REGEX: /\.js$/,

    JS_BABEL_REGEX: /(?<!\.min)\.js$/,

    VUE_FILE_REGEX: /\.vue$/,

    getAbsolutePath: function getAbsolutePath(pathToFile) {
        return pathToFile ? resolve(__dirname, "../", pathToFile) : resolve(__dirname, "../");
    },

};
0

There are 0 answers