Angular 1.5 Karma unit test causes duplicate loading of ng-mock library

My current web app is built using Typescript 2.4.2 and compiled with the latest Webpack version (2.7.0).

I am in the process of incorporating Karma tests utilizing Jasmine as the assertion library.

Below is my karma configuration file:

'use strict';

const webpack = require('./webpack.config');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const _ = require('lodash');

_.remove(webpack.plugins, plugin => plugin instanceof CleanWebpackPlugin);

webpack.module.rules.forEach(rule => {
    if (rule.loader === 'ts-loader') {
        rule.exclude = /sg\.d\.ts/;
    }
}); 

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

        mime: {
            'text/x-typescript': ['ts','tsx']
        },

        // base path used to resolve all patterns (e.g., files, exclude)
        basePath: '',

        // frameworks to utilize
        frameworks: ['jasmine'],

        // list of files/patterns to load in the browser
        files: [
            { pattern: 'app/scripts/**/*.test.ts', watched: true}
        ],

        preprocessors: {
            "app/scripts/**/*.test.ts": ["webpack"]
        },

        exclude: [],

        reporters: ['progress', 'mocha'],

        port: 9876,

        colors: true,

        logLevel: config.LOG_INFO,
        
        autoWatch: true,

        browsers: ['jsdom', /*'Chrome'*/],

        singleRun: false,

        concurrency: Infinity
    })
}

The initial test suite ran smoothly, resembling this structure:

import { default as moduleName } from "../module";
import { ListService, IListRequest } from "./listService";
import * as angular from 'angular';
import "angular-mocks";
import "jasmine";

const { module, inject } = angular.mock;

describe("List service", () => {

    let serviceToTest: ListService;

    let rootScope: ng.IRootScopeService;
    let httpBackend: ng.IHttpBackendService;

    beforeEach(module(moduleName));

    beforeEach(() => {
        inject(['$rootScope', '$httpBackend', ListService.SERVICE_NAME,
            ($rootScope: ng.IRootScopeService, $httpBackend: ng.IHttpBackendService, listService: ListService) => {
                serviceToTest = listService;
                rootScope = $rootScope;
                httpBackend = $httpBackend;
            }]);
    });

    it("service should not be null", () => {
        expect(serviceToTest).toBeDefined();
    });

    // Additional tests
});

However, as soon as I tried adding another test suite for a separate service, issues arose:

import { default as moduleName } from "../module";
import { RedirectionService } from "./RedirectionService";
import * as angular from 'angular';
import "angular-mocks";
import "jasmine";

const { module, inject } = angular.mock;

describe('Redirection service', () => {
});

You might have noticed that the second test suite is presently empty.

The issue emerges when Angular begins throwing errors upon the addition of the second suite - attempting to load Angular and ng-mock twice, once for each new imported file.

An error message surfaces stating:

Error: [$injector:modulerr] Failed to instantiate module ngLocale due to: RangeError: Maximum call stack size exceeded

After conducting a swift Google search, numerous threads suggest that the problem arises when Karma loads ng-mock twice. Inspecting the code on Chrome confirms that the initialization of ngMock fails, triggering a warning from Angular about its double loading.

What measures can I take to address this situation? It appears that Karma treats each test file independently, neglecting to bundle Angular through Webpack into a singular module but rather compiling each file individually and re-adding Angular and ng-mock.

Answer №1

I decided to take a different path as I was unable to find a solution to that particular issue.

In my updated webpack configuration, I have made the following changes:

 entry: { entry: './app/scripts/main.ts'},
    output: {
        filename: isDev ? "[name].js" : '[name]-[hash].js',
        path: path.resolve('dist'),
        pathinfo: isDev
    },
...
if (isDev) {
    module.exports.devtool = 'source-map';
    module.exports.entry.test = './test/test-main.ts';
}

Furthermore, I have removed all the webpack configurations from the Karma setup.

Now, I have instructed Webpack to compile an additional bundle with a basic TypeScript entry file that contains the following code:

Import((<any>require).context('../app/scripts/', true, /.*\.test\.ts$/i), (_: any) => {});

Karma is now monitoring the changes in the output bundle file.

Answer №2

To solve this issue, I created a file named angular-services.test.ts which includes all the tests utilizing angular-mock. These tests make use of functions like angular.mock.module and inject.

Here is the content of angular-services.test.ts:

import 'angular';
import 'angular-mocks';

import 'test_angular_service_1.test'
import 'test_angular_service_2.test'
.
.
import 'test_angular_service_n.test'

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

DataGrid parameters in Material UI are only considering the final value in the table

I am working with a Data Grid table containing user information, and I want to include a sub-menu of options in the last column that opens up a modal for each user. However, I am facing an issue where only the data from the final row in the table is being ...

Using type definitions in non-TS files with VSCode: A beginner's guide

My code is not in TypeScript, shown here: // foo.js module.exports = app => { // some logic here } I want to enhance my development experience by using TypeScript definition files to specify the type of the argument app, enabling VSCode to provide ...

