I'm currently implementing 'unit testing' in my angular application. However, if I run them, I receive multiple warnings/errors similar to this one: 'Error retrieving icon: Unable to find icon with the name ":myIcon"'
. I suspect it might be caused by not adding the svgs to my MatIconRegistry. I usually do this in my AppComponent, like so:
constuctor(private iconRegistry: MatIconRegistry,
private sanitizer: DomSanitizer,
...) {
iconRegistry.addSvgIcon('myIcon', sanitizer.bypassSecurityTrustResourceUrl('./assets/icons/myIcon.svg'));
}
If I run a unit test of another component though, this will not execute and thus not add my svg to the registry. I already tried adding it in my .spec file of the corresponding component, like so:
fdescribe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let iconRegistry;
let sanitizer;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
...
],
imports: [
...
],
providers: [
...
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
iconRegistry = TestBed.get(MatIconRegistry);
sanitizer = TestBed.get(DomSanitizer);
iconRegistry.addSvgIcon('myIcon', sanitizer.bypassSecurityTrustResourceUrl('./../../assets/icons/myIcon.svg'));
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create component', () => {
expect(component).toBeTruthy();
});
});
If I run this, it doesn't work. It just returns a different error message:
Error retrieving icon: <svg> tag not found
My initial thought was that I have made a mistake in the path, but after trying various other paths I'm sure thats not the case.
Does anyone know how do solve this problem? Or maybe there is a better way doing this, since I would have to add my svg icon in every component I'm testing, which would be kinda redundant.
SVG images can be written directly into the HTML document using the <svg> </svg> tag. To do this, open the SVG image in VS code or your preferred IDE, copy the code, and paste it inside the <body> element in your HTML document. If you did everything correctly, your webpage should look exactly like the demo below.
Add a class to the mat-icon html tag, as above. Next, add the SCSS for the class so that, when a user hovers over the button the colour of the icon changes. The Icons should now change colour when hovering over them. Enjoy!
can just do:
...
import { MatIcon } from '@angular/material/icon';
import { MatIconTestingModule } from '@angular/material/icon/testing';
describe('MyComponent', () => {
...
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyComponent, MatIcon],
imports: [MatIconTestingModule],
}).compileComponents();
}));
...
});
This will generate a test icon rendering without the http request
Mock the mat-icon
selector with the following component at the top of the unit test
@Component({
selector: 'mat-icon',
template: '<span></span>'
})
class MockMatIconComponent {
@Input() svgIcon: any;
@Input() fontSet: any;
@Input() fontIcon: any;
}
Then override the MatIconModule in the unit test as follows
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ ...],
providers: [ ... ],
imports: [ MatIconModule, NoopAnimationsModule ]
})
.overrideModule(MatIconModule, {
remove: {
declarations: [MatIcon],
exports: [MatIcon]
},
add: {
declarations: [MockMatIconComponent],
exports: [MockMatIconComponent]
}
})
.compileComponents();
You will no longer have the 'Error retrieving icon: Unable to find icon with the name ":myIcon"'
issue when running the unit tests
Just spent a couple hours on this. It looks like Angular now provides a FakeMatIconRegistry
. It squashed about 90% of the karma warnings, but still a few remain...
Had to do a lot of this:
TestBed.configureTestingModule({
declarations: [ MyComponent ],
imports: [
...
MatIconModule,
],
providers: [
...
{ provide: MatIconRegistry, useClass: FakeMatIconRegistry }
]
}).compileComponents();
Using typemoq for mocking; following worked for me:
const mockIconRegistry = Mock.ofType<MatIconRegistry>();
mockIconRegistry.setup(s => s.getNamedSvgIcon(It.isAny(), It.isAny())).returns(() => of(Mock.ofType<SVGElement>().object));
and then
providers: [{ provide: MatIconRegistry, useFactory: () => mockIconRegistry.object }]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With