Search code examples
angularjasmine

Spy on local variable inside function


I have a method that opens a Dialog and then when closed the dialog, it will delete an element which has been passed.
What i would like to do is to 'spy' on the afterClosed().subscribe method, the method:

deleteDialog = MatDialog;
onDeleteElementClicked($event: any, elementName: string): void {
        const dialogRef = this.deleteDialog.open(CustomDialog, {
            data: {
                //SOME DATA
           });

 
        dialogRef.afterClosed().subscribe(result => {
            this.toggleFlagAndCall(result, () => {
                this.deleteElement(this.result.name);
            });
        });
    }

The test:

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

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [
                DeleteComponent,
            ],
            imports: [
                // some imports
            ],
            providers: [
                { provide: MatDialogRef, useClass: MatDialogRef, useValue: { afterOpen: () => of(true)}},
                { provide: DeleteDialogComponent, useValue: { afterClosed: () => of(true)}},
                { provide: MatDialog, useValue: { afterClosed: () => of(true),
                    open: () => of(true)}},
                }
            ]
        })
            .compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(DeleteComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

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

    it('should delete a single element', () => {
        const event = {
            preventDefault: () => {},
            stopPropagation: () => {}
        };

        component.onDeleteElementClicked(event, 'toBeDeletedElement');
        expect(component.elements.length).toBe(0);
    });
});

I get the error:

TypeError: dialogRef.afterClosed is not a function

But i thought that this line:

{ provide: MatDialog, useValue: { afterClosed: () => of(true),

Would create the mock method for 'afterclosed' and would return an observable, but it does not even get invoked.
How can i spy on dialogRef.afterClosed().?


Solution

  • You could make a mock class MatDialog

    class MatDialogMock {
      open() {
        return {
          afterClosed: () => of(true)
        };
      }
    }
    

    Then in the test, you can use that mock class

    providers: [
      { provide: MatDialog, useClass: MatDialogMock }
    ]
    

    You now get an instance of MatDialogMock when your component uses MatDialog, and you can then use the afterClosed property to spy on it.