From fcbdbbcb30bf90856bef046eebc1db114b3ce1d9 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 15 Feb 2018 11:13:31 +0300 Subject: [PATCH 01/10] Parse html import dependencies and add them as dependencies via UIInternals Fix for #3479 --- .../component/internal/ComponentMetaData.java | 47 +++++- .../internal/HtmlDependencyParser.java | 147 ++++++++++++++++++ .../flow/component/internal/UIInternals.java | 11 +- 3 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java index a2c69e08b63..374f6a7da51 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/ComponentMetaData.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.vaadin.flow.component.Component; @@ -34,6 +35,7 @@ import com.vaadin.flow.component.dependency.Uses; import com.vaadin.flow.internal.AnnotationReader; import com.vaadin.flow.internal.ReflectTools; +import com.vaadin.flow.shared.ui.LoadMode; /** * Immutable meta data related to a component class. @@ -48,11 +50,11 @@ public class ComponentMetaData { * Framework internal class, thus package-private. */ public static class DependencyInfo { - private final List htmlImports = new ArrayList<>(); + private final List htmlImports = new ArrayList<>(); private final List javaScripts = new ArrayList<>(); private final List styleSheets = new ArrayList<>(); - List getHtmlImports() { + List getHtmlImports() { return Collections.unmodifiableList(htmlImports); } @@ -66,6 +68,27 @@ List getStyleSheets() { } + public static class HtmlImportDependency { + + private final Collection uris; + + private final LoadMode loadMode; + + private HtmlImportDependency(Collection uris, + LoadMode loadMode) { + this.uris = uris; + this.loadMode = loadMode; + } + + public Collection getUris() { + return Collections.unmodifiableCollection(uris); + } + + public LoadMode getLoadMode() { + return loadMode; + } + } + /** * Synchronized properties defined for a {@link Component} class. *

