help-me-mom / ng-mocks

Angular testing library for mocking components, directives, pipes, services and facilitating TestBed setup
https://www.npmjs.com/package/ng-mocks
MIT License
1.06k stars 77 forks source link

Defualt values of component inputs are overridden with MockRender #434

Closed vinayk406 closed 3 years ago

vinayk406 commented 3 years ago

https://stackblitz.com/edit/ng-mocks-examples-mkp6fd?file=app/app.component.spec.ts

In the provided stackblitz example, I expected the testcase to pass.

When we use MockRender(AnyComponent), the template is generated as <app-any [input1]=input1 [input2]=input2></app-any>

This overrides the default values of input1 and input2 defined in the component class.

This problem can be solved by using MockRender('<app-any></app-any>').

I feel it will be better if there is a configurable option for controlling template generation.

satanTime commented 3 years ago

Hi @vinayk406,

thanks for the report, I'll take a look deeper during next days.

As far as I remember, the problem is that default values aren't always the case if optional chaining is used.

<app-any [input1]="my?.data?.obj?.input1"></app-any>

Although input1 can be typed as input1: string = 'defaultValue', it will receive null if my is empty. The right declaration is this case is input1: string | null = 'defaultValue'. In order to show this behavior <app-any [input1]=input1 [input2]=input2></app-any> is generated.

Anyway, I'll take a look for a possible solution besides MockRender('<app-any></app-any>').

satanTime commented 3 years ago

Hi @vinayk406,

could you verify that the new version works as you expect? ng-mocks.zip

Thanks in advance!

vinayk406 commented 3 years ago

Thanks @satanTime

LGTM.

Is there any way to memoize the response of Mockrender between tests to improve performance?

satanTime commented 3 years ago

Great, thanks for checking.

Could you create a separate issue about memoization? It should be possible with ngMocks.faster and MockRender in beforeAll instead of beforeEach. At least it was the intention. But this feature hasn't been deeply tested and may not work as expected.

satanTime commented 3 years ago

There are some ongoing checks of other changes. A release with the fix will be on the next weekend.

satanTime commented 3 years ago

v11.11.0 has been released and contains a fix for the issue. Feel free to reopen the issue or to submit a new one if you meet any problems.

vinayk406 commented 3 years ago

Can we eliminate the creation of <mock-render> intermediary component in the below case?

MockRender(XComponent, {})

In this case, can we bypass the creation of intermediary component and call TestBed.createComponent(XComponent) directly to speed up the processing?

satanTime commented 3 years ago

Hi @vinayk406,

unfortunately, it is not only about passing / not passing params.

If XComponent is an onPush component, then, without <mock-render>, it cannot be tested properly. Because nothing is rerendered in default TestBed.createComponent despite input / output changes.

MockRender doesn't forbid usage of TestBed.createComponent(XComponent), it is a function which creates proper environment like a real angular app. If you don't need the environment, it is fine to use TestBed.createComponent(XComponent) instead.

satanTime commented 3 years ago

You can try to use TestBed.createComponent here to reproduce the issue: https://github.com/ike18t/ng-mocks/blob/6b07067d751f29b4eba6d5db2773d605a35b3add/tests/issue-537/test.spec.ts

vinayk406 commented 3 years ago

Sounds good. Thanks for the explanation.

Hi @vinayk406,

unfortunately, it is not only about passing / not passing params.

If XComponent is an onPush component, then, without <mock-render>, it cannot be tested properly. Because nothing is rerendered in default TestBed.createComponent despite input / output changes.

MockRender doesn't forbid usage of TestBed.createComponent(XComponent), it is a function which creates proper environment like a real angular app. If you don't need the environment, it is fine to use TestBed.createComponent(XComponent) instead.