Testing child components with the @output directiveWould you like to learn

Exploring the testing of a child component's @output feature in Angular 2 is my current goal. My aim is to utilize a mock version of the child component's @output functionality to trigger a function within the parent component for testing purposes.

I plan to mock the component and thoroughly test all asynchronous methods involved.

<wizard-quick-search-page *ngIf="initSearchPanel" [createUserAttributes]="createUserAttributes" [existingUserAttributes]="existingUserAttributes" (edit)="showEditUserPanel($event)"
  (create)="showCreateUserPanel($event)">
</wizard-quick-search-page>
@Component({
  selector: 'wizard-quick-search-page',
  template: '<button class="quick-search-page-submit" (click)="onClick()">Create</button>'
})
class MockQuickSearchPageComponent {
  @Output() public create: EventEmitter<any> = new EventEmitter<any>();
  public onClick(): void {
    console.log('call create');
    this.create.emit(true);
  }
}

fdescribe('AddUserComponent', () => {
  let component: AddUserComponent;
  let fixture: ComponentFixture<AddUserComponent>;
  let mockQuickSearchComponent: MockQuickSearchPageComponent;
  let mockQuickSearchComponentFixture: ComponentFixture<MockQuickSearchPageComponent>;
  let createButton: DebugElement;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        { provide: Language, useClass: MockLanguage }
      ],
      declarations: [
        AddUserComponent,
        MockQuickSearchPageComponent
      ],
      schemas: [NO_ERRORS_SCHEMA]
    })
      .compileComponents();
  }));

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  describe('quickSearchComponent', () => {
    beforeEach(() => {
      mockQuickSearchComponentFixture = TestBed.createComponent(MockQuickSearchPageComponent);
      mockQuickSearchComponent = mockQuickSearchComponentFixture.componentInstance;
      mockQuickSearchComponentFixture.detectChanges();

      createButton = mockQuickSearchComponentFixture.debugElement.query(By.css('button.quick-search-page-submit'));
    });

    it('should create', () => {
      expect(mockQuickSearchComponent).toBeTruthy();
    });

    it('should open create a new user panel', fakeAsync(() => {
      spyOn(component, 'showCreateUserPanel');
      createButton.triggerEventHandler('click', null);
      tick();
      mockQuickSearchComponentFixture.detectChanges();
      expect(component.showCreateUserPanel).toHaveBeenCalled();
    }));
  });
});

The parent component's function 'component.showCreateUserPanel' has not been called as expected.

Answer №1

If you are looking to test the communication between a parent and child component, it is recommended not to create an isolated instance of MockQuickSearchPageComponent, but rather use the instance that is initialized within the parent component.

Current Approach:

AddUserComponent  MockQuickSearchPageComponent

In the current implementation, they have no knowledge of each other.

TestBed.createComponent(MockQuickSearchPageComponent); creates a new component tree with MockQuickSearchPageComponent as the root component.

Preferred Approach:

 AddUserComponent  
       ||
       \/
MockQuickSearchPageComponent

Now, MockQuickSearchPageComponent is a child of AddUserComponent and can listen for any events emitted from the child component.

This can be achieved using

