2

I'm trying to test an angular material dialog, specifically, I want to test that it modifies the route when the dialog is closed. To that end, I don't want to mock/stub the dialog out (I don't think?), because I want it to run the actual .subscribe method that does the re-routing.

I'm getting two errors, on my actual dialog:

this.dialogRef.afterClosed is not a function

login-dialog-component.spec.ts

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [LoginDialogComponent],
      imports: [
        RouterTestingModule.withRoutes([]),
        MatDialogModule
      ],
      providers: [
        {provide: MatDialog},
        {provide: MAT_DIALOG_DATA, useValue: {}},
        {provide: MatDialogRef, useValue: {}},
      ]
    })
      .compileComponents();
  }));

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

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

The second error I'm getting is the test for the component that opens my dialog. It reports:

NullInjectorError: R3InjectorError(DynamicTestModule)[MatDialog -> Overlay -> Overlay]: 
  NullInjectorError: No provider for Overlay!

The test for component that opens my dialog: login.component.spec.ts

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ LoginComponent ],
      providers: [
        { provide: MatDialog },
        { provide: MAT_DIALOG_DATA, useValue: {} },
        { provide: MatDialogRef, useValue: {}}
      ]
    })
    .compileComponents();
  }));

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

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

The LoginComponent itself doesn't really require any testing, but as said above it's giving me the "No provider for overlay", presumably because the constructor is:

 constructor(
    private dialog: MatDialog
  ) { }

LoginComponent then opens the LoginDialog.

The code I wish to test in LoginDialog is:

 ngOnInit(): void {
    this.dialogRef.afterClosed().subscribe(_ =>
      this.router.navigate(['', {outlets: {login: null}}])
    );
  }

I want to ensure the router actually navigates away when the dialog closes.

So my question are

  1. How do I pass in a real dialogRef to the constructor of LoginDialog?
  2. How to get rid of the No provider for Overlay error?

Btw, if I change

{ provide: MatDialogRef, useValue {})

to:

{ provide: MatDialogRef }

(So I'm presumably trying to pass an actual MatDialogRef in)

The error changes from

this.dialogRef.afterClosed is not a function

to:

Can't resolve all parameters for MatDialogRef: (?, ?).

Thank you.

Bubbleshadow
  • 196
  • 1
  • 3
  • 10

1 Answers1

6

Try:

In login-dialog-component.spec.ts, remove the whole providers array because we shouldn't be mocking inner workings of MatDialog but keep MatDialogModule in the imports.

In login.component.spec.ts, add MatDialogModule in the imports array of TestBed.configureTestingModule and remove the providers array as mentioned previously.

AliF50
  • 16,947
  • 1
  • 21
  • 37
  • 1) That gives me "No provider for MatDialogRef". I've found on https://github.com/angular/components/issues/8419#issuecomment-359698681 it seems MatDialogRef cannot be injected during tests, thus the solution is to use mocks. – Bubbleshadow Sep 27 '20 at 00:32
  • https://stackoverflow.com/questions/48703365/angular-how-to-mock-matdialogref-while-testing Oh sorry about that, check out the last 2 answers there then. – AliF50 Sep 27 '20 at 00:35
  • 1
    2) Thank you, that seems to have fixed the issue for the LoginComponent. I think to fix the other issue I'm going to have to just use a mock, I won't be able to test the router code if a real MatDialogRef can't be injected. I'll probably accept your answer. Thanks again. – Bubbleshadow Sep 27 '20 at 00:39