Skip to content

Commit

Permalink
fix: Use correct view when using eagerServerLoad (#14036)
Browse files Browse the repository at this point in the history
* fix: Use correct view when using eagerServerLoad

Returns 404 for non-existant views

Helps with #13421
  • Loading branch information
Artur- authored and vaadin-bot committed Jun 27, 2022
1 parent 46755ee commit a504891
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ private static Map<String, List<String>> toFullParameters(
* @return query parameters information
*/
public static QueryParameters fromString(String queryString) {
if (queryString == null) {
return empty();
}
return new QueryParameters(parseQueryString(queryString));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.vaadin.flow.router.InvalidLocationException;
import com.vaadin.flow.router.Location;
import com.vaadin.flow.router.LocationUtil;
import com.vaadin.flow.router.QueryParameters;
import com.vaadin.flow.server.AppShellRegistry;
import com.vaadin.flow.server.BootstrapHandler;
import com.vaadin.flow.server.HandlerHelper;
Expand Down Expand Up @@ -90,9 +91,32 @@ public JavaScriptBootstrapContext(VaadinRequest request,
}

private static Location initRoute(VaadinRequest request) {
// This can be called in two ways:
// 1. From the JS during the second phase of a two phase init. In
// this case, the
// location is included in the REQUEST_LOCATION_PARAMETER and the
// request always
// goes to the servlet path
// 2. During the first request if eagerServerLoad is enabled. In
// this case, the
// location comes from the pathinfo + query parameters in the
// request
String pathAndParams = request.getParameter(
ApplicationConstants.REQUEST_LOCATION_PARAMETER);
return new Location(pathAndParams);
if (pathAndParams != null) {
return new Location(pathAndParams);
}

// Case 2, use the request
if (request instanceof VaadinServletRequest) {
return new Location(request.getPathInfo(),
QueryParameters
.fromString(((VaadinServletRequest) request)
.getQueryString()));
} else {
return new Location(request.getPathInfo(),
QueryParameters.empty());
}
}

}
Expand Down
5 changes: 3 additions & 2 deletions flow-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<vaadin.allow.appshell.annotations>false</vaadin.allow.appshell.annotations>
<useDeprecatedV14Bootstrapping>false</useDeprecatedV14Bootstrapping>
<vaadin.devmode.vite.options>--host</vaadin.devmode.vite.options>

<vaadin.eagerServerLoad>false</vaadin.eagerServerLoad>
<!-- make sure we do not leave webpack-dev-server running after IT -->
<vaadin.reuseDevServer>false</vaadin.reuseDevServer>
</properties>
Expand Down Expand Up @@ -223,7 +223,7 @@
<vaadin.reuseDevServer>${vaadin.reuseDevServer}</vaadin.reuseDevServer>
<vaadin.devmode.liveReload.enabled>${vaadin.devmode.liveReload.enabled}</vaadin.devmode.liveReload.enabled>
<vaadin.allow.appshell.annotations>${vaadin.allow.appshell.annotations}</vaadin.allow.appshell.annotations>

<vaadin.eagerServerLoad>${vaadin.eagerServerLoad}</vaadin.eagerServerLoad>
<jetty.scantrigger>${jetty.scantrigger}</jetty.scantrigger>
<!-- Allow test clients not on localhost to connect to Vite-->
<vaadin.devmode.vite.options>${vaadin.devmode.vite.options}</vaadin.devmode.vite.options>
Expand Down Expand Up @@ -313,6 +313,7 @@

<module>test-root-context</module>

<module>test-eager-bootstrap</module>
<module>test-v14-bootstrap</module>
<module>test-v14-bootstrap/pom-production.xml</module>

Expand Down
65 changes: 65 additions & 0 deletions flow-tests/test-eager-bootstrap/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.vaadin</groupId>
<artifactId>flow-tests</artifactId>
<version>23.2-SNAPSHOT</version>
</parent>
<artifactId>flow-test-eager-bootstrap</artifactId>
<name>Flow eager bootstrap (includes UIDL in first request) test</name>
<packaging>war</packaging>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<vaadin.eagerServerLoad>true</vaadin.eagerServerLoad>
</properties>

<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>flow-test-resources</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-dev-server</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>flow-maven-plugin</artifactId>
<configuration>
<productionMode>false</productionMode>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<executions>
<!-- start and stop jetty (running our app) when running
integration tests -->
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.eagerbootstrap;

import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;

@Route("hello")
public class HelloView extends Div {
public HelloView() {
setId("view");
setText("This is the Hello view");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.eagerbootstrap;

import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.router.Route;

@Route("")
public class RootView extends Div {
public RootView() {
setId("view");
setText("This is the root view");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.flow.servlet;

import org.junit.Assert;
import org.junit.Test;

import com.vaadin.flow.testutil.ChromeBrowserTest;

public class BasicViewsIT extends ChromeBrowserTest {

@Test
public void rootViewShown() throws Exception {
getDriver().get(getRootURL() + "/");
Assert.assertEquals("This is the root view",
$("*").id("view").getText());
}

@Test
public void helloViewShown() throws Exception {
getDriver().get(getRootURL() + "/hello");
Assert.assertEquals("This is the Hello view",
$("*").id("view").getText());
}

@Test
public void invalidViewShowsNotFound() throws Exception {
getDriver().get(getRootURL() + "/nonexistant");

Assert.assertTrue(getDriver().getPageSource()
.contains("Could not navigate to 'nonexistant'"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2022 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.flow.servlet;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;

import com.vaadin.flow.testutil.ChromeBrowserTest;

public class LowLevelFetchIT extends ChromeBrowserTest {

public static class OtherResponseCodeException extends IOException {

private int responseCode;

public OtherResponseCodeException(int responseCode) {
this.responseCode = responseCode;
}

public int getResponseCode() {
return responseCode;
}

}

@Test
public void rootViewContainsRootUIDL() throws Exception {
open(); // This is only to wait for the dev server...
String source = getUrl(getRootURL() + "/");
Assert.assertTrue(source.contains(
"\"key\":\"text\",\"feat\":7,\"value\":\"This is the root view\""));
}

private String getUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();

if (conn.getResponseCode() != 200) {
throw new OtherResponseCodeException(conn.getResponseCode());
}

return IOUtils.toString(conn.getInputStream(), StandardCharsets.UTF_8);
}

@Test
public void helloViewContainsHelloViewUidl() throws Exception {
open(); // This is only to wait for the dev server...
String source = getUrl(getRootURL() + "/hello");
Assert.assertTrue(source.contains(
"\"key\":\"text\",\"feat\":7,\"value\":\"This is the Hello view\""));
}

@Test
public void notFoundViewReturns404() throws Exception {
open(); // This is only to wait for the dev server...
try {
getUrl(getRootURL() + "/notfound");
} catch (OtherResponseCodeException e) {
Assert.assertEquals(404, e.getResponseCode());
return;
}
Assert.fail("Should have thrown OtherResponseCodeException");
}

@Override
protected String getTestPath() {
return "";
}

}

0 comments on commit a504891

Please sign in to comment.