Testing MdDialog component, getting an error

4,484 views
Skip to first unread message

Jeff Moss

unread,
Oct 28, 2016, 5:46:04 PM10/28/16
to angular-material2
I am trying to test a component I made and I'm getting this error:

Error: No provider for MdDialogRef!

Here is my test setup:


import { UserModule } from './user.module';


import { MdDialogModule, MdDialogRef } from '@angular/material';
import { MdIconModule } from '@angular/material';
import { TestBed, async, inject } from '@angular/core/testing';
import { UserSubscriptionComponent, SubscribeDialogComponent } from './subscription.component';


fdescribe
('Component: UserSubscription', () => {
    beforeEach
(() => {
       
TestBed.configureTestingModule({
            imports
: [
               
MdIconModule.forRoot(),
               
MdDialogModule.forRoot(),
               
UserModule.forRoot()
           
]
       
});
   
});

And the test:
    it('should render the dialog', async(inject([MdDialogRef], (ref: MdDialogRef<SubscribeDialogComponent>) => {
        let component
= TestBed.createComponent(SubscribeDialogComponent);
        component
.detectChanges();
        expect
(component.nativeElement.textContent).toContain('Upgrade to Premier for $95/yr');
   
})));

By the way I have other components like the UserSubscriptionComponent working. It's just the SubscribeDialogComponent (which the UserSubscriptionComponent opens) that I can't seem to initialize.

Here's what the component looks like:

@Component({
    selector
: 'mv-subscribe-dialog',
    templateUrl
: './subscribe-dialog.component.html',
    styleUrls
: ['./subscription-dialog.component.css']
})


export class SubscribeDialogComponent {
   
public card: PaymentMethod;


    loading
: boolean = false;
    years
: Array<string>;
    months
: Array<string>;
    states
: Array<string>;
    countries
: Array<string>;


    constructor
(
       
public dialogRef: MdDialogRef<SubscribeDialogComponent>,
       
private billing: BillingService,
       
private messages: MessageService
   
) {

Any ideas?

The opener component works fine, also it works in my browser when I run the code. It's just the test setup that I can't figure out. Why does it expect MdDialogRef to be a "provider"?

I have tried putting it in the TestBed.configureTestingModule call as the providers: [ MdDialogRef ], but I just get a different error:

Error: Can't resolve all parameters for MdDialogRef: (?).

If someone has a component test working, which uses MdDialogRef in the constructor, I'd love to see how you're doing it.

Thanks,
-Jeff
 

Ashwin Kumar

unread,
Nov 10, 2016, 9:55:26 PM11/10/16
to angular-material2
I have the same issue. I was wondering if you were able to find a solution.

Jeff Moss

unread,
Nov 11, 2016, 12:58:00 PM11/11/16
to angular-material2
Yes, here is my test, maybe some others will find this example useful. Here I am testing both the component that triggers the dialog as well as the dialog:

import { UserModule } from './user.module';

import { MdDialogModule, MdDialog, MdDialogConfig, MdDialogRef, MdIconModule, OverlayContainer } from '@angular/material';
import { TestBed, async, inject } from '@angular/core/testing';
import { FormBuilder, FormGroup } from '@angular/forms';
import { UserSubscriptionComponent, SubscribeDialogComponent } from './subscription.component';

describe('Component: UserSubscription', () => {
    let overlayContainerElement: HTMLElement;

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                MdIconModule.forRoot(),
                MdDialogModule.forRoot(),
                UserModule.forRoot()
            ],
            providers: [{
                provide: OverlayContainer,
                useFactory: () => {
                    overlayContainerElement = document.createElement('div');
                    return {
                        getContainerElement: () => overlayContainerElement
                    };
                }
            }]
        });
    });

    it('should render a response', () => {
        let component = TestBed.createComponent(UserSubscriptionComponent);
        component.detectChanges();
        expect(component.nativeElement.textContent).toContain('Upgrade for $1!');
    });

    it('should open a dialog when upgrade is clicked', () => {
        let component = TestBed.createComponent(UserSubscriptionComponent);
        expect(component.componentInstance.dialogRef).not.toBeDefined();
        document.getElementById('upgrade-action').click();
        expect(component.componentInstance.dialogRef).toBeDefined();
    });

    it('should render the dialog correctly', () => {
        let component = TestBed.createComponent(UserSubscriptionComponent);
        component.componentInstance.upgrade();
        let dialogRef = component.componentInstance.dialogRef;
        expect(overlayContainerElement.textContent).toContain('Card Number');
        expect(overlayContainerElement.textContent).toContain('Expiration Date');
        expect(overlayContainerElement.textContent).toContain('CVV');
        expect(overlayContainerElement.textContent).toContain('Cardholder Name');
        expect(overlayContainerElement.textContent).toContain('Address 1');
        expect(overlayContainerElement.textContent).toContain('Address 2');
        expect(overlayContainerElement.textContent).toContain('City');
        expect(overlayContainerElement.textContent).toContain('State');
        expect(overlayContainerElement.textContent).toContain('Postal Code');
    });

    it('submits the upgrade request fields', inject([BillingService], (billing: BillingService) => {
        let component = TestBed.createComponent(UserSubscriptionComponent);
        component.componentInstance.upgrade();
        let dialogRef = component.componentInstance.dialogRef;
        let dialog = dialogRef.componentInstance;
        let paymentMethod = {
            accountKey: 'A00000020',
            creditCardType: 'Visa',
            creditCardNumber: '4111111111111111',
            expirationMonth: '10',
            expirationYear: '2020',
            securityCode: '911',
            cardHolderInfo: {
                cardHolderName: 'Jeff Moss',
                addressLine1: '1234 Main St',
                addressLine2: '',
                city: 'Salt Lake City',
                state: 'UT',
                zipCode: '84123',
                country: 'USA',
                phone: '8015551234',
                email: 'je...@example.com'
            }
        };
        let observable = {
            subscribe: (callback) => {
                callback({ success: true });
            }
        };
        component.detectChanges();
        let form = <FormGroup> dialog.paymentMethodForm;
        form.controls['creditCardNumber'].setValue('4111111111111111');
        form.controls['expirationMonth'].setValue('10');
        form.controls['expirationYear'].setValue('2020');
        form.controls['securityCode'].setValue('911');
        let group = <FormGroup> dialog.paymentMethodForm.controls['cardHolderInfo'];
        group.controls['cardHolderName'].setValue('Jeff Moss');
        group.controls['addressLine1'].setValue('1234 Main St');
        group.controls['city'].setValue('Salt Lake City');
        group.controls['state'].setValue('UT');
        group.controls['country'].setValue('USA');
        group.controls['zipCode'].setValue('84123');
        group.controls['phone'].setValue('8015551234');
        group.controls['email'].setValue('je...@example.com');
        spyOn(billing, 'createPaymentMethod').and.returnValue(observable);
        dialog.processUpgrade();
        expect(billing.createPaymentMethod).toHaveBeenCalledWith(paymentMethod);
    }));
});


