5

I am trying to write integration tests for a component in angular using TestBed. there is some data being injected into component for material dialog using @inject(MAT_DIALOG_DATA). I want to test two cases. One is when no data is provided and other one is when some data is provided. But I wanted to configure testing module same way for all cases (in beforeEach method). So for cases without data being injected I am configuring the module as below:

    TestBed.configureTestingModule({
          declarations: [
            PostNewComponent
          ].concat(EntryComponents1),
          imports: [TestingModule],
          providers: [
            PostService,
            { provide: MAT_DIALOG_DATA, useValue: {} },
            { provide: MatDialogRef, useValue: { close: (dialogResult: any) => {}, updateSize: () => {} }}
          ]
        });

and then I have a case in which I want to test the passed test data. so I tried the following to override the provider.

    TestBed.overrideProvider(MAT_DIALOG_DATA, {useValue : {name: "passedName"}});

but is doesn't override the provider. I debugged the issue and found that overrideProvider is finally calling following method in core.js

        /**
     * Read the `ngInjectableDef` for `type` in a way which is immune to accidentally reading inherited
     * value.
     *
     * @param type A type which may have its own (non-inherited) `ngInjectableDef`.
     */
    function getInjectableDef(type) {
        var def = type[NG_INJECTABLE_DEF];
        // The definition read above may come from a base class. `hasOwnProperty` is not sufficient to
        // distinguish this case, as in older browsers (e.g. IE10) static property inheritance is
        // implemented by copying the properties.
        //
        // Instead, the ngInjectableDef's token is compared to the type, and if they don't match then the
        // property was not defined directly on the type itself, and was likely inherited. The definition
        // is only returned if the type matches the def.token.
        return def && def.token === type ? def : null;
    }

and "type" parameter passed to this function in case of MAT_DIALOG_DATA does not contain ngInjectableDef property. I don't have in depth knowledge of angular so can someone explain why is it not working and what exactly this read-only property "ngInjectableDef" is ?

AlexElin
  • 1,044
  • 14
  • 23
Muhammad Usman
  • 101
  • 1
  • 11

1 Answers1

2

I faced a similar problem. Not sure why it's not working but I was able to use a workaround for my situation. Since in the component's constructor we have

@Inject(MAT_DIALOG_DATA) public data: any,

we can access this value in the individual tests and just change their values e.g.:

component.data.name = "passedName";

Hope this helps.

super IT guy
  • 195
  • 2
  • 12
  • 2
    I would not recommend doing so. Setting class members to public just for the sake of testing is bad practise. – Smaïl Hammour Feb 19 '20 at 13:22
  • I did not write the actual code in the constructor, I was only writing the unit tests, but I think you could do the same thing for private like this: component['data'].name = "passedName"; – super IT guy Feb 20 '20 at 21:21
  • It is not good practice to touch private parts of the class directly – Imants Volkovs Sep 02 '22 at 08:47