angularunit-testingkarma-runner

karma don't see my test files and display this error "karma_error Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire')"


I'm trying to run my angular test with jasmine+karma. When i run karma start karma.conf.js it compile but i have a karma_error Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire') on browser and my files are not seen. Here's my karma.conf.js :

// Karma configuration
// Generated on Mon Dec 02 2024 15:28:03 GMT+0100 (Central European Standard Time)


module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    frameworks: ['jasmine', 'requirejs', 'karma-typescript'],

    plugins: [
      require('jasmine'),
      require('karma-jasmine'),
      require('karma-requirejs'),
      require('karma-typescript'),
      require('karma-babel-preprocessor'),
      require('karma-chrome-launcher'),
      require('@angular-devkit/build-angular')
    ],
    // list of files / patterns to load in the browser
    files: [
      'test-main.js',
      {
        pattern: 'src/app/**/*.ts',
        type: 'module'
      },
    ],


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


    // preprocess matching files before serving them to the browser
    preprocessors: {
      '**/*.ts': ['babel'],
      '**/*.js': ['babel']
    },
    babelPreprocessor: {
      // options go here
      options: {
        presets: [ "@babel/preset-typescript", "@babel/preset-env"],
        sourceMap: "inline"
      },
    },
    karmaTypescriptConfig: {
      compilerOptions: {
          emitDecoratorMetadata: true,
          experimentalDecorators: true,
          jsx: "react",
          sourceMap: true,
          moduleResolution: "node",
          target: "esnext",
          module: "esnext"
      },
      tsconfig: 'tsconfig.json',
      exclude: ["node_modules"]
  },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    reporters: ['progress', 'karma-typescript'],


    // 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_DEBUG,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    browsers: ['ChromeHeadless'],
    customLaunchers: {
      ChromeHeadless: {
        base: 'Chrome',
      flags: ['--no-sandbox']
      }
    },

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

    // Concurrency level
    // how many browser instances should be started simultaneously
    concurrency: Infinity
  })
}

my tsconfig.json :


{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "declaration": false,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "ESNext",
    "module": "ESNext",
    "types": ["karma", "jasmine"],
    "lib": [
      "ESNext",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

my tsconfig.spec.json :


{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": [
      "jasmine",
      "node",
      "@angular/localize"
    ],
    "target": "ESNext",
    "module": "ESNext"
  },
  "include": [
    "src/app/**/*.spec.ts",
    "src/**/*.d.ts"
  ],
  "exclude": ["node_modules"]
}

and my package.json :

{
  "name": "simulator",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test",
    "serve:ssr:simulator": "node dist/simulator/server/server.mjs",
    "lint": "ng lint"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^18.1.0",
    "@angular/cdk": "^18.2.5",
    "@angular/common": "^18.1.0",
    "@angular/compiler": "^18.1.0",
    "@angular/core": "^18.1.0",
    "@angular/fire": "^18.0.1",
    "@angular/forms": "^18.1.0",
    "@angular/material": "^18.2.9",
    "@angular/platform-browser": "^18.1.0",
    "@angular/platform-browser-dynamic": "^18.1.0",
    "@angular/platform-server": "^18.1.0",
    "@angular/router": "^18.1.0",
    "@angular/ssr": "^18.1.1",
    "@ng-bootstrap/ng-bootstrap": "^17.0.1",
    "@popperjs/core": "^2.11.8",
    "bootstrap": "^5.3.2",
    "express": "^4.18.2",
    "firebase": "^11.0.1",
    "lint": "^0.8.19",
    "ngx-currency": "^18.0.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^18.1.1",
    "@angular/cli": "^18.2.12",
    "@angular/compiler-cli": "^18.1.0",
    "@angular/localize": "^18.1.4",
    "@babel/core": "^7.26.0",
    "@babel/plugin-proposal-decorators": "^7.25.9",
    "@babel/plugin-transform-typescript": "^7.25.9",
    "@babel/preset-env": "^7.26.0",
    "@babel/preset-typescript": "^7.26.0",
    "@types/express": "^4.17.17",
    "@types/jasmine": "~5.1.0",
    "@types/karma": "^6.3.9",
    "@types/node": "^18.18.0",
    "angular-eslint": "18.4.1",
    "eslint": "^9.15.0",
    "jasmine": "^5.4.0",
    "jasmine-core": "^5.4.0",
    "karma": "~6.4.0",
    "karma-babel-preprocessor": "^8.0.2",
    "karma-chrome-launcher": "~3.2.0",
    "karma-cli": "^2.0.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "^5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "karma-requirejs": "^1.1.0",
    "karma-typescript": "^5.5.4",
    "ts-node": "^10.9.2",
    "typescript": "~5.5.2",
    "typescript-eslint": "8.15.0"
  }
}

