Before I begin, I have to say that I am VERY new to testing in Jasmine. It's one of these things that I didn't pay much attention or effort to when I was learning, and now I regret it.
Anyway, I'm writing unit testing for one of my components. Said component has a visible
boolean, initialized as false. When said boolean property becomes true, the component's display css attribute goes from none to block, making it visible.
Since my component is a child component, the cycle that I built so that a parent component technically 'triggers' the component is the following:
- The component initializes in an insivible state. Both the parent and the child are connected to a Service looking like this:
export class SidebarService {
public toggleSidebar: EventEmitter<void> = new EventEmitter();
constructor() {}
public showSidebar() {
this.toggleSidebar.emit();
}
}
The service does not require connection to any endpoints nor does it return any data: the emitter acts as a 'one-time-per-click' signal to the child component.
- Clicking a button in the parent template, the parent calls the following method:
toggleSidebar() {
this.sidebarService.showSidebar();
}
- On my child component's OnInit, I wrote the following:
ngOnInit() {
this.sidebarService.toggleSidebar.subscribe(() => {
this.visible = true;
});
}
So that when the parent triggers the event emitter, the child receives it and changes its visible
property. The child component has its own manual method to reset the visible property to false.
From a functional perspective, it does the job: the component 'appears' when the parent component clicks the button. But now I fear I might have botched the 'connectivity' aspect of their relation.
When writing the unit test, what I have so far for the component is the following:
describe('FilterSidebarComponent', () => {
let component: FilterSideBarComponent;
let fixture: ComponentFixture<FilterSideBarComponent>;
const sidebarServiceSpy = jasmine.createSpyObj('SidebarService', [
'showSidebar'
]);
const fb: FormBuilder = new FormBuilder();
configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [
MockModule(FormsModule),
MockModule(ReactiveFormsModule),
MockModule(TranslateModule.forRoot())
],
declarations: [
FilterSideBarComponent,
CheckboxInputComponent,
MockComponent(CountrySingleSearchComponent),
MockComponent(UniversitiesSearcherComponent)
],
providers: [
{provide: SidebarService, useValue: sidebarServiceSpy},
{provide: FormBuilder, useValue: fb},
]
});
});
beforeEach(() => {
fixture = TestBed.createComponent(FilterSideBarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
And the only test written so far ('should create'), fails, with Jasmine telling me: TypeError: Cannot read property 'subscribe' of undefined at at FilterSideBarComponent.subscribe [as ngOnInit]
I have searched for similar topics in StackOverflow regarding ways of mocking the subscription of services, but all examples I have found use services that return objects, data or Observables.
Of course I can rewrite the Service as long as it conserves its function, but- is there an effective way to test a 'Service' like mine, or should I rewrite the service in some way?