d_m...@digitalfoundry.com

unread,
Dec 2, 2016, 9:09:42 PM12/2/16
to angular-material2
Hi Jeff, I was wondering if there was anything else you had to tweak in your project in order to get this to work, perhaps your SubscriptionDialogComponent or UserSubscription component? Really any insight into what the solution to your problem was would be very much appreciated. As it stands I'm having trouble determining what fixed your problem just by looking at your test file.

jeff moss

unread,
Dec 5, 2016, 12:10:28 PM12/5/16
to d_m...@digitalfoundry.com, angular-material2
I'm essentially testing the dialog.open method. Here is what upgrade() looks like:
    upgrade () {
        if (!this.dialogRef) {
            let config = new MdDialogConfig();
            config.viewContainerRef = this.viewContainerRef;
            this.dialogRef = this.dialog.open(SubscribeDialogComponent, config);
            this.dialogRef.afterClosed().subscribe(
                result => this.dialogRef = null
            );
        }
    }

--
You received this message because you are subscribed to a topic in the Google Groups "angular-material2" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular-material2/xo29ERf0Mx4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular-material2+unsubscribe@googlegroups.com.
To post to this group, send email to angular-material2@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/angular-material2/a8b6de7e-801a-4ad0-8cc6-90dc7f7b75b2%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Stefan Aerts

unread,
Dec 13, 2016, 9:41:42 AM12/13/16
to angular-material2
So no answer from Jeff,
this pease of code has nothing to do with the error "No provider for MdDialogRef".
I have this code and i have the steps followed.I still get that error.
To unsubscribe from this group and all its topics, send an email to angular-materi...@googlegroups.com.
To post to this group, send email to angular-...@googlegroups.com.

Jorge Villegas

unread,
Dec 16, 2016, 10:08:12 AM12/16/16
to angular-material2
So, is there no way to test the dialog itself alone?

Jorge Villegas

unread,
Dec 28, 2016, 6:38:29 AM12/28/16
to angular-material2
Well, I finally got it working, with almost the same code from Jeff, but had to add this piece of code:

TestBed.configureTestingModule({
  declarations: [ DialogComponent],
});

TestBed.overrideModule(BrowserDynamicTestingModule, {
  set: {
    entryComponents: [ DialogComponent],
  },
});

Got it from a GH issue (https://github.com/angular/angular/issues/10760), hope it helps someone...

Rene Vallecillo

unread,
Jan 20, 2017, 6:02:21 PM1/20/17
to angular-material2
That one not working for me
beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ConfirmDialogComponent],
      imports: [MdDialogModule.forRoot()],
      providers: [
        {
          provide: OverlayContainer,
          useFactory: () => {
            overlayContainerElement = document.createElement('div');
            return { getContainerElement: () => overlayContainerElement };
          }
        }
      ],
    })
      .overrideModule(BrowserDynamicTestingModule, {
        set: {
          entryComponents: [ConfirmDialogComponent],
        },
      })
      .compileComponents();
  }));


Reply all
Reply to author
Forward
0 new messages