The css-loader in Webpack fails to recognize the localIdentName option

Currently, I am utilizing the css-loader as a Webpack plugin to modify my CSS class names. However, I am facing an issue where the localIndentName option is not having any effect. Below is the snippet of my webpack configuration related to the css-loader: ...

The primary export is not a React Component on the specified page: "/"

Encountering an error while attempting to use compiled code from Typescript to Javascript with Next.js Error message: The default export is not a React Component in page: "/" Seeking assistance on how to resolve this issue. Any help would be greatly appr ...

Has Angular been assimilated into the window object by webpack?

I'm encountering a puzzling issue with webpack that I can't seem to resolve. Here is the link to my webpack.config file: https://github.com/saike/maluvich-browser/blob/master/webpack.config.babel.js In my project, I import angular using ES6 mo ...

"Differences between a .js server, webpack, and how to plan

I'm feeling a bit overwhelmed. I recently started delving into node.js with the MEAN stack after previously using webpack and browserify without fully grasping their concepts. What's really puzzling me is the following: Express starts a server ...

Error TS2322: You cannot assign a Promise<any> to a string type

Having an issue in my react app where I am attempting to import the img source but encountering an error: TS2322: Type 'Promise<any>' is not assignable to type 'string'. What is the correct way to import an element into a variabl ...

Disabling an anchor using the 'disabled' property is proving to be a challenge for me

I'm attempting to dynamically enable or disable an anchor element based on the user's role. So far, I've tried a few different methods: document.getElementById('myBtn').disabled = true; However, this returns an error: The propert ...

Use a function on values that have corresponding keys in a separate array

I am working with a form.value object that looks like this: form.value = { "to_date": "2019-03-21T05:00:00.000Z", "from_date": "2019-03-13T05:00:00.000Z", "is_form": "" "errors":"" } Additionally, I have an array called filterArray: filterArray ...

"Efficient ways to calculate the total sum of an array of objects based on a specific property

I currently have a straightforward method that calculates the total sum of an object array based on one of the properties. const calculateSum = <T extends object, K extends keyof T>(array: T[], property : K) : number =>{ let total = 0; if ( ...

Limiting the Size of Highcharts Maps with maxWidth or maxHeight

My attempt to adjust the maxWidth of my world map using highcharts isn't altering its size. I have experimented with the following: responsive: { rules: [{ condition: { maxWidth: 500 }, ... As recomme ...

Inquiring about Vue 3 with TypeScript and Enhancing Types for Compatibility with Plugins

I've been struggling to find a working example of how to implement type augmentation with Vue3 and TypeScript. I have searched for hours without success, trying to adapt the Vue2 documentation for Vue3. It appears that the Vue object in the vue-class ...

Turn off the `noImplicitAny` TypeScript rule for a specific line of code

With "noImplicitAny": true enabled in my tsconfig.json, I encountered the TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}' error within my code space ...

Using react-scripts leads TypeScript to mistakenly search for the incorrect file to import

Currently utilizing React and Relay in my project, I've encountered an issue with TypeScript. After relocating the directory where Relay generates some TypeScript files that are included in my app, TypeScript is unable to find them, presenting an unus ...

Creating or deleting multiple batches of entries in Firebase Realtime Database

I am currently utilizing Firebase real time database in the following way: createSoldLead(soldLead: SoldLeadModel): void { const soldLeadsReference = this.angularFireDatabase.list<SoldLeadModel>( `groups/${this.groupId}/soldLeads` ); ...

Issue with Angular 6 Share module functionality not functioning as expected

While creating my Angular 6 application, I encountered an issue with sharing a header across multiple pages. I tried including it but it doesn't seem to be working. Can anyone point out what I might be doing wrong? For a demonstration, you can visit . ...

Exploring the Angular Heroes Journey: What's the significance of one being labeled with a colon while the other is identified

Setting: Angular 5+ Source: https://angular.io/tutorial Within the heroes.component.ts class, we see an assignment using a colon: export class HeroesComponent implements OnInit { heroes: Hero[]; However, in the app.component.ts class, a different as ...

What is the best way to define the type of an object in TypeScript when passing it to a function

I am currently working on a function that accepts an object of keys with values that have specific types. The type for one field is determined by the type of another field in the same object. Here is the code: // Consider this Alpha type and echo function. ...

What are the steps to utilize webpack for refreshing the script tag in a jade file?

Can webpack be used to automatically update the script tag in a jade/pug template to point to the minified and cache-busted JS bundle? Most examples I've come across demonstrate how plugins can be used to convert the jade template to HTML, but I am us ...

Error: The file named '/accounts.ts' cannot be recognized as a module within a Node.js API

After researching this issue, I have found some answers but none of them seem to solve my problem. Below is the code in my model file: // accounts.ts const mongoose = require('mongoose'); var autoincrement = require('simple-mongoose-autoi ...