Encountering the error "Cannot access property 'on' of undefined" during Angular unit testing with Karma and Jasmine

Inside my component.ts file, I have a service called 'socketService' that utilizes socket functionality. Within the component, I include the following code:

this.socket = this.socketService.getSocketIOConnector(this.data.product)
this.socket.on('connected', (message: string) => {
    this.connectionMsg = message
})

In my spec.ts file, the setup includes:

beforeEach(async(() => {
  fixture = TestBed.createComponent(OndemandComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
}));
it("should check the socket service", inject([SocketioService], (socketioService: SocketioService) => {
  socketioService = TestBed.get(SocketioService);
  const spy = spyOn(socketioService, "getSocketIOConnector");
  expect(spy).toHaveBeenCalled();
}));
it("should create", () => {
  expect(component).toBeTruthy();
});

During testing, an error is encountered: TypeError: Cannot read property 'on' of undefined near the line containing this.socket.on in the component.

Answer №1

Failure to simulate the return value of getSocketIOConnector method caused the error. It is crucial to remember to execute fixture.detectChanges(); after mocking in order to activate the ngOnInit method of the component.

Take a look at this functional demonstration utilizing angular version 11+:

ondemand.component.ts:

import { Component, OnInit } from '@angular/core';
import { SocketService } from './socket.service';

@Component({})
export class OndemandComponent implements OnInit {
  socket: SocketService;
  data = {
    product: 'real product',
  };
  connectionMsg: string;
  constructor(private socketService: SocketService) {}
  ngOnInit() {
    this.socket = this.socketService.getSocketIOConnector(this.data.product);
    this.socket.on('connected', (message: string) => {
      this.connectionMsg = message;
    });
  }
}

socket.service.ts:

import { Injectable } from '@angular/core';

@Injectable()
export class SocketService {
  getSocketIOConnector(params) {
    return this;
  }
  on(event, listener) {}
}

ondemand.component.spec.ts:

import { ComponentFixture, inject, TestBed } from '@angular/core/testing';
import { OndemandComponent } from './ondemand.component';
import { SocketService } from './socket.service';

fdescribe('65302152', () => {
  let fixture: ComponentFixture<OndemandComponent>;
  let component: OndemandComponent;
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [OndemandComponent],
      providers: [SocketService],
    }).compileComponents();
    fixture = TestBed.createComponent(OndemandComponent);
    component = fixture.componentInstance;
  });
  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should check socket service', inject(
    [SocketService],
    (socketioService: SocketService) => {
      const connectorSpy = jasmine.createSpyObj('connector', ['on']);
      connectorSpy.on.and.callFake((event, listener) => {
        listener('fake message');
      });
      const getSocketIOConnectorSpy = spyOn(
        socketioService,
        'getSocketIOConnector'
      ).and.returnValue(connectorSpy);

      // trigger ngOnInit of component
      fixture.detectChanges();

      expect(getSocketIOConnectorSpy).toHaveBeenCalledOnceWith('real product');
      expect(connectorSpy.on).toHaveBeenCalledOnceWith(
        'connected',
        jasmine.any(Function)
      );
    }
  ));
});

unit test result:

https://i.sstatic.net/ULfWJ.png

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

Enhance Your SVG Elements with Angular Tooltips

I am faced with a challenge on my website where I have an SVG element: <ellipse id="svg_2" cy="78.999999" cx="1042.499999" stroke-width="1.5" stroke="#000" fill="#fff"/> My goal is to add a tooltip to this specific element. I attempted using NGPrim ...

Executing a function in the view/template with Angular 2+

