Simulate an HTTP request from a service class during a jasmine test

I initially believed that spying on services in Jasmine using the spyOn method and returning a value when the method is called was straightforward. However, it seems like my assumption may have been too simplistic?

I intend to test the following action in nxjs:

./Auth.state.ts

  // ...

  @Action(Login)
  login(ctx: StateContext<AuthStateModel>, action: Login) {
    return this.authService.login(action.payload).pipe(
      tap(({ accessToken }: { accessToken: string }) => {
        const {exp} = jwt_decode(accessToken);
        const expiresAt = dayjs().add(exp, 'second');
        ctx.patchState({
          token: accessToken,
          username: action.payload.username,
          expiresAt
        });
      })
    );
  }

This action relies on the authService login method:

./auth.service.ts

  // ...

  login({ username, password }: User): Observable<{ accessToken?: string }> {
    return this.http
      .post(`${api.BASEURL}${api.API_LOGIN}`, { username, password });
  }

Now I am trying to write a test for this scenario:

./Auth.state.spec.ts

describe('Auth', () => {
  let store: Store;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [NgxsModule.forRoot([AuthState]), HttpClientTestingModule],
      providers: [HttpClient, HttpHandler, AuthService]
    });

    store = TestBed.inject(Store);
  });

  function setupState(NEW_STATE = null) {
    store.reset({
      ...store.snapshot(),
      auth: NEW_STATE
    });
  }

  describe('login', () => {
    it('updates the state upon successful login', () => {
      // TS2345: Argument of type '"register"' is not assignable to parameter of type 'never'.
      spyOn(AuthService, 'login').and.returnValue(false);

      // find a possible workaround here: https://github.com/facebook/jest/issues/9675 
      // Object.defineProperty(AuthService, 'login', { get(){ return false; } });
      // still no success...
      
      const expectedState = { token: null, username: 'Some username', expiresAt: null };
      setupState();
      store.dispatch(new Login({ username: expectedState.username, password: '' }));
    
      const auth = store.selectSnapshot(state => state.auth);
      expect(auth).toEqual(expectedState);
    });
  });
  // ...

Answer №1

To access the injected service in your Auth.state.spec.ts file, you will need to obtain an instance of the service from angular's TestBed.

describe('login', () => {
   it('should update the state upon successful login', () => {
      // Obtain the injected instance of AuthService
      const authService = TestBed.inject(AuthService);

      spyOn(authService, 'register').and.returnValue(of(false));

      spyOn(authService, 'login').and.returnValue(
        of({ access_token: 'scdkj2' })
      );
      // Ensure that fixture.detectChanges() is not called before all spies are set up
      fixture.detectChanges();
      
      ....
    });
  });

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

Issue with bi-directional data binding in Angular's matInput component

When working on my template... <input matInput placeholder="Amount" [(value)]="amount"> In the corresponding component... class ExampleComponent implements OnInit { amount: number = 0; ... } The binding doesn't seem to work as expect ...

Strange behavior of the .hasOwnProperty method

