Search code examples
angulartestingsvgjasmine

How do I add svg files via MatIconRegistry in unit tests?


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.


Solution

  • 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