Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test component with providers

I have a service SoundPanelService which is used in service isolation scenario ( like https://angular.io/guide/hierarchical-dependency-injection#scenario-service-isolation )

@Injectable()
export class SoundPanelService {
  recorded = new Subject<Sound>();

  constructor() {
  }
}

and I have SoundPanelComponent

Component({
  selector: 'app-sound-panel',
  templateUrl: './sound-panel.component.html',
  styleUrls: ['./sound-panel.component.css'],
  providers: [SoundPanelService] // Service isolation 
})
export class SoundPanelComponent implements OnInit {
  recorded = new Subject<Sound>();

  constructor(private soundPanelService: SoundPanelService) {
    this.soundPanelService.recorded.subscribe((data) => {
      this.recorded.next(data);
    });
  }

  ngOnInit() {
  }

}

sound-panel.component.html

<app-sound-player></app-sound-player>
<app-sound-recorder></app-sound-recorder>

SoundPlayer and SoundRecorder communicate with soundpanel through service SoundPanelService.

I want to test SoundPanelComponent

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import { SoundPanelComponent } from './sound-panel.component';
import { SoundRecorderComponent } from '../sound-recorder/sound-recorder.component';
import { SoundPlayerComponent } from '../sound-player/sound-player.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { SoundPanelService } from 'src/app/_services/sound-panel.service';
import { Sound } from 'src/app/_models/Sound';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        SoundPanelComponent,
        SoundPlayerComponent,
        SoundRecorderComponent,
        SafeHtmlPipe
      ],
      imports: [HttpClientTestingModule],
      providers: [
      {
        provide: SoundPanelService, useClass: SoundPanelService
      }
      ]
    })
    .compileComponents();
  }));

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

  it('should emit sound on new record from sound panel service',  async () => {
    const s: Sound = {base64: 'data:base64', mimeType: 'audio/wmw'};
    spyOn(component.recorded, 'next').and.callThrough();
    sps = TestBed.get(SoundPanelService);
    sps.recorded.next(s);
    fixture.detectChanges();
    fixture.whenStable().then(res => {
expect(component.recorded.next).toHaveBeenCalledTimes(1);
    });
  });
   
});

but I get error

SoundPanelComponent > should emit sound on new record from sound panel service Expected spy next to have been called once. It was called 0 times.

If I make SoundPanelService providedIn: 'root' I manage to pass tests, but this is not what I want since I want SoundPanelService to be isolated to each SoundPanelComponent and it's children (I intend to have have many SoundPanelComponents on the same page).

How to test this?

like image 954
Developer Marius Žilėnas Avatar asked Feb 18 '26 22:02

Developer Marius Žilėnas


1 Answers

SOLVED

Used this Override component providers

Had to change code to this:

  1. introduced .overrideComponent
 beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        SoundPanelComponent,
        SoundPlayerComponent,
        SoundRecorderComponent,
        SafeHtmlPipe
      ],
      imports: [HttpClientTestingModule]
    })
    .overrideComponent(SoundPanelComponent, {
      set: {
        providers: [
          { provide: SoundPanelService, useClass: SoundPanelService}
        ]
      }
    })
    .compileComponents();
  }));
  1. get SoundPanelService from debug element:
it('should emit sound on new record from sound panel service',  async () => {
    const s: Sound = {base64: 'data:base64', mimeType: 'audio/wmw'};
    spyOn(component.recorded, 'next').and.callThrough();
    sps = fixture.debugElement.injector.get(SoundPanelService) as SoundPanelService;
    sps.recorded.next(s);
    fixture.detectChanges();
    fixture.whenStable().then(res => {
      expect(component.recorded.next).toHaveBeenCalledTimes(1);
    });
  });

Test passed!

like image 133
Developer Marius Žilėnas Avatar answered Feb 20 '26 17:02

Developer Marius Žilėnas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!