Testing a dynamic method invocation in Angular unit tests

In the component I'm working on, there is a particular service with a method that needs to be called dynamically.

@Input methodName: string;

constructor(
        private readonly testService: testService
    ) {
}

loadData() {
   this.testService[this.methodName]().subscribe();
}

However, when trying to test the loadData() method, I encountered an issue where it says that this.testService[methodName] is not a function. How can this type of method be effectively tested?

it('should ',  fakeAsync(() => {
        // getData is the supposed methodName that has to be set;
        testService.getData.and.returnValue(asyncData({} as any));
        component.loadData();
        flush();
        expect(testService.getData).toHaveBeenCalled();
}));

Answer №1

  1. Ensure the service is made public in the component constructor for improved testing capabilities

  2. Adopt the following example as a standard practice:

service.ts

@Injectable({
  providedIn: 'root',
})
export class UserSvcService {
  test() {
    return of('test');
  }
}

for a component.ts

@Component({
  selector: 'app-user-detail',
  templateUrl: './user-detail.component.html',
  styleUrls: ['./user-detail.component.scss'],
})
export class UserDetailComponent implements OnInit {
  name = 'test';
  val :string

  public constructor(public _userSvc: UserSvcService) {}

  ngOnInit() {
    this._userSvc[this.name]().subscribe(res =>
      this.val = res
    );
  }
}

Create a stub like this:


export class UserServiceStub {
  test() {
    return of('test mock');
  }
}

replace the actual service with stub as:

describe('UserDetailComponent', () => {
  let component: UserDetailComponent;
  let fixture: ComponentFixture<UserDetailComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [],
      declarations: [UserDetailComponent],
      providers: [{ provide: UserSvcService, useClass: UserServiceStub }],
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserDetailComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
    expect(component.val).toBe('test mock'); // move into another "it" block
  });

This setup should function correctly. To enable smooth testing, remember to utilize `spyOn` with the service marked as `public` first:

it('should ',  () => {       
        spyOn(component.testService,'getData').and.returnValue(return of({some val}));
        component.loadData();
        expect(component.testService.getData).toHaveBeenCalled();
});

Take a look at this article for more insights

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

What is the method for inserting line breaks in Ionic2 toasts using HTML?

Is there a way to include new lines and other HTML tags in a toast message? let toast = this.toastCtrl.create({ message: "First line<br />Second line.", duration: 5000, dismissOnPageChange: true }); toast.present( ...

What is the method for dynamically altering attributes using a directive?

I am currently working on dynamically assigning attributes to HTML tags (such as Select, Button, or Input) within a switch statement. However, I'm a bit stuck and would appreciate any better ideas or suggestions you may have. My goal is to identify w ...

Guide on transitioning Angular 2 RC 1 (or an earlier version) Forms to the new Forms in Angular 2 RC 2 / RC 4

I am currently in the process of upgrading my Angular 2 RC 1 app to Angular 2 RC 4, and part of this update involves migrating my existing forms to Angular 2 RC 4 New Forms. Could someone provide guidance on how to successfully update my existing forms to ...

The server is not allowing the requested method through HTTP POST and therefore returning

Excuse me if this question sounds beginner or if my terminology is incorrect, because I am new to this. I have created a basic Python API for reading and writing to a database (CSV file) with Angular 5 as my front end. While I was able to successfully ret ...

Set the root of Ionic OneSignal Push Notification instead of pushing it from the Home page to Another Page

Experiencing some trouble with my OneSignal push notifications and page redirection. While the app is open, tapping on a notification pushes the news-detail page onto the stack from the current home page. (This behavior is desired when the app is closed.) ...

Utilizing ControlValueAccessor for accurate data validation

I've developed my own input fields using the ControlValueAccessor. How can I retrieve validation information within this component? Feel free to check out an example here: https://stackblitz.com/edit/angular-ngmodel-valid?file=src/app/text-input.com ...

Reactjs-ffsevents does not exist as a function

An error occurred: TypeError: fsevents is not a function. This issue is located in the FSEventsWatcher file at line 162. A new FSEventsWatcher was attempted to be created in jest-haste-map, triggering this error. The watcher creation process involved map ...

Unlocking the potential of deeply nested child objects

I have a recursively typed object that I want to retrieve the keys and any child keys of a specific type from. For example, I am looking to extract a union type consisting of: '/another' | '/parent' | '/child' Here is an il ...

Checking the formik field with an array of objects through Yup for validation

Here is a snippet of the code I'm working on: https://codesandbox.io/s/busy-bose-4qhoh?file=/src/App.tsx I am currently in the process of creating a form that will accept an array of objects called Criterion, which are of a specific type: export inte ...

Tips for monitoring dispatch in fetch/middleware functions

Just testing a basic webpage <template> <HomeTemplate /> </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ async fetch(context) { // or middleware(context) await context.store.disp ...

Utilizing the NPM package as a JSX Component is prohibited due to type errors

I've been encountering some unusual type errors in my TypeScript project with certain packages. For example: 'TimeAgo' cannot be used as a JSX component. Its instance type 'ReactTimeago<keyof IntrinsicElements | ComponentType<{} ...

It appears that the ngOnInit function is being activated prior to receiving any data through the Input()

For a personal challenge, I am working on creating a website that showcases a list of League Of Legends champions. Users can click on the champion icons to access more details. However, I am facing an issue where the champion details (specifically images) ...

Javascript operations for duplicating and altering arrays

In my Angular application, I am working with an array called subAgencies that is connected to a datasource. I need to implement 2-way binding on this array. Currently, I have a method in place where I copy the contents of the original array to a new one, ...

After updating my Ionic Android App to Angular 12, it got stuck on a blank white screen with an error message stating: "goog.getLocale is

After successfully upgrading my Ionic App with Angular 11 to version 12, everything seemed fine when running it in the browser. However, when attempting to launch it on an Android device, I encountered a white screen after the splash-screen vanished. My t ...

Expanding the Mui Typescript breakpoints within a TypeScript environment

Encountering a typescript error when attempting to utilize custom names for breakpoint values: Type '{ mobile: number; tablet: number; desktop: number;}' is not compatible with type '{ xs: number; sm: number; md: number; lg: number; xl: numb ...

Steps for eliminating a selection in the dropdown list:

I am dealing with a situation in which my select element gets new options added based on a specific input value. However, each time the value is changed, more options are appended to the select element instead of replacing the old ones. How can I remove th ...

Having difficulty initializing a constant object in TypeScript

Encountering an error while attempting to compile my code using Angular 7.2.0 and TypeScript version 3.2.2: Error TS1005: ',' expected.**… The issue seems to be arising from the line where I am trying to define a const object. addAppareil( ...

Relative path of Angular 2 component

After setting up my systemjs.config.js file to map the "app" to a "dist" folder, I encountered an issue when trying to reference my component html file relatively. The error message displayed was: Failed to load https://localhost:44337/dist/appComponent.h ...

Integrating Angular with ng-select for item selection verification

Could someone help me with setting up this scenario? A user picks an option from the dropdown menu. The previous selection remains until a certain point is reached. The selected value is sent out through the @Output variable. The chosen value is then con ...

Managing form input in Ionic2 components from external sources in Angular2

Hello there, I am currently facing an issue with managing form validation along with proper styling for nested forms. Here's what I'm aiming to achieve: I have a Page that displays Tabs components with four tabs. Each tab represents a separate @ ...