spectator icon indicating copy to clipboard operation
spectator copied to clipboard

detectChanges is being triggered from setInput and setRouteParam

Open Adam-Pond opened this issue 3 years ago • 6 comments

Is this a regression?

Yes

Description

After setting up a component with detectChanges disabled (set to false in createRoutingFactory or createComponentFactory), detectChanges is called which triggers the ngOnInit to be called. If however, other setup needs to be set for the test to work during initialisation, there is now no opportunity to set the second. The second call does not trigger ngOnInit as it's already been called.

There is a workaround for setInput by setting multiple input parameters concurrently in the one statement

    spectator.setInput({
      param1: param1data,
      param2: param1data,
    });

But, this syntax is not available on setRouteParam.

Regardless, this is a regression and the fix is not to add additional multi-parameter overload to setRouteParam, but rather to respect the fact that it's not the framework's responsibility to call detectChnages when it's been disabled.

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

Stepping through in the debugger, it's easy to observe this behaviour.

Please provide the environment you discovered this bug in

Angular 14.1.0
"@ngneat/spectator": "^11.1.3",

Anything else?

fit('should not call ngOnInit before both route params are called', () => {
  // arrange
  spectator.setRouteParam('routeParam1', "routeParamValue2");
  // -- [ do some other setup that perhaps injects a service ] --
  
  // act
  spectator.detectChanges();  // expect that in ngOnInit, that further configuration can be done after setRouteParam but before detectChanges

  // never triggers ngOnInit because the first setRouteParam triggered
});

Do you want to create a pull request?

No

Adam-Pond avatar Jul 28 '22 12:07 Adam-Pond

This seems to be the culprit at a glance

    /**
     * Updates the route params and triggers a route navigation.
     */
    setRouteParam(name, value) {
        if (this.checkStubPresent()) {
            this.activatedRouteStub.setParam(name, value);
            this.triggerNavigationAndUpdate();   // <-- Not sure why setRoutParam should trigger a route navigation. Has this been added since previous versions?
        }
    }
    
    triggerNavigationAndUpdate() {
        this.activatedRouteStub.triggerNavigation();
        this.detectChanges();
    }

Adam-Pond avatar Jul 28 '22 12:07 Adam-Pond

Can confirm I ran into this with regards to setInput and detectChanges: false in a really simple test. In my case I was able to work around it with the ability mentioned in the OP to set multiple inputs at once, but ideally these methods should not call detectChanges if it is set to false.

localpcguy avatar Oct 26 '22 20:10 localpcguy

I found the same issues after updating from spectator 10.0.0, I feel this change is the differentiator: https://github.com/ngneat/spectator/issues/539 https://github.com/ngneat/spectator/commit/c40a2a6ef7dbd780da09a017d01b0158354d141b But perhaps this is working as intended as normally onInput change would also trigger change detection.

johant87 avatar Dec 23 '22 14:12 johant87

You're welcome to submit a PR

NetanelBasal avatar Dec 24 '22 16:12 NetanelBasal

any news ??? please let us know

gelsogrove avatar Feb 02 '23 13:02 gelsogrove

You could use SpectatorRouting.triggerNavigation()

This method allows you to set multiple params, queryParams, data etc. via the RouteOptions. It does not solve the problem if you need to set both input + params since it does triggers a route navigation..

For example:

    SpectatorRouting.triggerNavigation(
      {
        params: {
          testParam1: 'value1', 
          testParam2: 'value2'
        }
      }
    );

MCD1987 avatar Jun 17 '23 20:06 MCD1987