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

Dynamically populate dropdown menu with values extracted from dataset

I'm currently working on a dropdown menu that needs to be updated dynamically using the data set below: this.additionalPercentages = this.offer.offerData.wellbeing.retirementPackages[0].additionalVoluntaryContributionPercentages; When I console this ...

To toggle the state of an md-checkbox in Angular 2 (or 4) by referencing its unique identifier

<md-checkbox [align]="end" *ngFor="issueConfid in issueConfidences" (change)=onIssueConfidenceFilterChange(issueConfid)" id="favoriteCheck1.name"> {{issueConfid.name}} </md-checkbox> Is there a way to programmatically uncheck or check the ...

What is the best way to organize the Firebase data that is stored under the user's unique

Hey there, I'm currently working on developing a leaderboard feature for an app. The idea is that users will be able to store their "points" in a Firebase database, linked to their unique user ID. This is how the data is structured in JSON format: ...

Prevent Click Event on Angular Mat-Button

One of the challenges I'm facing involves a column with buttons within a mat-table. These buttons need to be enabled or disabled based on a value, which is working as intended. However, a new issue arises when a user clicks on a disabled button, resul ...

Automatically arrange TypeScript import statements in alphabetical order in WebStorm / PhpStorm

I am using tslint with the default config tslint:recommended and I am looking to minimize the number of rules I need to customize. Some rules require that imports be alphabetized: src/core/task/TaskMockDecorator.ts[2, 1]: Imports within a group must be a ...

Following the Angular 6 update, a new error message "Error: Expected to find an ngsw-config.json configuration file" appears when running the ng build --prod command

After completing the update process, I encountered an issue during the build where the following error message appeared. Error: Expected to find an ngsw-config.json configuration file in the /Users/nathanielmay/Code/firebaseTest folder. Either provide ...

Error: Call stack size limit reached in Template Literal Type

I encountered an error that says: ERROR in RangeError: Maximum call stack size exceeded at getResolvedBaseConstraint (/project/node_modules/typescript/lib/typescript.js:53262:43) at getBaseConstraintOfType (/project/node_modules/typescript/lib/type ...

Error Raised Due to Modification After Checking in Angular 2/Angular 5

Dealing with ExpressionChangedAfterItHasBeenCheckedError in Angular 2/Angular5 Error message: An error has occurred: ExpressionChangedAfterItHasBeenCheckedError. The expression has changed after it was checked. Previously it was 'ng-untouched: ...

Determine the time difference between the beginning and ending times using TypeScript

Is there a way to calculate the difference between the start time and end time using the date pipe in Angular? this.startTime=this.datePipe.transform(new Date(), 'hh:mm'); this.endTime=this.datePipe.transform(new Date(), 'hh:mm'); The ...

Error encountered in React component: TypeScript TS2339 states that the property 'xyz' is not found on type 'IntrinsicAttributes...'

I am attempting to develop a straightforward React component that can accept any properties. The syntax below using any is causing issues (unexpected token just before <): export class ValidatedInput extends React.Component<any, any> {...} The p ...

"Utilizing Angular's RxJS to efficiently filter an observable

I am currently attempting to filter a stream of products using an array of filters, but I am unsure of the best approach. Let me clarify my goal: I want to store the filtered result in the variable filteredProducts. To perform the filtering, I need to ite ...

Ways to verify a component that expands from a base component using ng-mocks

In my code, I have a CakeItemContainerComponent that extends ItemContainerComponent and I am attempting to test it using ng-mocks. Here is what I'm trying to accomplish: @Component({ selector: 'app-item-container', template: '&apos ...

Navigating between two different HTML pages using Angular 2 routing

In my Angular2 application, I have both a front-end section and an admin interface. The front-end section is styled with its own unique set of styles defined in the index.html file. On the other hand, the admin interface has a completely different set of ...

The optimal location to declare a constructor in Typescript

When it comes to adding properties in an Angular component, the placement of these properties in relation to the constructor function can be a topic of discussion. Is it best to declare them before or after the constructor? Which method is better - Method ...

The functionality of Angular is not compatible with a mobile network connection

Recently, I noticed that my Angular 6 application hosted on my server with SSL and HTTPS protocol loads quickly on my computer but is extremely slow on my mobile phone, taking about 3-4 minutes to fully load. I conducted network profiling using Chrome, bu ...

Lack of intellisense support for .ts files in Visual Studio Code

Currently, I am using Visual Studio Code 1.17.2 on Arch Linux to kickstart my work with Node.js/Angular4. To avoid confusion caused by loosely typed code, I have decided to switch to TypeScript for my NodeJS server as well. This is why my main file is name ...

Understanding the meaning of `.then()` in Excel JavaScript involves recognizing its function

Excel.run(function (context) { var sheet = context.workbook.worksheets.getItem("Sample"); var range = sheet.getRange("B2:C5"); range.load("address"); return context.sync() .then(function () { ...

The act of importing the MatButtonModule module serves no purpose

I am developing an Angular application with the Material design framework. My goal is to incorporate the material button module into my project. Including it in app.module.ts is done as follows (excerpt from code): import { MatTableModule } from '@ ...

Utilizing the JavaScript Array.find() method to ensure accurate arithmetic calculations within an array of objects

I have a simple commission calculation method that I need help with. I am trying to use the Array.find method to return the calculated result from the percents array. The issue arises when I input a price of 30, as it calculates based on the previous objec ...

The function has been called but it did not return a

It seems that there is confusion surrounding the .toHaveBeenCalled() Matcher in Jasmine. While it should return a Promise that resolves when the function has been called, some users are experiencing it returning undefined instead. For example: it('sh ...