I have a component (MapComponent) that calls external API via HexesService. Results of Data of this API call are loaded to some buttons (View Map, Edit Map). I have another internal component (HexesComponent) and clicking on a View button makes a call to this internal component (which in turn makes another API call and displays the data inside of HexesComponent).
I've created a test with a mock of external service. My test checks that after the main component is loaded it makes call to the mocked service and loads data properly (all buttons are populated). This works perfectly fine.
The next thing I'd like to check that click on the button makes a call to a method of the HexesComponent.
The problem I have is that my internal component is always undefined. I've created a stub for my internal component, but this did not help: even the stab is empty.
Question #1: What do I do wrong? I've tried using async for the method inside the 'beforeEach', this did not help.
Needless to say that outside of 'tests', the functionality works perfectly fine.
Question #2: How to validate that clicking on the button leads to the call of 'loadMap' method of the HexComponent?
Here is the code of my test:
class MockHexesService extends HexesService {
getDataForButtons(){
return of(...);
}
...
}
@Component({ selector: 'app-hex', template: '' })
class HexStubComponent {
public loadMap = jasmine.createSpy('loadMap');
}
describe('MapsComponent', () => {
let component: MapsComponent;
let hexComponent: HexStubComponent;
let fixture: ComponentFixture<MapsComponent>;
let componentService: HexesService;
let hexComponentSpy: any;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
declarations: [MapsComponent, HexStubComponent],
providers: [HexesService],
}).compileComponents();
TestBed.overrideComponent(MapsComponent, {
set: {
providers: [{ provide: HexesService, useClass: MockHexesService }],
},
});
fixture = TestBed.createComponent(MapsComponent);
component = fixture.componentInstance;
componentService = fixture.debugElement.injector.get(HexesService);
fixture.detectChanges();
hexComponent = fixture.debugElement.injector.get(HexStubComponent);
hexComponentSpy = spyOn(hexComponent, 'loadMap');
});
it('Loaded map descriptions should load data for buttons', () => {
const tblRows =
fixture.debugElement.nativeElement.querySelectorAll('table tr');
const cells0 = tblRows[0].querySelectorAll('td');
expect(cells0[0].innerHTML).toBe('Map 1');
... checking other buttons are populated properly
expect(component.hexComponent).toBeTruthy(); // - this fails here
});
it('Click on "View" button should load the map', async(() => {
//spyOn(component.hexComponent.loadMap)
const btns = fixture.debugElement.nativeElement.querySelectorAll('button');
expect(btns.length).toBe(6);
const btnView = btns[0];
expect(btnView.innerHTML).toBe('View Map');
btnView.click();
fixture.whenStable().then(() => {
expect(component.hexComponent).toBeTruthy(); // - this fails
// and how do I check that 'loadMap' method of hexComponent is called with proper data?
});
}));
});
Essential part of maps.component.html:
...
<tr *ngFor="let d1 of data">
...
<button (click)="loadMap(d1.mapId)">View Map</button>
...
</tr>
<app-hex id="hexComponent"></app-hex>
Essential part of maps.component.ts:
export class MapsComponent implements OnInit {
@ViewChild(HexComponent) hexComponent: HexComponent;
constructor(public ngZone: NgZone, private hexesService: HexesService) {}
ngOnInit(): void {
this.hexesService
.getDataForButtons()
.subscribe((data: any) => this.populateButtons(data));
}
loadMap(mapId): void {
this.hexComponent.loadMap(mapId);
}
P.S. I've found a similar question (How can I use a fake/mock/stub child component when testing a component that has ViewChildren in Angular 10+?) which suggests to use ng-mocks, but could not make them work.
P.P.S. I've tried to use
@Component({ selector: 'app-hex', template: '' })
class HexStubComponent {
//public loadMap(mapId: number) {}
public loadMap = jasmine.createSpy('loadMap');
}
and use HexStubComponent in declarations for 'TestBed.configureTestingModule', but my test gives error:
NullInjectorError: R3InjectorError(DynamicTestModule)[HexStubComponent -> HexStubComponent]: NullInjectorError: No provider for HexStubComponent!
Can't figure out how to resolve that.