Whenever a function is called in the view of an Angular component, it seems to be executed repeatedly. A typical example of this scenario can be seen below: nightclub.component.ts import { Component } from '@angular/core'; @Component({ selec ...

Problem integrating 'fs' with Angular and Electron

Currently, I am working with Angular 6.0, Electron 2.0, TypeScript 2.9, and Node.js 9.11 to develop a desktop application using the Electron framework. My main challenge lies in accessing the Node.js native API from my TypeScript code. Despite setting "com ...

Create multiple instances of a component in a dropdown menu using different datasets in Angular 5

Outlined below is the structure of my drop-down list: Companies > Depots Each company has multiple depots. I have developed a component for companies, and upon clicking on a company (menu item), an HTTP request is made to bring all companies which are ...

What sets apart the browser's debugger from Angular's setTimeout function?

I'm currently working on an angular application that is embedded within a larger application that I do not have access to. I am using a router to navigate between pages after a pop-up modal has been acknowledged (checkbox & button). It's crucial ...

Angular 2: Change Boolean value depending on a condition

I find myself facing a challenge with a search-bar feature. My goal is to display all the filtered names when the input value reaches a length of 2 or more characters. After successfully extracting the value.length from the input field, I encountered a ro ...

Export firebase information to automatically populate a template-driven form

I am currently developing an application using Angular 4.0.2 along with AngularFire2 and Firebase. However, I have encountered an issue where I am unable to utilize data from AngularFire2 to set it as the default input value in a form used in model-driven ...

After calling Subject.next, the function will return an Observable

In my current Ionic 2 project, I am focusing on implementing two key functionalities - logging out the user and remotely clearing the database. Below is the code snippet I have been working on: private logoutEvent: Subject<any> = new Subject(); priv ...

Having trouble getting socket.io to function properly in conjunction with express and ejs

Just started exploring node.js, express, and ejs. Attempting to implement socket.io communication but running into some issues. The index.ejs is loading correctly in the browser, however, the server is not displaying the log message. // server side var e ...

Error: Angular encountered an undefined variable when attempting to import 'node_modules/bootstrap/scss/grid'

Having some trouble setting up Angular with SCSS and Bootstrap. When attempting to run ng serve, I encountered the following error: ./src/styles.scss - Error: Module build failed (from ./node_modules/sass-loader/dist/cjs.js): SassError: Undefined variable. ...

Issues may arise when attempting to navigate within a lazy module using Angular Nativescript

Recently, I utilized a template called Nativescript-Tabs-Template from this GitHub repository. While attempting to navigate to a sibling component (both within the same lazy module), I encountered the following issue: showItem() { this.routerExtensi ...

Upgrade from Next.js version 12

Greetings to all! I have recently been assigned the task of migrating a project from next.js version 12 to the latest version. The changes in page routing and app routing are posing some challenges for me as I attempt to migrate the entire website. Is ther ...

Spartacus storefront is having trouble locating the .d.ts file when using Angular/webpack

Seeking help from the SAP Spartacus team. Encountering errors while developing a Spartacus component, specifically with certain Spartacus .d.ts definition files that cannot be resolved. The issue is reproducible in this Github repository/branch: This pr ...

Angular: Modify the spelling of a single term across an application to cater to international audiences

I am working on an Angular application that must support both British and American English languages. The language setting is determined by a server at start-up, allowing me to know which language to display. One specific change I need to make throughout ...

What is the process for defining a default value for a template-driven form input in Angular 2?

I have a simple input element in my form that requires a default initial value to be set. <input type="number" name="interest_rate" [(ngModel)]="interest_rate"> In my code, I included this.form.controls['interest_rate'].patchValue(this.a ...

The NgRx Store encountered an error: Unable to freeze

I am currently developing a basic login application using Angular, NgRx Store, and Firebase. I have implemented a login action that is supposed to log in to Firebase and store the credentials in the store. However, it seems like there is an issue in my imp ...

Blast information to Observable

To view the code sample, visit the following link: stackblitz In my data service, data is fetched asynchronously from a global object (in the actual project, data is emitted via EventEmitter). The structure of the service is as follows: import { Injectab ...

Guide on displaying and handling server-side validation errors within an angular form

I recently started working with Angular and encountered a problem I can't seem to solve. In my form, I need to display server validation errors from a Laravel REST API response. Although I can see the error message in the console, I'm unsure how ...

The term "primordials is not defined" is a common error

Whenever I attempt to run Gulp using the task runner, I am encountering this error message. I suspect it may be due to updating my npm project, but I'm unsure about how to resolve it. Should I try installing a different version of npm? >Failed to r ...

Bidirectional enumeration in TypeScript

I am working with an enum defined as: enum MyEnum { key1 = 'val1' key2 = 'val2' } However, I am unsure how to create a SomeType implementation that fulfills the following requirements: Function: const myFunction = (param: SomeT ...