Bubbleshadow
Bubbleshadow

Reputation: 196

Angular / Jasmine: No provider for Overlay! Also how to test a material dialog

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.

Upvotes: 2

Views: 9469

Answers (1)

AliF50
AliF50

Reputation: 18859

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.

Upvotes: 6

Related Questions