When attempting to instantiate Typescript objects from JSON data received over HTTP, I began considering using the for..in loop along with .hasOwnProperty(): class User { private name: string; private age: number; constructor(data: JSON) { ...

Navigating in Angular to initiate file retrieval

Is there a way to set up a route in Angular that allows me to download a file? For example, having a route like '/myFile' would result in downloading the file "/assets/files/test.pdf". I've tried using the redirectTo option for routing, bu ...

Enigmatic Cartography Classification

In my attempt to construct a specialized Map-like class that maps keys of one type to keys of another, I encountered a challenge. A straightforward approach would be to create a Map<keyof A, keyof B>, but this method does not verify if the member typ ...

Pass a photo along with additional characteristics to the post endpoint in the API

Using the code snippet below, I am able to send an image to a post method and save it as a BLOB in the database successfully: Angular Code: public postUploadedFile(file:any){ this.formData = new FormData(); this.formData.append('file',fi ...

There seems to be a syntax error in the regular expression used in Angular TypeScript

I've encountered an error and I'm struggling to identify the syntax issue. core.mjs:6495 ERROR SyntaxError: Invalid regular expression: /https://graph.microsoft.com/v1.0/communications/callRecords/getPstnCalls(fromDateTime=2020-01-30,toDateTime ...

Issue arises when isomorphic-dompurify is used alongside dompurify in Next.js 13 causing compatibility problems

I am currently facing a compatibility problem involving isomorphic-dompurify and dompurify in my Next.js 13 project. It appears that both libraries are incompatible due to their dependencies on canvas, and I am struggling to find a suitable alternative. M ...

The @angular/fire package is unable to locate the AngularFireModule and AngularFireDatabaseModule modules

I am facing some challenges while trying to integrate Firebase Realtime Database into my Angular project. Specifically, I am encountering difficulties at the initial step of importing AngularFireModule and AngularFireDatabaseModule. To be more specific, I ...

Steps for updating text within an object in Angular

details = [ { event: "02/01/2019 - [Juan] - D - [Leo]", point: 72 }, { event: "02/01/2019 - [Carlo] - N - [Trish]", point: 92 } ]; I am attempting to modify the text within the titles that contain - N - or - D - The desired outcom ...

"Learn how to dynamically change the color of a button in Angular after it has been clicked

Can someone assist me in changing the button color to red after it has been clicked? I am looking for guidance on how to achieve this. The current code snippet is as follows: <td> <button mat-icon-button color="primary"> <m ...

Error in Mocha test: Import statement can only be used inside a module

I'm unsure if this issue is related to a TypeScript setting that needs adjustment or something else entirely. I have already reviewed the following resources, but they did not provide a solution for me: Mocha + TypeScript: Cannot use import statement ...

Implementing Batch File Uploads using Typescript

Is there a way to upload multiple files in TypeScript without using React or Angular, but by utilizing an interface and getter and setter in a class? So far I have this for single file upload: <input name="myfile" type="file" multi ...

"Optimizing Performance: Discovering Effective Data Caching

As a developer, I have created two functions - one called Get to fetch data by id from the database and cache it, and another called POST to update data in the database. However, I am facing an issue where I need to cache after both the get and update oper ...

In Angular 2, property binding will not function properly when attempting to bind to an object

I have encountered a strange issue with Angular 2 property binding. Let's start with the Store class: export class Store { id: number; name: string; address: string; } This is the component code snippet: export class MyBuggyComponent i ...

Assembly of these elements

When dealing with a structure where each property is of type These<E, A> where E and A are unique for each property. declare const someStruct: { a1: TH.These<E1, A1>; a2: TH.These<E2, A2>; a3: TH.These<E3, A3>; } I inte ...

Why is the dateclick event in PrimeNG's FullCalendar not being emitted when clicking on a date? What is the best way to handle click events on specific dates within the calendar?

I am new to using Angular and PrimeNG, and I am facing challenges while trying to implement the FullCalendar component. The specific component I am referring to can be found here: The issue arises when I attempt to trigger an event when a user clicks on a ...

Vue.js 3 with TypeScript is throwing an error: "Module 'xxxxxx' cannot be located, or its corresponding type declarations are missing."

I developed a pagination plugin using Vue JS 2, but encountered an error when trying to integrate it into a project that uses Vue 3 with TypeScript. The error message displayed is 'Cannot find module 'l-pagination' or its corresponding type ...

Tips on sending component values to Host Listener in Custom Directives using Angular 2

I am looking to transmit model values from my HTML template to a custom directive: @Directive({ selector: '[eventlistener]' }) export class EventListener { @Input() value:string = 'Not Defined'; @HostListener('click& ...

What is the best way to extract information from a button and populate a form in AngularCLI?

I am currently attempting to enhance my Angular App by using a button to transfer information to a form upon clicking, rather than the traditional radio buttons or select dropdowns. My objective is to incorporate HTML content into the button (such as Mat-I ...

Run JavaScript code whenever the table is modified

I have a dynamic table that loads data asynchronously, and I am looking for a way to trigger a function every time the content of the table changes - whether it's new data being added or modifications to existing data. Is there a method to achieve th ...