Narshe
Narshe

Reputation: 466

Testing components with Font Awesome Icons Module

I'm currently working in an Angular 6 project where I have imported several of the new font-awesome 5 icons using the Fort-awesome module for angular.

As expected, by doing so now some of my Unit Tests (Karma + Jasmine) won't pass due to not being able to render the fa-icon selectors in my pages.

I understand that I could use a CUSTOM_ELEMENTS_SCHEMA in the TestBed for each component but I don't know if by doing so I may have other side effects that would make my unit tests less reliable (i.e. other sub-components may stop being tested).

Another option is to simply import the module in each of the required unit tests, and in each of those, also add the library.add() with the required icons. I do think, however, this could end up being tedious as there may be between 20 and 50 icons depending on the type of application.

I've also thought, but haven't tried yet, to add a stub module for the icons, so I simply "ignore" them. I think this could be reasonable, but not sure what the best practice would be in this case.

Below an excerpt of my imports in App.Module

import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faLock, faHourglassHalf, faLockOpen } from '@fortawesome/free-solid-svg-icons';

And in the constructor

export class AppModule {
  constructor() {
    library.add(
      faHourglassHalf, // Task in progress
      faLockOpen, // Archive task
      faLock
    );
  }
} 

Full repo here: https://github.com/Narshe1412/Code-Institute-Interactive-Frontend-Project/tree/taskman

As I know this is not debate forum I would simply ask:

Upvotes: 9

Views: 7285

Answers (4)

Yoan Dieu
Yoan Dieu

Reputation: 161

You can now use font-awesome testing module like this:

import {FontAwesomeTestingModule} from '@fortawesome/angular-fontawesome/testing';

TestBed.configureTestingModule({imports: [ FontAwesomeTestingModule ]}).compileComponents();

Upvotes: 14

1FpGLLjZSZMx6k
1FpGLLjZSZMx6k

Reputation: 1067

I do not like the other solutions, even if they may work. To me it seems unclean importing the AppModule in a unit test.

My solution is to separate the icons from the other stuff, as described below. This solution is kind of like the already accepted answer, but cleaner in my opinion:

import { NgModule } from '@angular/core';
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
import { faDownload, faUpload, faFileExport, faCircle, faChevronRight, faChevronDown, faPlus, faTimes } from '@fortawesome/free-solid-svg-icons';

@NgModule({
  imports: [ FontAwesomeModule ],
  exports: [ FontAwesomeModule ]
})
export class IconsModule {
  constructor(library: FaIconLibrary) {
    // add icons to the library for convenient access in other components
    library.addIcons(faDownload, faUpload, faFileExport, faCircle, faChevronRight, faChevronDown, faPlus, faTimes);
  }
}

Then import the IconsModule wherever you need it, be it in the application itself or in a test:

AppModule:

import { IconsModule } from './icons.module';

@NgModule({
  declarations: [...],
  imports: [
    ...
    IconsModule,
  ],
  bootstrap: [...]
})
export class AppModule {}

Unit Test:

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ MyComponent ],
      imports: [
        ...
        IconsModule,
      ]
    })
    .compileComponents();
  }));

  ...

});

HTML:

<fa-icon icon="download"></fa-icon>

Nice side effect: If you ever were to change the font library from Font Awesome to something else, this is much easier now, as you only have to change the IconsModule and the respective HTML code for the icons.

Upvotes: 13

Jeppe Gravgaard
Jeppe Gravgaard

Reputation: 63

Looks like there is already an accepted answer for this issue, but I will try to supplement with info from a related topic.

You can mock everything from external modules, but the imported component's selectors. There is an easy way which is to disable this kind of errors as you mentioned.

Can't bind to 'icon' since it isn't a known property of 'fa-icon'

import { NO_ERRORS_SCHEMA } from '@angular/core';

...

TestBed.configureTestingModule({
  schemas: [ NO_ERRORS_SCHEMA ],
  ...

The NO_ERRORS_SCHEMA tells the Angular compiler to ignore unrecognized elements and attributes.

Otherwise I would suggest to add FontAwesome directly into the testbed despite it being a tedious task. It improves readability and avoids importing redundant components in the test module. This mainly becomes a problem when you have more than one component.

TestBed.configureTestingModule({
  imports: [
    FontAwesomeModule
  ]
})
.compileComponents();

Upvotes: 0

peinearydevelopment
peinearydevelopment

Reputation: 11474

I would just like to throw out a 'third' option. This is the approach that my team and I have been using and prefer.

The module brings in the FontAwesomeModule.

import { NgModule } from '@angular/core';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    FontAwesomeModule
  ],
  exports: [
    FontAwesomeModule
  ]
})

export class AppModule { }

The component that actually uses the font awesome icons imports only the icons it needs to know about.

import {
  Component
} from '@angular/core';

import { faLock } from '@fortawesome/free-solid-svg-icons';

@Component({
  selector: 'app-fa-example',
  template: '<fa-icon [icon]="faLock"></fa-icon>'
})
export class AppComponent {
  faLock = faLock;
}

Then in our *.spec.ts files, we have a setup like the following:

TestBed.configureTestingModule({
  imports: [
    AppModule
  ]
})
.compileComponents();

Since the FontAwesomeModule is exported in the AppModule it will be available to the test bed here through the AppModule import. Since the icons are being imported explicitly in the component, there is no need to library.add(...) here either specifying all of the font awesome icons used in the module/component.

Upvotes: 1

Related Questions