Angular close generic Dialog testing

Viewed 83

I'm having Dialog Service for open, confirm and close the dialog and I am making its unit test file but I got an error wail testing the bellow method on Angular and this is the code.

dialog.service.ts

@Injectable({
  providedIn: 'root'
})
export class DialogService {
  public genericDialogRef?: MatDialogRef<GenericDialogComponent>;

  constructor(
    private dialog: MatDialog,
    private toastr: ToastrService,
    private translateService: TranslateService
  ) { }

  public openGenericDialog(options: GenericDialogOptions) {
const filledInConfig: Required<GenericDialogOptions> = { ...defaultValues, ...options };
this.genericDialogRef = this.dialog.open(GenericDialogComponent, {
  data: filledInConfig
});
  }

  public genericDialogClosed(): Observable<boolean> {
    if (!this.genericDialogRef)
      throw Error("Dialog ref wasn't initialized! Call open first");

    return this.genericDialogRef.afterClosed().pipe(take(1));
  }
}

dialog.service.spec.ts

describe('DialogService', () => {
  let service: DialogService;
  let matDialogMock = jasmine.createSpyObj(['open']);
  let toastrServiceMock = {};
  let dialog: any;
  let translateService: TranslateService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [TranslateModule.forRoot()],
      providers: [
        { provide: MatDialog, useValue: matDialogMock },
        { provide: ToastrService, useValue: toastrServiceMock },
      ],
    });
    service = TestBed.inject(DialogService);
    dialog = TestBed.inject(MatDialog);
    translateService = TestBed.inject(TranslateService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should close generic Dialog', fakeAsync(() => {

    service.genericDialogClosed().subscribe(() => {
      expect(service.genericDialogRef?.afterClosed).toHaveBeenCalled();
    });

    tick();
  }));

});

Here is the error: enter image description here could you please help me to fix this issue?

Edit: The below test works fine:

  it('should close generic Dialog', () => {
    service.genericDialogRef = {
      afterClosed: () => of(true)
    } as MatDialogRef<GenericDialogComponent>;

    service.genericDialogClosed()
  });

1 Answers

That's the correct outcome because genericDialogRef was never set. Quick fix would be to set it manually, best with some mock. But since you are testing if afterClosed was called, you should wrap it to a fakeAsync function and subscribe to genericDialogClosed function, otherwise it won't work.

EDIT: As I said, I was hoping for a very simple solution, but in your case it's getting complicated. The reason is, that you assign DialogRef with a specific type to a service's property and the type check won't allow my simple value assign. So you can either mock it:

// Create a mock
const matDialogRefMock: MatDialogRef<GenericDialogComponent> {
  // completely mock the DailogRef
  afterClosed: () => of(true);
}

it('should close generic Dialog', fakeAsync(() => {
  // then assign it before you try to close the dialog
  service.genericDialogRef = matDialogRefMock;

  service.genericDialogClosed().subscribe(() => {
    expect(service.genericDialogRef?.afterClosed).toHaveBeenCalled();
  });
  // Make the async tick happen
  tick();  
}));

Or you can try to open the dialog before closing it, so that the reference is existing.

it('should close generic Dialog', fakeAsync(() => {
  // open the dialog in order to create a reference to it
  service.openGenericDialog();

  service.genericDialogClosed().subscribe(() => {
    expect(service.genericDialogRef?.afterClosed).toHaveBeenCalled();
  });
  // Make the async tick happen
  tick();  
}));

I had a similar test case once and when I opened the dialog in one it test case I assigned the reference to the top level variable, which was then available for another it test to close it.

Related