Angular Unit Test Observable/Subject with Karma

Alan Grosz picture Alan Grosz · Aug 16, 2017 · Viewed 7k times · Source

I am trying to test a Subject change in my component, but the coverage never enters into the subscribe function.

titlebar-search.component.ts

export class TitlebarSearch implements OnInit {

    @ViewChild('titleSearchInput') titleSearchInputEl: any;
    @Input() inputValue: string;
    @Output() searchText = new EventEmitter<string>();
    searchChange: Subject<string> = new Subject<string>();


    constructor(private renderer: Renderer) {

    }    

    /**
     * Waits a time before send the text to search
     * 
     * @protected
     * @memberof TitlebarSearch    
     * 
     */
    protected prepareSearchInput() {
        this.searchChange.debounceTime(500).subscribe(value => {
            this.searchText.emit(value);
        });
    }

    /**
     * Send the text to the searchChange Observable
     * 
     * @param {string} text 
     * @memberof TitlebarSearch
     */
    public doSubmit(text:string){
        this.searchChange.next(text);        
    }    

}

titlebar-search.component.spec.ts

describe('Titlebar Search tests', () => {
    let fixture;
    let titlebarComponent;

    beforeEach(async(() => {
        //Creates a UserService using a mock class
        TestBed.configureTestingModule({
            declarations: [TitlebarSearch],
            imports: [FormsModule],
            //CUSTOM_ELEMENTS_SCHEMA to solve html elements issues
            schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
            providers: [Renderer]
        }).compileComponents().then(() => {
            fixture = TestBed.createComponent(TitlebarSearch);            
            titlebarComponent = fixture.componentInstance
        });

    }));

    //specs
    it('should send the text to detect the change', async((done) => {        
        const text = "Changed text";
        titlebarComponent.doSubmit(text);
        fixture.detectChanges();
        titlebarComponent.searchChange.subscribe(textRecived => {
            expect(textRecived).toEqual(text);
            done();
        })     
    }));           
});

The doSubmit method, is called when the input text had been changed. Then the prepareSearchInput has a subscription to the subject to get the next with debounce and output the same text.

I don't know where is the mistake in the test, but the coverage never cover the subscription code. The examples over Internet did't help me.

Answer

JP Lew picture JP Lew · Feb 9, 2018

I had the same problem, but got the answer from @jonrsharpe in this thread: Unit test Angular 2 service subject.

You need to declare your subject subscription earlier in your test, before the next() is called. If you reorder it like this, it should work:

it('should send the text to detect the change', async((done) => {        
    titlebarComponent.searchChange.subscribe(textRecived => {
        expect(textRecived).toEqual(text);
        done();
    })   
    const text = "Changed text";
    titlebarComponent.doSubmit(text);
    fixture.detectChanges();
}));     

The problem, according to John, was that your subject didn't have any replay/buffer behaviour.