I retried to run karma init to have an initial setup but my test files are not seen by karma. I added babel as preprocessor but I have the error karma_error Uncaught TypeError: Cannot set properties of undefined (setting 'jasmineRequire')

so, I need some help to resolve this issue. Thanks

UPDATE

I installed webpackand webpack-cli, add a webpack.config.js and still have an error : ERROR [karma-server]: TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined

the webpack.config.js :

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const isProduction = process.env.NODE_ENV == "production";

const stylesHandler = isProduction
  ? MiniCssExtractPlugin.loader
  : "style-loader";

const config = {
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    // Add your plugins here
 
  ],
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/i,
        loader: "ts-loader",
        exclude: ["/node_modules/"]
      },
      {
        test: /\.css$/i,
        use: [stylesHandler, "css-loader"]
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
        type: "asset"
      }

      // Add your rules for custom modules here
     
    ]
  },
  resolve: {
    extensions: [".tsx", ".ts", ".jsx", ".js", "..."]
  }
};

module.exports = () => {
  if (isProduction) {
    config.mode = "production";

    config.plugins.push(new MiniCssExtractPlugin());
  } else {
    config.mode = "development";
  }
  return config;
};

UPDATE 2

After update my karma.conf.js file like this :

 preprocessors: {
      'src/app/**/*.spec.ts': ['webpack'],
      'src/**/*.js': ['webpack']
    },

webpack preprocess test files but now I have an error related to the loader :

ERROR in ./src/app/app.component.spec.ts 17:13
Module parse failed: Unexpected token (17:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| describe('AppComponent', () => {
| 
>   let fixture: ComponentFixture<AppComponent>;
|   let modalService: NgbModal;
|   let modalRef: NgbModalRef; 

ERROR in ./src/app/email-checker-api.service.spec.ts 7:13
Module parse failed: Unexpected token (7:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
| describe('EmailCheckerApiService', () => {
>   let service: EmailCheckerApiService;
| 
|   beforeEach(() => {

ERROR in ./src/app/email.service.spec.ts 8:13
Module parse failed: Unexpected token (8:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
| describe('EmailService', () => {
>   let service: EmailService;
| 
|   beforeEach(() => {

ERROR in ./src/app/form/form.component.spec.ts 9:15
Module parse failed: Unexpected token (9:15)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
| describe('FormComponent', () => {
>   let component: FormComponent;
|   let fixture: ComponentFixture<FormComponent>;
| 

ERROR in ./src/app/message.service.spec.ts 6:13
Module parse failed: Unexpected token (6:13)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| 
| describe('MessageService', () => {
>   let service: MessageService;
| 
|   beforeEach(() => {

1 error has detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.

I installed the ts-loader package and removed node_modules and reinstall it. No luck, the package seems not to be loaded by thee webpack config


Solution

  • ok, finally I switched to jest framework and followed the setup from the doc here.

    My jest.conf.js is like :

    module.exports = {
      testEnvironment: "jsdom",
      preset: "jest-preset-angular",
      setupFilesAfterEnv: ["<rootDir>/setup-jest.ts"],
      moduleNameMapper: {
        '^.+\\.html$': '<rootDir>/src/__mocks__/htmlMock.js',
        '^.+\\.(css|scss)$': 'identity-obj-proxy',
      },
      transform: {
        "^.+.(tsx?)$": ["jest-preset-angular"],
        "^.+.jsx?$": 'babel-jest',
      },
      transformIgnorePatterns: [
        "node_modules/(?!(@angular|@ng-bootstrap|ngx-*)/*)"
      ],
     moduleFileExtensions: ['js', 'ts', 'tsx', 'json', 'node'],
    };
    

    I added the jest-preset-angular as additional package and add htmlMocks.js file :

    module.exports = '';
    

    My setup-jest.ts is like :

    import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
    import './jest-global-mocks';
    
    setupZoneTestEnv();
    

    I also added jest-global-mocks.ts to handle html files as explained by this resource as it :

    Object.defineProperty(document, 'doctype', {
      value: '<!DOCTYPE html>',
    });
    Object.defineProperty(window, 'getComputedStyle', {
      value: () => {
        return {
          display: 'none',
          appearance: ['-webkit-appearance'],
        };
      },
    });
    /**
     * ISSUE: https://github.com/angular/material2/issues/7101
     * Workaround for JSDOM missing transform property
     */
    Object.defineProperty(document.body.style, 'transform', {
      value: () => {
        return {
          enumerable: true,
          configurable: true,
        };
      },
    });
    

    and voila!