Exploring the inner function within Angular using jasmine testing

While working on my project, I encountered a situation where I needed to define an inner function and assign it to a class variable for future use. The reason behind this decision was to have access to the parent function's arguments without granting access to that data to other methods within the class.

@Component({
  selector: 'app-report-topup',
  templateUrl: './report-topup.component.html',
  styleUrls: ['./report-topup.component.scss'],
})
export class ReportTopupComponent implements OnInit {
 
  loadReports: (pageNum, pageSize) => void;
  reportDataSource: ReportDataSource;
  currentPageDetails: { index: number; size: number } = { index: 0, size: 5 };

  constructor(public topupHttpService: TopupHttpService){}

  ngOnInit(): void {
    this.reportDataSource = new ReportDataSource(this.topupHttpService);
  }

  onReportTopupSearchFormSubmit(formData: ReportTopupSearch) {
  
    this.loadReports = (pageNum, pageSize) => {
      this.reportDataSource.loadReports();
    };

    this.loadReports(0, this.currentPageDetails.size);
    this.setCurrentPageDetails(0 , this.currentPageDetails.size);
  }

Although the code seems to be working fine, I encountered some issues while testing it. Here's a snippet of my spec.ts function:

 it('should call load Reports and setCurrentPageDetails on form submit', () => {
    spyOn(component, 'setCurrentPageDetails');
  
    const reportFormData: ReportTopupSearch = {
      company: 'ABC',
      dateFrom: '2021-01-01',
      dateTo: '2021-01-02',
      status: 'new',
    };

    component.onReportTopupSearchFormSubmit(reportFormData);
    
    expect(component.loadReports).toBeDefined();
    expect(component.loadReports).toHaveBeenCalled();
    expect(component.setCurrentPageDetails).toHaveBeenCalled();
  });
  1. When attempting to use `spyOn` from jasmine, the test runner throws an error. Refer to this image for details: https://i.sstatic.net/5eD7q.png

  2. If I switch to using `jasmine.createSpy` as shown below:

 component.loadReports = jasmine.createSpy('load reports spy' , () => {});
I encounter the error "Expected spy but got a function". Refer to this image for more information: https://i.sstatic.net/ZyOj5.png

I'm currently stuck on how to resolve this issue and properly test whether `component.loadReports()` has been called. The spy for the `setCurrentPageDetails()` method seems to be working fine because it's a method of the class. Any assistance would be greatly appreciated.

Answer №1

In the process of defining the signature of the loadReports() method, make sure to include an implementation as well. Without an implementation, when jasmine attempts to set a spy, it expects a function and will fail to set the spy.

To enable jasmine to spy on the loadReports() method, provide an implementation and use the following syntax:

spyOn(component, 'loadReports');

Answer №2

The issue at hand is that the loadReports function is being implemented and called immediately, making it impossible to spy on it using SpyOn in this manner. To clarify:

  • If you attempt to spy on loadReports before invoking onReportTopupSearchFormSubmit, you will receive an error stating that loadReports is not a function.
  • Conversely, if you spy on loadReports after calling onReportTopupSearchFormSubmit, it is too late as loadReports has already been executed.

One possible solution is to divide onReportTopupSearchFormSubmit into two separate methods:

  • The first method should handle the dynamic implementation of loadReports.
  • The second method can then utilize the previously implemented logic and include any additional actions needed, such as
    this.loadReports(0, this.currentPageDetails.size); this.setCurrentPageDetails(0, this.currentPageDetails.size);

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

Incorporating TypeScript basics into the if statement post compiling

As I delve into the Angular2 Quickstart, I stumbled upon a peculiar issue within app.component.js after compiling app.component.ts using tsc (version 1.8.2): if (d = decorators[i]) I am unable to pinpoint where I may have gone wrong in configuring the qu ...

Transforming TypeScript declaration files into Kotlin syntax

Has there been any progress on converting d.ts files to Kotlin? I came across a post mentioning that Kotlin developers were working on a converter, but I am unsure about the current status. I also found this project, which seems to be using an outdated c ...

What is the process for establishing the default type for an Activity Entity in Microsoft Dynamics?

Currently in the process of restructuring a portion of script code associated with the Fax Activity Entity within Microsoft Dynamics. Within the script code, the following can be found: document.getElementById("regardingobjectid").setAttribute("defaulttyp ...

The Jasmine test is having trouble locating the imported variable

In my Angular project, I have a class set up as follows: import { USERS } from "./data/users"; // imports an Array of Objects export class User { constructor(name: string) { const user = USERS.find(e => e.name === name); } ... } Every ...

Utilizing Angular's primeng library with CommonJS or AMD dependencies may lead to optimization setbacks

I recently updated my Angular app and started using PrimeNG components. However, after the update to Angular 10, I've been encountering a Warning message: CommonJS or AMD dependencies can cause optimization bailouts. This warning appears for variou ...

Is there a way to position the label to the left side of the gauge?

Is there a way to position the zero number outside the gauge? I'm having trouble figuring out how to do it because the x & y options won't work since the plotLine's position keeps changing. The zero needs to move along with the plotLine and ...

Angular 8: A Guide to Updating Tags in innerHTML

Hello, below is the code I am working with: <span [innerHtml]="question.description | SafePipe: 'html'" style="font-weight:500;" class="ml-1"></span> Upon inspecting my website, I noticed that my <span> tag contains nested &l ...

Ensure that column headers remain fixed when scrolling side to side

I'm trying to adjust the column headers so that I can scroll horizontally while keeping the headers visible. I've attempted the following changes but haven't been successful. In the screenshots provided, you can see that when I scroll up or ...

Broaden the `...args: Parameters<T>` to enable the inclusion of additional optional parameters towards the end

I am currently working on a function that can take a function as input and return an "extended" function. The returned function should have the same parameters as the original function, with an additional optional parameter at the end. I have managed to ...

Is it possible for a property to be null or undefined on class instances?

Consider this TypeScript interface: export interface Person { phone?: number; name?: string; } Does having the question mark next to properties in the interface mean that the name property in instances of classes implementing the interface ca ...

Is it possible to utilize a single node_modules folder for multiple Angular 2/4 projects?

As I dive into the world of Angular, I've noticed that creating a new project can be time-consuming due to the 100MB "node_modules" folder that the CLI generates. The contents of this folder are repetitively consistent across projects, with few change ...

Exploring the concept of asynchronous subscriptions in Angular

My current issue seems to be related to asynchronous programming, specifically with the subscription not running at the desired time. I typically approach this problem from both the user's and developer's perspectives. User's Perspective: ...

Managing input and output using a collaborative service

I've been working on refactoring some code that contains a significant amount of duplicate methods between two components. Component A is a child of component B, and they can be separate instances as intended. The issue I'm facing revolves around ...

TS2688 Error: Type definition file for 'tooltip.js' not found

Why am I getting an 'undefined' error when trying to import the Tooltip class from the npm tooltip.js package in my TypeScript file? ...

Error in React Native Navigation: Passing parameters is not functioning properly

Within my React Native application, I have meticulously established the following routes in my app.js: export default class App extends Component { render() { return ( <NavigationContainer> <Stack.Navigator initialRouteName=&qu ...

React Native Async Storage: displaying a blank page issue

I am facing an issue while attempting to save my data locally using AsyncStorage, specifically with the getData method. const storeData = async (value: string) => { //storing data to local storage of the device try { await AsyncStorage.setItem(& ...

Encountering a 405 HTTP error in Angular8 app when refreshing the page

Currently, I am working on a project using Angular8 and .NET Core 3.0 in Visual Studio. Everything is running smoothly except for one issue that arises when I press F5 on a page with a form. The error message that pops up reads: Failed to load resource: ...

What is the best way to export Class methods as independent functions in TypeScript that can be dynamically assigned?

As I work on rewriting an old NPM module into TypeScript, I encountered an intriguing challenge. The existing module is structured like this - 1.1 my-module.js export function init(options) { //initialize module } export function doStuff(params) { ...

What methods can be used to obtain download statistics for an Angular2 npm package?

Currently working on a presentation for an upcoming conference and faced with a bit of confusion... I'm having trouble locating the download statistics for the angular2 npm package! I've been looking here but unfortunately, there doesn't se ...

How to Retrieve and Display HTTP Response Body in Angular 8

Previously, when I was using Angular 7, I would retrieve the body of the response like this: import { Http } from '@angular/http'; constructor(public http: Http...) this.http.get(myURL).subscribe( (data) => { const myURL_body = data[& ...