Search code examples
javascriptangularunit-testingjasminekarma-jasmine

jasmine unit-testing: Can't trigger change event in custom angular dropdown component


I am working on unit-testing with jasmine and karma an angular component. In the template-component a custom dropdown component is used:

   <div class="my-modal-body">
        <form [formGroup]="form" class="form-horizontal">
            <div class="padding-dropdown">
                <my-form-wrapper
                    label="Dateiformat"
                    labelClass="col-lg-4 two-col-label-size"
                    inputClass="col-lg-8 two-col-input-size"
                >
                    <my-dropdown
                        [items]="exportOptionen"
                        formControlName="dateiTyp"
                        (selectedChange)="exportFileChange($event)"
                    >
                    </my-dropdown>
                </my-form-wrapper>
            </div>

In my testing I try to test the value change, but can't get it working. However I try to set the value, the exportFileChange is not triggered. And I know that the component is correct, because it's already in production. So it has to be the test that errors.

Here is my test:

    it('dateiTyp auswahl excel', waitForAsync(() => {
        spyOn(component, 'exportFileChange');
        dateiTyp.setValue('Excel');
        component.dateiTyp.setValue('Excel', { emitEvent: true });
        fixture.detectChanges();
        fixture.whenStable().then(
            () => {
                expect(component.exportFileChange).toHaveBeenCalled();
                let exDiv = fixture.debugElement.query(By.css("#excelExportDiv"));
                expect(exDiv).not.toBeNull();
            }
        );
    }));

When changing the selection the exportFileChange(event) method should be called and in the template an div appears. The exportFileChange-Method in the component just changes an boolean. I tested changing the boolean in the test and that worked, but the event still wasn't triggered.

Here are the most relevant parts of the setup:

describe('ExportModalComponent', () => {
   [...]
   let dateiTyp: jasmine.SpyObj<FormControl>;
   let dateiTypChange: Subject<string>;
[...]

beforeEach( waitForAsync(() => {
[...]
  dateiTyp = jasmine.createSpyObj('dateiTyp', ['value', 'setValue']);
  formGroup.get.withArgs('dateiTyp').and.returnValue(dateiTyp);
  dateiTypChange = new Subject();
  Object.defineProperty(dateiTyp, 'valueChanges', { value: dateiTypChange });
[...]

and my-dropdown.component.d.ts:

export declare class myDropdownComponent implements ControlValueAccessor, OnInit, OnChanges 
{ [...] }

I can change the ExportModal-template or the ExportModal-component but I can't change the implementation or use of myDropdownComponent.

I am grateful for every help!

Thanks!


Solution

  • This is not a complete answer but it should help you.

    This is a good read. In these kind of situations, I just use triggerEventHandler on the DebugElement.

    Something like this:

    it('should do abc', () => {
       // get a handle on the debugElement
       const myDropDown = fixture.debugElement.query(By.css('my-dropdown'));
       // the first argument is the name of the event you would like to trigger
       // and the 2nd argument of type object (or anything) is the $event you want to mock for the calling function
       myDropDown.triggerEventHandler('selectedChange', { /* mock $event here */});
       // continue with tests
    });
    

    I am not entirely sure how your components are wired but that's the best way I have found to raise custom events for custom components.