Search code examples
angularjskarma-jasmineangular-unit-test

How to fake child components while unit testting


I'm new to testing with Jasmine and Karma. Pardon me if I'm asking anything wrong. I've a component app-timeselector inside which there are some custom child components. The template looks like:

timeselector.component.html

<kls-label></kls-label>
<kls-dropdown></kls-dropdown>
<kls-option></kls-option>

In the above example I've shown only three but in my case there are 11 of them. So, the solution that I know is to mock them. And I'm doing this one by one for all 11 child components like this:

import { TestBed, ComponentFixture, async } from "@angular/core/testing"
import { TimeselectorComponent } from './timeselector.component'
...

describe('TimeselectorComponent', () => {
    let fixture: ComponentFixture<TimeselectorComponent>;
    @Component({
        selector: 'kls-label',
        template: '<div></div>'
    })
    class FakeKlsLabelComponent {}

    @Component({
        selector: 'kls-dropdown',
        template: '<div></div>'
    })
    class FakeKlsDropdownComponent {}


    @Component({
        selector: 'kls-option',
        template: '<div></div>'
    })
    class FakeKlsDropdownOption {
        @Input() value;
    }

    ...

    beforeEach(async(()=>{
        TestBed.configureTestingModule({
            imports: [
                ...
            ],
            providers: [
                ...
            ],
            declarations: [
                TimeselectorComponent,
                FakeKlsLabelComponent,
                FakeKlsDropdownComponent,
                FakeKlsDropdownOption,
                ...
            ],
        });
        fixture = TestBed.createComponent(TimeselectorComponent);

    }))
    it('should create', ()=> {
        expect(fixture.componentInstance).toBeTruthy();
    })

    it('should apply filters accross dashboards', () => {
        ...
    })
})

Is this a good practice. Is there are way to mock all of them together. I don't want to use NO_ERRORS_SCHEMA. I've yesterday started following Pluralsight tutorials.


Solution

  • Use ng-mocks

    Use it like this:

    import { MockComponent } from 'ng-mocks';
    
    // import your real components
    import { KlsLabelComponent } from ...
    import { KlsDropdownComponent } from ...
    import { KlsDropdownOption } from ...
    
    TestBed.configureTestingModule({
        imports: [
            ...
        ],
        providers: [
            ...
        ],
        declarations: [
            TimeselectorComponent,
            // mock them
            MockComponent(KlsLabelComponent),
            MockComponent(KlsDropdownComponent),
            MockComponent(KlsDropdownOption),
            ...
        ],
    });
    

    EDIT: You're doing something wrong, too:

    And I'm doing this one by one for all 11 child components like this

    Your component is too big. If it has 11 child components, your component has far too much responsibility (and will be extremely difficult to use, debug, refactor AND test). Break it down into smaller components.