fixture.debugElement.query(By.directive(MockQuickSearchPageComponent)
:

describe('quickSearchComponent', () => {
  beforeEach(() => {
    fixture.componentInstance.initSearchPanel = true;
    fixture.detectChanges();

    const childDirQueryResult = 
             fixture.debugElement.query(By.directive(MockQuickSearchPageComponent));

    mockQuickSearchComponent = childDirQueryResult.componentInstance;

    createButton = childDirQueryResult.query(By.css('button.quick-search-page-submit'));
  });

  it('should create', () => {
    expect(mockQuickSearchComponent).toBeTruthy();
  });

  it('should open create a new user panel', () => {
    spyOn(component, 'showCreateUserPanel');
    createButton.triggerEventHandler('click', null);

    expect(component.showCreateUserPanel).toHaveBeenCalled();
  });
});

Example Link

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

Error in Mongoose Schema Configuration Detected in NestJS App

I'm currently developing an e-commerce application using NestJS and MongoDB with Mongoose. I've been facing an issue while trying to implement a user's shopping cart in the application. The error message I keep encountering is as follows: ...

Is there a way to attach a ref to a Box component in material-ui using Typescript and React?

What is the best way to attach a ref to a material-ui Box component in React, while using TypeScript? It's crucial for enabling animation libraries such as GreenSock / GSAP to animate elements. According to material-ui documentation, using the itemRef ...

Sharing methods between two components on the same page in Angular can greatly improve code efficiency

On a single page, I have two components sharing some methods and properties. How can I utilize a service to achieve this? See the sample code snippet below... @Component({ selector: 'app', template: '<h1>AppComponent1</h1>' ...

Issue with excluding certain events from being identified in the polyfills.ts file in Angular 8

While developing an application in Angular 8 that utilizes jsPlumbToolkit to showcase and modify flowcharts, I encountered performance issues. Upon investigating, I discovered that the change detection from zone.js was triggering at every mouse move event. ...

What is the proper way to refactor this TypeScript class?

Can you assist me in converting this class into TypeScript and explaining why it's not functioning? class Students { public name: string; public surname: string; public age: number; } constructor(name:string,surname:string,age:number) { ...

Utilizing Angular to pass a component as the ng-template of another component

In my Angular 6 application, I am faced with the challenge of passing a Component to another Component as an ng-template. The scenario involves having a Component A that needs to be replicated multiple times, each time with different components (referred t ...

Blending of Typescript Tuples

Is there a way to merge tuples in TypeScript such that one tuple is added at the end of another? Here is an example: type MergeTuple<A extends any[], B extends any[]> = [...A, ...B]; I have tried the following approach: type MergeTuple<A extend ...

Looking to seamlessly integrate a CommonJS library into your ES Module project while maintaining TypeScript compatibility?

I am interested in creating a project with Typescript. The project is built on top of the Typescript compiler, so I am utilizing Typescript as a library, which I believe is a CommonJS library. Although the project is designed to run on Node (not in the bro ...

Using aliases for importing will not function in the Vite (React, Typescript) starter template

I had installed shadcn/ui into my vite boilerplate as per the documentation, but ran into issues with the compiler not recognizing the aliasing. I discovered that TypeScript utilizes multiple configuration files - tsconfig.json, tsconfig.app.json, and tsco ...

Implementing ngFor to group values within div containers according to specific keys

In my Angular application, I am working with an array named calendarDates that holds various date-related information. calendarDates = [ {"date": "2018-10-23", "day": 5, "month":10, "year":2018, "price":"500", "date_is_valid": true}, {"date": "2018-10 ...

Creating a Custom Form Control in Angular 2 and Implementing Disable Feature

I have developed a unique custom control using ControlValueAccessor that combines an input[type=text] with a datepicker. While the template-driven forms accept it without any issues, the situation changes when implementing the model-driven approach (react ...

Create duplicates of both the array and its individual elements by value

I'm having trouble figuring out how to properly copy an array along with all its elements. In my model, I have a name and options, both of which are strings. This is what I currently have: const myArrayToDuplicate = [myModel, myModel, myModel] My ...

I'm looking to locate the API documentation for AngularJS TypeScript

After transitioning from using AngularJS 1.4 and plain JavaScript to now working with AngularJS 1.5 but utilizing TypeScript, I have found it challenging to find helpful documentation. For instance, when trying to inject services like $q or $timeout into m ...

Error Detection during Subject() Pipe Access Unit Test

I encountered an issue while writing a test case, where it is showing an error stating that pipe is not a function. The specific error message is: this.panelService.outputEmitter.pipe is not a function Below is the relevant code snippet in TypeScript an ...

Tips for comparing two typed objects using interfaces in React?

I am currently working in TypeScript and facing a challenge where I need to obtain the delta (key/value) of the modified attributes between two objects. Both objects are created using the same interface. export interface ITestObj { att1: string; att ...

Angular2 Event:keyup triggers the input to lose focus

I am working on a component with an input element that is bound to a property. I want the input field to update in real time as I type in it. Here is my current code: <input type="text" #updatetext [value]="item.name" (keyup)="updateItem(item.$key, up ...

I am interested in updating the content on the page seamlessly using Angular 6 without the need to reload

As a newcomer to Angular, I am interested in dynamically changing the page content or displaying a new component with fresh information. My website currently features cards, which you can view by following this Cards link. I would like to update the page ...

What should I do when dealing with multiple submit buttons in NextJS?

How can I differentiate between two submit buttons in a form component created in Next.js? I'm struggling to determine which button was pressed and need help resolving this issue. import React from "react"; const LoginPage = () => { as ...

Issue TS7053 occurs when trying to access any index of the target of a React.FormEvent<HTMLFormElement>

I've been working on adapting this tutorial to React and TypeScript. Here is the code snippet I have implemented for handling the onSubmit event: const handleSignUp = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); ...

What is the process for obtaining a new access token to connect with Google API using Firebase authentication in an Angular application?

In my Angular application, users log in using the Firebase provider. new firebase.auth.GoogleAuthProvider() Subsequently, firebase.auth().getRedirectResult() Upon accessing the application, I am only provided with a token such as ya29.a0AfH6SMAYg1A1RLw ...