io.component.ts

import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-io',
  template: `
        
        My favourite color is: {{color}}
    `,
})
export class IoComponent {
  @Input() color = '';
  @Output() colorChange = new EventEmitter<string>();

  changeColor() {
    this.colorChange.emit('pink');
  }
}

When testing Angular components with @Input() and @Output(), we need to verify they work as they would in a real app. The best way? Mock their parent (host) component.

This approach lets us:

  • Control input values passed to the component.
  • Capture emitted events exactly like a real parent would.

io-component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { IoComponent } from './io.component';
import { Component, ViewChild } from '@angular/core';

@Component({
  template: `
      
      `
})
class HostComponent {
  @ViewChild(IoComponent) ioComponent!: IoComponent;
  hostColor = 'red';
  emittedColor = '';
  onColorChanged(color: string) {
    this.emittedColor = color;
  };
}

describe('IoComponent', () => {
  let hostComponent: HostComponent;
  let hostFixture: ComponentFixture<HostComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [IoComponent, HostComponent]
    });
    hostFixture = TestBed.createComponent(HostComponent);
    hostComponent = hostFixture.componentInstance;
    hostFixture.detectChanges();
  });

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

  describe('Input binding', () => {
    it('should receive initial color from host', () => {
      expect(hostComponent.ioComponent.color).toBe('red');
    });

    it('should update when host changes color', () => {
      hostComponent.hostColor = 'blue';
      hostFixture.detectChanges();
      expect(hostComponent.ioComponent.color).toBe('blue');
    });
  });

  describe('Output binding', () => {
    it('should emit new color when button clicked', () => {
      const button = hostFixture.nativeElement.querySelector('button');
      button.click();
      expect(hostComponent.emittedColor).toBe('pink');
    });

    it('should emit through direct component call', () => {
      const spy = jest.spyOn(hostComponent.ioComponent.colorChange, 'emit');
      hostComponent.ioComponent.changeColor();
      expect(spy).toHaveBeenCalledWith('pink');
    });
  });

});