@@ -126,8 +149,8 @@ private static DependencyInfo findDependencies( scannedClasses.add(componentClass); - dependencyInfo.htmlImports.addAll( - AnnotationReader.getHtmlImportAnnotations(componentClass)); + dependencyInfo.htmlImports + .addAll(getHtmlImportDependencies(componentClass)); dependencyInfo.javaScripts.addAll( AnnotationReader.getJavaScriptAnnotations(componentClass)); dependencyInfo.styleSheets.addAll( @@ -169,6 +192,22 @@ public DependencyInfo getDependencyInfo() { return dependencyInfo; } + private static Collection getHtmlImportDependencies( + Class componentClass) { + return AnnotationReader.getHtmlImportAnnotations(componentClass) + .stream().map(ComponentMetaData::getHtmlImportDependencies) + .collect(Collectors.toList()); + } + + private static HtmlImportDependency getHtmlImportDependencies( + HtmlImport htmlImport) { + String value = htmlImport.value(); + HtmlDependencyParser parser = new HtmlDependencyParser(value); + + return new HtmlImportDependency(parser.parseDependencies(), + htmlImport.loadMode()); + } + /** * Scans the class for {@link Synchronize} annotations and gathers the data. * diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java new file mode 100644 index 00000000000..26cb3b44afe --- /dev/null +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java @@ -0,0 +1,147 @@ +/* + * Copyright 2000-2017 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.component.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + +import javax.servlet.ServletContext; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.vaadin.flow.server.VaadinRequest; +import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.VaadinUriResolverFactory; +import com.vaadin.flow.server.WrappedHttpSession; + +/** + * Html import dependencies parser. + *

+ * It takes the an HTML import url as a root and parse the content recursively + * collecting html import dependencies. + * + * @author Vaadin Ltd + * + */ +public class HtmlDependencyParser { + + private final String root; + + /** + * Creates a new instance using the given {@code uri} as a root. + * + * @param uri + * HTML import uri + */ + public HtmlDependencyParser(String uri) { + this.root = uri; + } + + Collection parseDependencies() { + Set dependencies = new HashSet<>(); + + parseDependencies(root, dependencies); + + return dependencies; + } + + private void parseDependencies(String path, Set dependencies) { + if (dependencies.contains(path)) { + return; + } + dependencies.add(path); + + VaadinRequest request = VaadinService.getCurrentRequest(); + VaadinSession session = VaadinSession.getCurrent(); + if (request == null || session == null + || request.getWrappedSession() == null) { + /* + * Cannot happen in runtime. + * + * But not all unit tests set it. So let's just return the root uri + * and return. + */ + return; + } + VaadinUriResolverFactory factory = session + .getAttribute(VaadinUriResolverFactory.class); + assert factory != null; + ServletContext context = ((WrappedHttpSession) request + .getWrappedSession()).getHttpSession().getServletContext(); + + String resolvedUri = factory.toServletContextPath(request, path); + + try (InputStream content = context.getResourceAsStream(resolvedUri)) { + if (content == null) { + getLogger().info( + "Can't find resource '%s' via the servlet context", + path); + } + + parseHtmlImports(content, path).map(uri -> resolveUri(uri, path)) + .forEach(uri -> parseDependencies(uri, dependencies)); + } catch (IOException exception) { + // ignore exception on close() + getLogger().debug("Couldn't close template input stream", + exception); + } + } + + private String resolveUri(String relative, String base) { + try { + URI uri = new URI(base); + return uri.resolve(relative).toString(); + } catch (URISyntaxException exception) { + getLogger().debug( + "Couldn't make URI for {}. The path {} will be used as is.", + base, relative); + } + return relative; + } + + private Stream parseHtmlImports(InputStream content, String path) { + assert content != null; + try { + Document parsedDocument = Jsoup.parse(content, + StandardCharsets.UTF_8.name(), ""); + + return parsedDocument.getElementsByTag("link").stream() + .filter(link -> link.hasAttr("rel") && link.hasAttr("href")) + .filter(link -> link.attr("rel").equals("import")) + .map(link -> link.attr("href")); + } catch (IOException exception) { + getLogger().info( + "Can't parse the template declared using '%s' path", path, + exception); + } + return Stream.empty(); + } + + private Logger getLogger() { + return LoggerFactory.getLogger(HtmlDependencyParser.class); + } +} diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java index ef6089009cc..370681f80a1 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/UIInternals.java @@ -779,16 +779,17 @@ public void addComponentDependencies( Page page = ui.getPage(); DependencyInfo dependencies = ComponentUtil .getDependencies(componentClass); - dependencies.getHtmlImports().forEach(html -> page - .addHtmlImport(getHtmlImportValue(html), html.loadMode())); + dependencies.getHtmlImports() + .forEach(html -> html.getUris().forEach( + uri -> page.addHtmlImport(getHtmlImportValue(uri), + html.getLoadMode()))); dependencies.getJavaScripts() .forEach(js -> page.addJavaScript(js.value(), js.loadMode())); dependencies.getStyleSheets().forEach(styleSheet -> page .addStyleSheet(styleSheet.value(), styleSheet.loadMode())); } - private String getHtmlImportValue(HtmlImport html) { - String importValue = html.value(); + private String getHtmlImportValue(String importValue) { if (theme != null) { return VaadinServlet.getCurrent().getUrlTranslation(theme, importValue); @@ -864,7 +865,7 @@ public void setContinueNavigationAction( /** * Gets the application id tied with this UI. Different applications in the * same page have different unique ids. - * + * * @return the id of the application tied with this UI */ public String getAppId() { From 1bd88bf3fdf4c7d70bec5d437034f475c70f46a8 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 15 Feb 2018 12:41:26 +0300 Subject: [PATCH 02/10] Correct absolute URL handling and add a test UI view for IT test --- .../internal/HtmlDependencyParser.java | 10 ++-- .../ui/template/ThemedTemplateView.java | 47 +++++++++++++++++++ .../src/main/webapp/frontend/absolute.html | 32 +++++++++++++ .../uitest/ui/template/ThemedTemplate.html | 32 +++++++++++++ .../template/custom-theme/ThemedTemplate.html | 38 +++++++++++++++ .../ui/template/custom-theme/relative1.html | 32 +++++++++++++ .../flow/uitest/ui/template/relative2.html | 32 +++++++++++++ 7 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java create mode 100644 flow-tests/test-root-context/src/main/webapp/frontend/absolute.html create mode 100644 flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/ThemedTemplate.html create mode 100644 flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html create mode 100644 flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/relative1.html create mode 100644 flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html diff --git a/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java b/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java index 26cb3b44afe..efdb27663ad 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/internal/HtmlDependencyParser.java @@ -100,10 +100,11 @@ private void parseDependencies(String path, Set dependencies) { getLogger().info( "Can't find resource '%s' via the servlet context", path); + } else { + parseHtmlImports(content, path) + .map(uri -> resolveUri(uri, path)) + .forEach(uri -> parseDependencies(uri, dependencies)); } - - parseHtmlImports(content, path).map(uri -> resolveUri(uri, path)) - .forEach(uri -> parseDependencies(uri, dependencies)); } catch (IOException exception) { // ignore exception on close() getLogger().debug("Couldn't close template input stream", @@ -112,6 +113,9 @@ private void parseDependencies(String path, Set dependencies) { } private String resolveUri(String relative, String base) { + if (relative.startsWith("/")) { + return relative; + } try { URI uri = new URI(base); return uri.resolve(relative).toString(); diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java new file mode 100644 index 00000000000..e342387df8e --- /dev/null +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2017 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.uitest.ui.template; + +import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.dependency.HtmlImport; +import com.vaadin.flow.component.polymertemplate.PolymerTemplate; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.templatemodel.TemplateModel; +import com.vaadin.flow.theme.AbstractTheme; +import com.vaadin.flow.theme.Theme; +import com.vaadin.flow.uitest.ui.template.ThemedTemplateView.CustomTheme; + +@Tag("themed-template") +@HtmlImport("frontend://com/vaadin/flow/uitest/ui/template/ThemedTemplate.html") +@Route(value = "com.vaadin.flow.uitest.ui.template.ThemedTemplateView") +@Theme(CustomTheme.class) +public class ThemedTemplateView extends PolymerTemplate { + + public static class CustomTheme implements AbstractTheme { + + @Override + public String getBaseUrl() { + return ThemedTemplateView.class.getPackage().getName().replace('.', + '/'); + } + + @Override + public String getThemeUrl() { + return getBaseUrl() + "/custom-theme"; + } + + } +} diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/absolute.html b/flow-tests/test-root-context/src/main/webapp/frontend/absolute.html new file mode 100644 index 00000000000..534eb5d56c9 --- /dev/null +++ b/flow-tests/test-root-context/src/main/webapp/frontend/absolute.html @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/ThemedTemplate.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/ThemedTemplate.html new file mode 100644 index 00000000000..d02a9f71150 --- /dev/null +++ b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/ThemedTemplate.html @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html new file mode 100644 index 00000000000..d49bc06fb1f --- /dev/null +++ b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/relative1.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/relative1.html new file mode 100644 index 00000000000..917e4100e5f --- /dev/null +++ b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/relative1.html @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html new file mode 100644 index 00000000000..915cd9c682a --- /dev/null +++ b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html @@ -0,0 +1,32 @@ + + + + + + + + + From 9b2eaca14a824875ff1b93de2f812468681fae15 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 15 Feb 2018 17:46:23 +0300 Subject: [PATCH 03/10] Unit test for HtmlDependencyParser --- .../internal/HtmlDependencyParserTest.java | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 flow-server/src/test/java/com/vaadin/flow/component/internal/HtmlDependencyParserTest.java diff --git a/flow-server/src/test/java/com/vaadin/flow/component/internal/HtmlDependencyParserTest.java b/flow-server/src/test/java/com/vaadin/flow/component/internal/HtmlDependencyParserTest.java new file mode 100644 index 00000000000..cad609c5306 --- /dev/null +++ b/flow-server/src/test/java/com/vaadin/flow/component/internal/HtmlDependencyParserTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2017 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.component.internal; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collection; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.flow.internal.CurrentInstance; +import com.vaadin.flow.server.VaadinRequest; +import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.VaadinUriResolverFactory; +import com.vaadin.flow.server.WrappedHttpSession; + +import net.jcip.annotations.NotThreadSafe; + +@NotThreadSafe +public class HtmlDependencyParserTest { + + private VaadinRequest request; + private VaadinSession session; + private WrappedHttpSession wrappedSession; + private ServletContext context; + private VaadinUriResolverFactory factory; + + @Before + public void setUp() { + request = Mockito.mock(VaadinRequest.class); + CurrentInstance.set(VaadinRequest.class, request); + session = Mockito.mock(VaadinSession.class); + CurrentInstance.set(VaadinSession.class, session); + + wrappedSession = Mockito.mock(WrappedHttpSession.class); + context = Mockito.mock(ServletContext.class); + factory = Mockito.mock(VaadinUriResolverFactory.class); + + Mockito.when(session.getAttribute(VaadinUriResolverFactory.class)) + .thenReturn(factory); + + HttpSession httpSesson = Mockito.mock(HttpSession.class); + + Mockito.when(httpSesson.getServletContext()).thenReturn(context); + + Mockito.when(request.getWrappedSession()).thenReturn(wrappedSession); + Mockito.when(wrappedSession.getHttpSession()).thenReturn(httpSesson); + } + + @After + public void tearDown() { + CurrentInstance.clearAll(); + } + + @Test + public void mainImportDoesntHaveContentToParse_mainInportIsReturnedAndNoExceptions() { + String root = "foo.html"; + HtmlDependencyParser parser = new HtmlDependencyParser(root); + Collection dependencies = parser.parseDependencies(); + Assert.assertTrue("Dependencies parser doesn't return the root URI", + dependencies.contains(root)); + } + + @Test + public void oneLevelDependency_variousURIs_URIsAreCollectedCorrectly() { + String root = "baz/foo.html"; + HtmlDependencyParser parser = new HtmlDependencyParser(root); + + String resolvedRoot = "baz/bar/" + root; + Mockito.when(factory.toServletContextPath(request, root)) + .thenReturn(resolvedRoot); + + String importContent = "" + + "" + + "" + + ""; + InputStream stream = new ByteArrayInputStream( + importContent.getBytes(StandardCharsets.UTF_8)); + Mockito.when(context.getResourceAsStream(resolvedRoot)) + .thenReturn(stream); + + Collection dependencies = parser.parseDependencies(); + + Assert.assertEquals(5, dependencies.size()); + + Assert.assertTrue("Dependencies parser doesn't return the root URI", + dependencies.contains(root)); + Assert.assertTrue( + "Dependencies parser doesn't return the simple relative URI (same parent)", + dependencies.contains("baz/relative1.html")); + Assert.assertTrue( + "Dependencies parser doesn't return the realtive URI which is located in the parent folder", + dependencies.contains("relative2.html")); + Assert.assertTrue( + "Dependencies parser doesn't return the realtive URI which is located sub folder", + dependencies.contains("baz/sub/relative3.html")); + Assert.assertTrue("Dependencies parser doesn't return the absolute URI", + dependencies.contains("/absolute.html")); + } + + @Test + public void nestedDependencyLevels_variousURIs_URIsAreCollectedCorrectly() { + String root = "foo.html"; + HtmlDependencyParser parser = new HtmlDependencyParser(root); + + String resolvedRoot = "baz/bar/" + root; + Mockito.when(factory.toServletContextPath(request, root)) + .thenReturn(resolvedRoot); + + String importContent = ""; + InputStream stream = new ByteArrayInputStream( + importContent.getBytes(StandardCharsets.UTF_8)); + Mockito.when(context.getResourceAsStream(resolvedRoot)) + .thenReturn(stream); + + String resolvedRelative = "baz/bar/relative.html"; + Mockito.when(factory.toServletContextPath(request, "relative.html")) + .thenReturn(resolvedRelative); + + InputStream relativeContent = new ByteArrayInputStream( + "" + .getBytes(StandardCharsets.UTF_8)); + Mockito.when(context.getResourceAsStream(resolvedRelative)) + .thenReturn(relativeContent); + + Collection dependencies = parser.parseDependencies(); + + Assert.assertEquals(3, dependencies.size()); + + Assert.assertTrue("Dependencies parser doesn't return the root URI", + dependencies.contains(root)); + Assert.assertTrue( + "Dependencies parser doesn't return the simple relative URI (same parent)", + dependencies.contains("relative.html")); + Assert.assertTrue( + "Dependencies parser doesn't return the realtive URI which is located in the parent folder", + dependencies.contains("relative1.html")); + } + +} From 5d4de31a26857fba7608ed7d9f204d94f9c97510 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 16 Feb 2018 09:49:42 +0300 Subject: [PATCH 04/10] Update UI code for an IT test and make the IT test --- .../ui/template/ThemedTemplateView.java | 6 +- .../{template => custom-theme}/relative2.html | 0 .../template}/ThemedTemplate.html | 9 +- .../template}/relative1.html | 0 .../uitest/ui/template/ThemedTemplate.html | 3 + .../uitest/ui/template/ThemedTemplateIT.java | 92 +++++++++++++++++++ 6 files changed, 102 insertions(+), 8 deletions(-) rename flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/{template => custom-theme}/relative2.html (100%) rename flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/{template/custom-theme => custom-theme/template}/ThemedTemplate.html (81%) rename flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/{template/custom-theme => custom-theme/template}/relative1.html (100%) create mode 100644 flow-tests/test-root-context/src/test/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateIT.java diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java index e342387df8e..92481b4cf57 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/uitest/ui/template/ThemedTemplateView.java @@ -34,8 +34,10 @@ public static class CustomTheme implements AbstractTheme { @Override public String getBaseUrl() { - return ThemedTemplateView.class.getPackage().getName().replace('.', - '/'); + String pkg = ThemedTemplateView.class.getPackage().getName(); + int index = pkg.lastIndexOf('.'); + pkg = pkg.substring(0, index); + return "/" + pkg.replace('.', '/'); } @Override diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/custom-theme/relative2.html similarity index 100% rename from flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/relative2.html rename to flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/custom-theme/relative2.html diff --git a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/custom-theme/template/ThemedTemplate.html similarity index 81% rename from flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html rename to flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/custom-theme/template/ThemedTemplate.html index d49bc06fb1f..901e2e4b6ef 100644 --- a/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/template/custom-theme/ThemedTemplate.html +++ b/flow-tests/test-root-context/src/main/webapp/frontend/com/vaadin/flow/uitest/ui/custom-theme/template/ThemedTemplate.html @@ -15,16 +15,13 @@ --> - - -