Observe a classified entity with private ownership containing programmed functions

My Angular application utilizes the oidc-client UserManager class for managing OAuth authentication.

The service I have is structured like this:

export class AuthService {
  private userManager: UserManager
  private readonly configService: ConfigService;
  constructor(configService: ConfigService) {
    this.configService = configService;
  }
...
  async load(): Promise<any> {
    config = this.configService.getConfig();
    this.userManager = new UserManager(config);
    const user = await this.userManager.getUser();
...

Below is the setup of my spec file:

  beforeEach(() => {
    const spy = jasmine.createSpyObj('UserManager', ['getUser']);
    spy.getUser.and.returnValue(mockUser);
    const configSpy = jasmine.createSpyObj('ConfigService', ['getConfig']);
    configSpy.getConfig.and.returnValue(mockConfig);

    TestBed.configureTestingModule({
      providers: [
        AuthenticationService,
        { provide: UserManager, useValue: spy },
        { provide: AppConfigService, useValue: configSpy }
      ]
    });
    authService = TestBed.inject(AuthenticationService);
    appConfigSpy = TestBed.inject(ConfigService) as jasmine.SpyObj<ConfigService>;
    userManagerSpy = TestBed.inject(UserManager) as jasmine.SpyObj<UserManager>;
  });

...and here is my initial test case :

    it('should initialize the user manager', async () => {
         // arrange 
      userManagerSpy.getUser.and.resolveTo(mockUser);
      appConfigSpy.getConfig.and.returnValue(mockConfig);

      // act
      await authService.load();

      // assert
      expect(userManagerSpy).toHaveBeenCalled();
    });

When running tests, I encounter a 404 error which leads me to believe that new UserManager(config) and/or this.userManager.getUser() are attempting to make HTTP requests instead of returning mock values.

How can I spyOn userManager and mock the return value from getUser()?

I thought that the TestBed.configureTestModule providers were meant for setting up services injected into the service, not for members of the service itself.

Answer №1

If you want to keep an eye on a constructor, in the world of JavaScript you can achieve this like so:

spyOn(window, 'UserManager').andReturn(...);

To learn more about spying on constructors, check out: Spying on a constructor using Jasmine

Instead of using ..., consider creating a spy/mock and verifying if the #getUser() function was called. Alternatively, you could develop a Moco implementation for #getUser().

But remember that "Everytime a mock returns a mock a fairy dies". In simpler terms, this may not be the most effective way to write tests and could point to issues with code quality. If UserManager is created within a function, it may not qualify as a service and should possibly avoid having its own logic.

Perhaps you could reorganize the code so that the config is used to invoke methods from a service injected into the constructor of AuthService?

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

Exploring the integration of LeafLet into Next JS 13 for interactive mapping

I'm currently working on integrating a LeafLet map component into my Next JS 13.0.1 project, but I'm facing an issue with the rendering of the map component. Upon the initial loading of the map component, I encountered this error: ReferenceError ...

Encountering a 404 error when trying to reload a page on the Angular-Wakanda webserver

It appears that when you refresh the page, the Wakanda server is expecting to find a specific file path in the web root. Since I have utilized the Angular router to dynamically generate paths like https://my-site.com/home/products, there may not be an exac ...

Transforming date and timezone offset into an isoDate format using moment.js

When retrieving data from the API, I encounter Date, Time, and Offset values in separate columns. My goal is to obtain an ISO date while maintaining the original date and time values. const date = "2019-04-15" const time = "13:45" const ...

Handling the onChange event in ReactJS using Typescript and Redux for number values with comma separators

Consider the following scenario: I am working on a reactjs/redux/typescript application. I have implemented two-way binding with redux for my input textboxes using the onChange event. The props are all declared with the data type "number" and everything i ...

Converting JavaScript object data to x-www-form-urlencoded: A step-by-step guide

I am trying to convert a JavaScript object into x-www-form-urlencoded. Is there a way to achieve this using Angular 2? export class Compentency { competencies : number[]; } postData() { let array = [1, 2, 3]; this.comp.competencies ...

The extensive magnetic scrolling functionality in Ionic 2 sets it apart from other frameworks

Hi everyone, I could really use some assistance! I've been working on developing an Ionic 2 App and my navigation setup is not too complex. I have a main menu where clicking on an item opens another menu with a submenu. From there, if I click on an i ...

What is the best way to transfer the $event parameter from a dynamically generated function that requires the $event argument during a typical mouse click operation?

On an angular HTML template, I have a click handler that passes the $event argument to the handler function. My goal is to call this function programmatically on ngOnInit to initialize the component with default data as if the button had been clicked: Bel ...

Sending data from an element within an ngFor loop to a service module

In my component, I have a loop that goes through an array of different areas with unique IDs. When you click the button, it triggers a dialog containing an iframe. This iframe listens for an event and retrieves data as JSON, then sends it via POST to an IN ...

What is the proper method for utilizing an object as a dependency when using useEffect?

Currently, I am in the process of developing a react hook that takes in a query object. export function useMyQuery(query: QueryObjectType) { React.useEffect(executeQuery, [ query ]); // ... } Unfortunately, whenever my hook is called during a re- ...

Executing an action in a child component when a button is clicked on the parent route

Currently, I am developing a web application using Angular 4 that involves both parent and child routes. Within the parent route, there are two buttons available - 'Add' and 'Remove'. I am seeking guidance on how to trigger a function ...

Mocking Multiple Instances of Classes in Jest

I am currently working on a project where I have a class that creates multiple instances of the same object. I am trying to mock this behavior in jest, but I keep encountering an error specifically for the second instance creation test. Error: expect(rece ...

How come once I close a PrimeNG modal that is defined within a child component, I am unable to reopen it?

Currently, I am developing an Angular application that utilizes PrimeNG. In the process, I encountered a challenge. Initially, I had a component with a PrimeNG Dialog embedded within (refer to this link), and it was functioning properly. To streamline my ...

A guide to effectively injecting a service into a guard

I've encountered a challenge while working on an API using nestjs, specifically with service injection in a guard. The error message I'm facing is: Error: Nest can't resolve dependencies of the AuthorizerGuard (?). Please make sure that the ...

I'm fascinated by the way well-known websites like The Guardian are utilizing Angular, as I often notice that when I click on links, the entire page reloads

As a beginner in Angular, I recently explored popular websites that implement Angular or React. I discovered sites like The Guardian, New York Times, and Netflix. However, most of these sites have links that open in new pages, while the remaining ones ut ...

Leverage an array of objects as the model within a child Angular component, and ensure to monitor any

I have a component that showcases a lineup of items (objects). My goal is to develop another component that takes in this lineup as its model (or parameter) and generates an interactive dashboard with this information. For instance, if I have a list of pro ...

Exploring the use of @HostListener in Angular for handling drop events

I am currently working on developing a directive for drag and drop functionality with files. I have successfully implemented the dragenter and dragleave events, but for some reason, the drop event is not being recognized. @HostListener('drop', [ ...

Angular Modular Routing encountering a 'No matching route found' error with the '**' wildcard

Utilizing the forChild method in each separate sub-module to define routes is a good way to modularize an application. But what happens when there are URLs that do not match any of the defined routes? If I include the following routes in the main AppRoutin ...

Error: Cannot assign type 'number' to type 'PersonConfig'. Please resolve the issue before continuing

An error occurred indicating that type 'number' is not assignable to type 'PersonConfig'. The issue seems to be related to the index signature in this code snippet. interface Person { [Id: string]: PersonConfig } interface PersonC ...

Having trouble with ngx-pagination's next page button not responding when clicked?

I am experiencing issues with pagination. The next page button does not function as expected, and clicking on the page number also does not work. Below is the code snippet and a Demo link for your reference. HTML <table mat-table [dataSou ...

I'm curious if it's possible to set up both Tailwind CSS and TypeScript in Next.js during the initialization process

When using the command npx create-next-app -e with-tailwindcss my-project, it appears that only Tailwind is configured. npx create-next-app -ts If you use the above command, only TypeScript will be configured. However, running npx create-next-app -e with ...