Skip to content

Commit

Permalink
fix: forward/reroute when query parameters changed (#17659)
Browse files Browse the repository at this point in the history
Forward and reroute should run even when targeting the same target
but with different query parameters.

Fixes #17639
  • Loading branch information
mcollovati committed Sep 21, 2023
1 parent 5a65925 commit bb258af
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -658,18 +658,25 @@ protected Optional<Integer> handleTriggeredBeforeEvent(
if (beforeEvent.hasExternalForwardUrl()) {
return Optional.of(forwardToExternalUrl(event, beforeEvent));
}

boolean queryParameterChanged = beforeEvent.hasRedirectQueryParameters()
&& !beforeEvent.getRedirectQueryParameters()
.equals(event.getLocation().getQueryParameters());

if (beforeEvent.hasForwardTarget() && (!isSameNavigationState(
beforeEvent.getForwardTargetType(),
beforeEvent.getForwardTargetRouteParameters())
|| queryParameterChanged
|| !(navigationState.getResolvedPath() != null
&& navigationState.getResolvedPath()
.equals(beforeEvent.getForwardUrl())))) {
return Optional.of(forward(event, beforeEvent));
}

if (beforeEvent.hasRerouteTarget()
&& !isSameNavigationState(beforeEvent.getRerouteTargetType(),
beforeEvent.getRerouteTargetRouteParameters())) {
&& (!isSameNavigationState(beforeEvent.getRerouteTargetType(),
beforeEvent.getRerouteTargetRouteParameters())
|| queryParameterChanged)) {
return Optional.of(reroute(event, beforeEvent));
}

Expand Down
212 changes: 211 additions & 1 deletion flow-server/src/test/java/com/vaadin/flow/router/RouterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import java.util.stream.Stream;

import net.jcip.annotations.NotThreadSafe;

import org.hamcrest.MatcherAssert;
import org.junit.After;
import org.junit.Assert;
Expand Down Expand Up @@ -66,6 +65,7 @@

import elemental.json.Json;
import elemental.json.JsonObject;

import static com.vaadin.flow.router.internal.RouteModelTest.parameters;
import static com.vaadin.flow.router.internal.RouteModelTest.varargs;
import static org.hamcrest.CoreMatchers.is;
Expand Down Expand Up @@ -466,6 +466,68 @@ public void beforeEnter(BeforeEnterEvent event) {
}
}

@Route("rerouteWithQueryParams")
@Tag(Tag.DIV)
public static class RerouteWithQueryParams extends RouteParametersBase
implements BeforeEnterObserver {

static int events = 0;

static void clear() {
RouteParametersBase.clear();
events = 0;
}

@Override
public void beforeEnter(BeforeEnterEvent event) {
events++;
super.beforeEnter(event);
QueryParameters queryParameters = event.getLocation()
.getQueryParameters();
String updateQueryParams = queryParameters
.getSingleParameter("updateQueryParams").orElse(null);
QueryParameters newParams = QueryParameters.of("newParam", "hello");
if (queryParameters.getParameters().isEmpty()) {
event.rerouteTo("show", newParams);
} else if ("true".equals(updateQueryParams)) {
event.rerouteTo("rerouteWithQueryParams", newParams);
} else if ("false".equals(updateQueryParams)) {
event.rerouteTo("rerouteWithQueryParams", queryParameters);
}
}
}

@Route("forwardWithQueryParams")
@Tag(Tag.DIV)
public static class ForwardWithQueryParams extends RouteParametersBase
implements BeforeEnterObserver {

static int events = 0;

static void clear() {
RouteParametersBase.clear();
events = 0;
}

@Override
public void beforeEnter(BeforeEnterEvent event) {
events++;
super.beforeEnter(event);
QueryParameters queryParameters = event.getLocation()
.getQueryParameters();
String updateQueryParams = queryParameters
.getSingleParameter("updateQueryParams").orElse(null);
QueryParameters newParams = QueryParameters.of("newParam", "hello");
if (queryParameters.getParameters().isEmpty()) {
event.forwardTo("show", newParams);
} else if ("true".equals(updateQueryParams)) {
event.forwardTo("forwardWithQueryParams", newParams);
} else if ("false".equals(updateQueryParams)) {
event.forwardTo("forwardWithQueryParams", queryParameters);
}
}
}

@Route("redirect/to/param")
@Tag(Tag.DIV)
public static class RedirectToRouteWithParamInUrl extends Component
Expand Down Expand Up @@ -1736,6 +1798,8 @@ public void init() throws NoSuchFieldException, SecurityException,
@After
public void tearDown() {
CurrentInstance.clearAll();
ForwardWithQueryParams.clear();
RerouteWithQueryParams.clear();
}

@Rule
Expand Down Expand Up @@ -4159,6 +4223,152 @@ public void forwardToExternalUrl_forwardsToUrl() {

}

@Test
public void reroute_queryParameters()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(RerouteWithQueryParams.class, ShowAllView.class);

router.navigate(ui, new Location("rerouteWithQueryParams"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected reroute to ShowAll view but was "
+ RouteParametersBase.target,
ShowAllView.class, RouteParametersBase.target);
Assert.assertEquals("Expecting reroute view to be entered once", 1,
RerouteWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("newParam").orElse(null);
Assert.assertEquals("Missing parameter after reroute", "hello",
singleParameter);
}

@Test
public void reroute_queryParameters_sameNavigationTarget()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(RerouteWithQueryParams.class, ShowAllView.class);

router.navigate(ui,
new Location("rerouteWithQueryParams?updateQueryParams=true"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected reroute to same view but was "
+ RouteParametersBase.target,
RerouteWithQueryParams.class, RouteParametersBase.target);
Assert.assertEquals("Expecting reroute view to be entered twice", 2,
RerouteWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("newParam").orElse(null);
Assert.assertEquals("Missing parameter after reroute", "hello",
singleParameter);
Assert.assertTrue(
"Expecting original parameter not be present after reroute",
RouteParametersBase.queryParameters
.getSingleParameter("updateQueryParams").isEmpty());
}

@Test
public void reroute_sameQueryParameters_sameNavigationTarget()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(RerouteWithQueryParams.class, ShowAllView.class);

router.navigate(ui,
new Location("rerouteWithQueryParams?updateQueryParams=false"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected reroute to same view but was "
+ RouteParametersBase.target,
RerouteWithQueryParams.class, RouteParametersBase.target);
Assert.assertEquals("Expecting reroute view to be entered once", 1,
RerouteWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("updateQueryParams").orElse(null);
Assert.assertEquals("Expecting original parameter after reroute",
"false", singleParameter);
Assert.assertTrue(
"Expecting new parameter not to be present after reroute",
RouteParametersBase.queryParameters
.getSingleParameter("newParam").isEmpty());
}

@Test
public void forward_queryParameters()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(ForwardWithQueryParams.class, ShowAllView.class);

router.navigate(ui, new Location("forwardWithQueryParams"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected forward to ShowAll view but was "
+ RouteParametersBase.target,
ShowAllView.class, RouteParametersBase.target);
Assert.assertEquals("Expecting forward view to be entered once", 1,
ForwardWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("newParam").orElse(null);
Assert.assertEquals("Missing query parameter after forward", "hello",
singleParameter);
}

@Test
public void forward_queryParameters_sameNavigationTarget()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(ForwardWithQueryParams.class, ShowAllView.class);

router.navigate(ui,
new Location("forwardWithQueryParams?updateQueryParams=true"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected forward to same view but was "
+ RouteParametersBase.target,
ForwardWithQueryParams.class, RouteParametersBase.target);
Assert.assertEquals("Expecting forward view to be entered twice", 2,
ForwardWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("newParam").orElse(null);
Assert.assertEquals("Missing query parameter after forward", "hello",
singleParameter);
Assert.assertTrue(
"Expecting original parameter not be present after forward",
RouteParametersBase.queryParameters
.getSingleParameter("updateQueryParams").isEmpty());
}

@Test
public void forward_sameQueryParameters_sameNavigationTarget()
throws InvalidRouteConfigurationException {
RouteParametersBase.clear();
setNavigationTargets(ForwardWithQueryParams.class, ShowAllView.class);

router.navigate(ui,
new Location("forwardWithQueryParams?updateQueryParams=false"),
NavigationTrigger.PROGRAMMATIC);

Assert.assertEquals(
"Expected forward to same view but was "
+ RouteParametersBase.target,
ForwardWithQueryParams.class, RouteParametersBase.target);
Assert.assertEquals("Expecting forward view to be entered once", 1,
ForwardWithQueryParams.events);
String singleParameter = RouteParametersBase.queryParameters
.getSingleParameter("updateQueryParams").orElse(null);
Assert.assertEquals("Missing original query parameter after forward",
"false", singleParameter);
Assert.assertTrue(
"Expecting new parameter not be present after forward",
RouteParametersBase.queryParameters
.getSingleParameter("newParam").isEmpty());
}

private void assertWrongRouteParametersRedirect() {
assertRouteParameters("show/wrong", null, null);
}
Expand Down

0 comments on commit bb258af

Please sign in to comment.