Search code examples
angularkarma-jasminekarma-runnerautomerge

Karma-Jasmine do not identify all Angular unit tests when using Automerge package


Problem: Having a weird issue with the Karma runner. It does not identify all the unit tests while running ng test command.

Reproduce: I have created this stackblitz: https://stackblitz.com/edit/node-ooup44?file=my-workspace/projects/lib2/src/lib/lib2.component.ts

To first see the working version, run these commands:

cd my-workspace
ng test lib2

It will show the Karma page like this: enter image description here

To reproduce the issue, uncomment this code in the lib2.component.ts. if the page on the right does not refresh automatically then refresh it manually or rerun the ng test lib2 command in the terminal.

const appState: App2State = {
  doc: Automerge.from({
    name: 'test3',
    data: [],
  }),
  syncState: Automerge.initSyncState(),
};

Sometimes I encounter this error: Unhandled promise rejection: Error: 'describe' should only be used in 'describe' function enter image description here

Sometimes only unit tests work that do not implement/consume (eventually via parent library) Automerge package. enter image description here

Sometimes I don't get the describe.... error and only unit tests work that does not consume Automerge at all. This happens most of the time in my actual app. enter image description here

While debugging I found that whenever I remove all Automerge usage (from(), initSyncState()) the unit tests start working. Basically whenever karma runner tries to run a unit test that is connected to the Automerge package then it starts failing.

I could confirm that this is not a cache issue, I have tried clearing both Angular and Browser caches.

[UPDATE]

While debugging I found that even if directly use Automerge package in a component then its respective test won't get executed.

Here is the stackblitz URL: https://stackblitz.com/edit/node-mcrcay?file=my-workspace%2Fsrc%2Fapp%2Fapp.component.ts

To reproduce the issue uncomment this code in the app.component.ts and run ng test command.

const test = from({
  test: 'test',
});

You will not notice any unit test in the Karma runner, but if you want to see the working unit tests then keep the code commented in the app.comment.ts and then run ng test, you will see 3 unit tests for the AppCompoennt in the Karma runner.

Raised an issue in Karma runner Github repo: https://github.com/karma-runner/karma/issues/3836


Solution

  • To address this issue, we will use a polyfill. A polyfill is a piece of code that implements a feature on web browsers that do not natively support it.

    To add the necessary code in your polyfills.ts file, include the following:

    import '@automerge/automerge';
    import '@automerge/automerge-wasm' // this solves it all
    
    

    This addition resolves the problem with browsers not being able to handle .wasm files. However, if you need to handle complex requirements such as processing time, you can set up a preprocessor. You can achieve this by using a custom webpack configuration. In an Angular project, webpack runs under the hood without the need to create it, but you can create a webpack.config.js file for customization purposes:

    Create a file webpack.config.js

    module.exports = {
      devtool: 'inline-source-map',
      experiments: {
        asyncWebAssembly: true,
      },
      target: "web",
      mode: "development", // or production
      performance: {
        hints: false,
        maxEntrypointSize: 512000,
        maxAssetSize: 512000,
      },
      module: {
        rules: [
          {
            test: /\.ts$/,
            loader: 'ts-loader',
          },
          {
            test: /\.html$/,
            loader: 'raw-loader',
            exclude: /\.async\.(html|css)$/
          },
          {
            test: /\.wasm$/,
            type: 'webassembly/experimental', // Ensure the Wasm files are handled correctly
            use: [
              {
                loader: 'wasm-loader',
                options: {
                  esModule: true,
                },
              },
            ],
          },
          {
            test: require.resolve('./src/main.ts'),
            use: 'imports-loader?wrapper=window',
          }
        ],
      },
      resolve: {
        extensions: ['.ts', '.js', '.wasm'],
      },
    };
    
    

    In the above code, I enhanced the performance and handling of execution time by defining a custom webpack configuration. If you are not dealing with specific performance requirements, the default polyfill.ts file with addition of imports should work perfectly fine.

    In your karma.conf.js file, make the following changes:

    module.exports = function (config) {
      config.set({
        basePath: '',
        frameworks: ['jasmine', '@angular-devkit/build-angular','webpack'],
        plugins: [
          require('karma-jasmine'),
          require('karma-chrome-launcher'),
          require('karma-webpack'),
          require('@angular-devkit/build-angular/plugins/karma'),
          require('karma-jasmine-html-reporter'),
          require('karma-coverage'),     
        ],
        client: {
          clearContext: false // leave Jasmine Spec Runner output visible in browser
        },
        jasmineHtmlReporter: {
          suppressAll: true // removes the duplicated traces
        },
        coverageReporter: {
          dir: require('path').join(__dirname, './coverage/automerge-example'),
          reporters: [
            { type: 'html' },
            { type: 'text-summary' }
          ]
        },
        preprocessors: {
          'src/**/*.spec.ts': ['webpack'],
        },
        webpack: require('./webpack.config.js'),
        reporters: ['progress', 'kjhtml'],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browsers: ['Chrome'],
        singleRun: false,
        restartOnFileChange: true,
      });
    };
    

    Note: When requiring webpack.config.js, I instructed Karma to use webpack for preprocessing, specifically for the spec.ts extension. Additionally, make sure to install karma-webpack and wasm-loader if you need to handle performance and other related aspects.

    enter image description here