diff --git a/flow-client/src/main/frontend/Flow.ts b/flow-client/src/main/frontend/Flow.ts index 04488e5fea1..1f94209e395 100644 --- a/flow-client/src/main/frontend/Flow.ts +++ b/flow-client/src/main/frontend/Flow.ts @@ -244,8 +244,6 @@ export class Flow { // Call server side to navigate to the given route flowRoot.$server.connectClient( - this.container.localName, - this.container.id, this.getFlowRoutePath(ctx), this.getFlowRouteQuery(ctx), this.appShellTitle, @@ -296,15 +294,20 @@ export class Flow { await this.config.imports(); } - // Load flow-client module - const clientMod = await import('./FlowClient'); - await this.flowInitClient(clientMod); - // we use a custom tag for the flow app container const tag = `flow-container-${appId.toLowerCase()}`; - this.container = document.createElement(tag); + const serverCreatedContainer = document.querySelector(tag); + if (serverCreatedContainer) { + this.container = serverCreatedContainer as HTMLElement; + } else { + this.container = document.createElement(tag); + this.container.id = appId; + } flowRoot.$[appId] = this.container; - this.container.id = appId; + + // Load flow-client module + const clientMod = await import('./FlowClient'); + await this.flowInitClient(clientMod); // hide flow progress indicator this.loadingFinished(); diff --git a/flow-client/src/test/frontend/FlowTests.ts b/flow-client/src/test/frontend/FlowTests.ts index 3b78b1d13ff..5eb60bcb808 100644 --- a/flow-client/src/test/frontend/FlowTests.ts +++ b/flow-client/src/test/frontend/FlowTests.ts @@ -114,6 +114,9 @@ describe('Flow', () => { if (indicator) { indicator.remove(); } + Array.from(document.body.children) + .filter((e) => e.tagName.toLowerCase().startsWith('flow-container')) + .forEach((e) => e.remove()); $wnd.addEventListener = (type, listener) => { listeners.push({ type: type, listener: listener }); @@ -704,18 +707,13 @@ function stubServerRemoteFunction( flowRoot.$server = { timers: [], - connectClient: (localName: string, elemId: string, route: string) => { - expect(localName).not.to.be.undefined; - expect(elemId).not.to.be.undefined; + connectClient: (route: string) => { expect(route).not.to.be.undefined; if (routeRegex) { expect(route).to.match(routeRegex); } - expect(elemId).to.equal(id); - expect(localName).to.equal(`flow-container-${elemId.toLowerCase()}`); - - container = flowRoot.$[elemId]; + container = flowRoot.$[id]; expect(container).not.to.be.undefined; expect(container.serverConnected).not.to.be.undefined; diff --git a/flow-server/src/main/java/com/vaadin/flow/component/UI.java b/flow-server/src/main/java/com/vaadin/flow/component/UI.java index 1028b8796c2..61845835cbc 100644 --- a/flow-server/src/main/java/com/vaadin/flow/component/UI.java +++ b/flow-server/src/main/java/com/vaadin/flow/component/UI.java @@ -117,9 +117,6 @@ public class UI extends Component private static final String NULL_LISTENER = "Listener can not be 'null'"; - private static final Pattern APP_ID_REPLACE_PATTERN = Pattern - .compile("-\\d+$"); - /** * The id of this UI, used to find the server side instance of the UI form * which a request originates. A negative value indicates that the UI id has @@ -262,8 +259,15 @@ public void doInit(VaadinRequest request, int uiId, String appId) { } this.uiId = uiId; - appId = APP_ID_REPLACE_PATTERN.matcher(appId).replaceAll(""); - getInternals().setAppId(appId); + getInternals().setFullAppId(appId); + + // Create flow reference for the client outlet element + wrapperElement = new Element(getInternals().getContainerTag()); + + // Connect server with client + getElement().getStateProvider().appendVirtualChild( + getElement().getNode(), wrapperElement, + NodeProperties.INJECT_BY_ID, appId); // Add any dependencies from the UI class getInternals().addComponentDependencies(getClass()); @@ -1637,6 +1641,8 @@ public Stream getChildren() { private String forwardToClientUrl = null; + private boolean firstNavigation = true; + /** * Gets the new forward url. * @@ -1650,10 +1656,6 @@ public String getForwardToClientUrl() { * Connect a client with the server side UI. This method is invoked each * time client router navigates to a server route. * - * @param clientElementTag - * client side element tag - * @param clientElementId - * client side element id * @param flowRoutePath * flow route path that should be attached to the client element * @param flowRouteQuery @@ -1667,9 +1669,8 @@ public String getForwardToClientUrl() { */ @ClientCallable @AllowInert - public void connectClient(String clientElementTag, String clientElementId, - String flowRoutePath, String flowRouteQuery, String appShellTitle, - JsonValue historyState, String trigger) { + public void connectClient(String flowRoutePath, String flowRouteQuery, + String appShellTitle, JsonValue historyState, String trigger) { if (appShellTitle != null && !appShellTitle.isEmpty()) { getInternals().setAppShellTitle(appShellTitle); @@ -1692,21 +1693,16 @@ public void connectClient(String clientElementTag, String clientElementId, } else { navigationTrigger = NavigationTrigger.HISTORY; } - if (wrapperElement == null) { - // Create flow reference for the client outlet element - wrapperElement = new Element(clientElementTag); - - // Connect server with client - getElement().getStateProvider().appendVirtualChild( - getElement().getNode(), wrapperElement, - NodeProperties.INJECT_BY_ID, clientElementId); - + if (firstNavigation) { + firstNavigation = false; getPage().getHistory().setHistoryStateChangeHandler( event -> renderViewForRoute(event.getLocation(), event.getTrigger())); - // Render the flow view that the user wants to navigate to. - renderViewForRoute(location, navigationTrigger); + if (getInternals().getActiveRouterTargetsChain().isEmpty()) { + // Render the route unless it was rendered eagerly + renderViewForRoute(location, navigationTrigger); + } } else { History.HistoryStateChangeHandler handler = getPage().getHistory() .getHistoryStateChangeHandler(); 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 5c64f776c05..d9fd0525910 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 @@ -24,13 +24,18 @@ import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.HasElement; @@ -75,9 +80,6 @@ import com.vaadin.flow.shared.Registration; import com.vaadin.flow.shared.communication.PushMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Holds UI-specific methods and data which are intended for internal use by the * framework. @@ -90,6 +92,9 @@ */ public class UIInternals implements Serializable { + private static final Pattern APP_ID_REPLACE_PATTERN = Pattern + .compile("-\\d+$"); + /** * A {@link Page#executeJs(String, Serializable...)} invocation that has not * yet been sent to the client. @@ -200,6 +205,8 @@ public List getParameters() { private String appId; + private String fullAppId; + private Component activeDragSourceComponent; private ExtendedClientDetails extendedClientDetails = null; @@ -983,11 +990,13 @@ public void setContinueNavigationAction( * Sets the application id tied with this UI. Different applications in the * same page have different unique ids. * - * @param appId - * the id of the application tied with this UI + * @param fullAppId + * the (full, not stripped) id of the application tied with this + * UI */ - public void setAppId(String appId) { - this.appId = appId; + public void setFullAppId(String fullAppId) { + this.fullAppId = fullAppId; + this.appId = APP_ID_REPLACE_PATTERN.matcher(fullAppId).replaceAll(""); } /** @@ -1000,6 +1009,17 @@ public String getAppId() { return appId; } + /** + * Gets the full app id, which funnily enough is not the same as appId. This + * really should be removed but not right now. Don't use this method, it + * will be gone. + * + * @return the full app id + */ + public String getFullAppId() { + return fullAppId; + } + /** * Gets the router used for navigating in this UI, if the router was active * when this UI was initialized. @@ -1215,4 +1235,9 @@ private void removeChildrenContentFromRouterLayout( oldContent = oldChildren.get(oldContent); } } + + public String getContainerTag() { + return "flow-container-" + getFullAppId().toLowerCase(Locale.ENGLISH); + + } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandler.java b/flow-server/src/main/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandler.java index b501f9c12dc..bea3cf9c0f4 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandler.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandler.java @@ -99,9 +99,18 @@ public boolean synchronizedHandleRequest(VaadinSession session, if (service.getBootstrapInitialPredicate() .includeInitialUidl(request)) { includeInitialUidl(initialJson, session, request, response); - + UI ui = UI.getCurrent(); + var flowContainerElement = new Element( + ui.getInternals().getContainerTag()); + flowContainerElement.attr("id", ui.getInternals().getAppId()); + Elements outlet = indexDocument.body().select("#outlet"); + if (!outlet.isEmpty()) { + outlet.first().appendChild(flowContainerElement); + } else { + indexDocument.body().appendChild(flowContainerElement); + } indexHtmlResponse = new IndexHtmlResponse(request, response, - indexDocument, UI.getCurrent()); + indexDocument, ui); } else { indexHtmlResponse = new IndexHtmlResponse(request, response, indexDocument); diff --git a/flow-server/src/test/java/com/vaadin/flow/component/internal/JavaScriptBootstrapUITest.java b/flow-server/src/test/java/com/vaadin/flow/component/internal/JavaScriptBootstrapUITest.java index b9451651f52..60e610df9cf 100644 --- a/flow-server/src/test/java/com/vaadin/flow/component/internal/JavaScriptBootstrapUITest.java +++ b/flow-server/src/test/java/com/vaadin/flow/component/internal/JavaScriptBootstrapUITest.java @@ -1,5 +1,10 @@ package com.vaadin.flow.component.internal; +import static com.vaadin.flow.component.UI.CLIENT_NAVIGATE_TO; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import java.io.Serializable; import java.util.Collections; import java.util.Optional; @@ -28,24 +33,16 @@ import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeLeaveEvent; import com.vaadin.flow.router.BeforeLeaveObserver; -import com.vaadin.flow.router.InternalServerError; import com.vaadin.flow.router.Location; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.QueryParameters; import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Router; import com.vaadin.flow.router.RouterLink; -import com.vaadin.flow.server.InvalidRouteConfigurationException; import com.vaadin.flow.server.MockServletServiceSessionSetup; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinSession; -import static com.vaadin.flow.component.UI.CLIENT_NAVIGATE_TO; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - public class JavaScriptBootstrapUITest { private static final String CLIENT_PUSHSTATE_TO = "setTimeout(() => window.history.pushState($0, '', $1))"; @@ -192,6 +189,7 @@ public void setup() throws Exception { Collections.emptyList()); ui = new UI(); ui.getInternals().setSession(mocks.getSession()); + ui.doInit(null, 0, "appIdABC"); CurrentInstance.setCurrent(ui); } @@ -203,13 +201,13 @@ public void cleanup() { @Test public void should_allow_navigation() { - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); assertEquals(Tag.HEADER, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H2, ui.wrapperElement.getChild(0).getChild(0).getTag()); // Dirty view is allowed after clean view - ui.connectClient("foo", "bar", "/dirty", "", "", null, ""); + ui.connectClient("/dirty", "", "", null, ""); assertEquals(Tag.SPAN, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H1, ui.wrapperElement.getChild(0).getChild(0).getTag()); @@ -217,7 +215,7 @@ public void should_allow_navigation() { @Test public void should_navigate_when_endingSlash() { - ui.connectClient("foo", "bar", "/clean/", "", "", null, ""); + ui.connectClient("/clean/", "", "", null, ""); assertEquals(Tag.HEADER, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H2, ui.wrapperElement.getChild(0).getChild(0).getTag()); @@ -225,7 +223,7 @@ public void should_navigate_when_endingSlash() { @Test public void getChildren_should_notReturnAnEmptyList() { - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); assertEquals(1, ui.getChildren().count()); } @@ -233,7 +231,7 @@ public void getChildren_should_notReturnAnEmptyList() { public void addRemoveComponent_clientSideRouting_addsToBody() { final Element uiElement = ui.getElement(); - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); // router outlet is a virtual child that is not reflected on element // level assertEquals(1, ui.getChildren().count()); @@ -264,7 +262,7 @@ public void addRemoveComponent_clientSideRouting_addsToBody() { public void addComponent_clientSideRouterAndNavigation_componentsRemain() { final Element uiElement = ui.getElement(); // trigger route via client - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); final RouterLink routerLink = new RouterLink(); ui.add(routerLink); @@ -281,25 +279,25 @@ public void addComponent_clientSideRouterAndNavigation_componentsRemain() { @Test public void should_prevent_navigation_on_dirty() { - ui.connectClient("foo", "bar", "/dirty", "", "", null, ""); + ui.connectClient("/dirty", "", "", null, ""); assertEquals(Tag.SPAN, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H1, ui.wrapperElement.getChild(0).getChild(0).getTag()); // clean view cannot be rendered after dirty - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); assertEquals(Tag.H1, ui.wrapperElement.getChild(0).getChild(0).getTag()); // an error route cannot be rendered after dirty - ui.connectClient("foo", "bar", "/errr", "", "", null, ""); + ui.connectClient("/errr", "", "", null, ""); assertEquals(Tag.H1, ui.wrapperElement.getChild(0).getChild(0).getTag()); } @Test public void should_remove_content_on_leaveNavigation() { - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); assertEquals(Tag.HEADER, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H2, ui.wrapperElement.getChild(0).getChild(0).getTag()); @@ -311,7 +309,7 @@ public void should_remove_content_on_leaveNavigation() { @Test public void should_keep_content_on_leaveNavigation_postpone() { - ui.connectClient("foo", "bar", "/dirty", "", "", null, ""); + ui.connectClient("/dirty", "", "", null, ""); assertEquals(Tag.SPAN, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H1, ui.wrapperElement.getChild(0).getChild(0).getTag()); @@ -324,32 +322,31 @@ public void should_keep_content_on_leaveNavigation_postpone() { @Test public void should_handle_forward_to_client_side_view_on_beforeEnter() { - ui.connectClient("foo", "bar", "/forwardToClientSideViewOnBeforeEnter", - "", "", null, ""); + ui.connectClient("/forwardToClientSideViewOnBeforeEnter", "", "", null, + ""); assertEquals("client-view", ui.getForwardToClientUrl()); } @Test public void should_not_handle_forward_to_client_side_view_on_beforeLeave() { - ui.connectClient("foo", "bar", "/forwardToClientSideViewOnBeforeLeave", - "", "", null, ""); + ui.connectClient("/forwardToClientSideViewOnBeforeLeave", "", "", null, + ""); assertNull(ui.getForwardToClientUrl()); } @Test public void should_not_handle_forward_to_client_side_view_on_reroute() { - ui.connectClient("foo", "bar", "/forwardToClientSideViewOnReroute", "", - "", null, ""); + ui.connectClient("/forwardToClientSideViewOnReroute", "", "", null, ""); assertNull(ui.getForwardToClientUrl()); } @Test public void should_handle_forward_to_server_side_view_on_beforeEnter_and_update_url() { - ui.connectClient("foo", "bar", "/forwardToServerSideViewOnBeforeEnter", - "", "", null, ""); + ui.connectClient("/forwardToServerSideViewOnBeforeEnter", "", "", null, + ""); assertEquals(Tag.HEADER, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H2, @@ -368,20 +365,11 @@ public void should_handle_forward_to_server_side_view_on_beforeEnter_and_update_ @Test public void should_show_error_page() { - ui.connectClient("foo", "bar", "/err", "", "", null, ""); + ui.connectClient("/err", "", "", null, ""); assertEquals(Tag.DIV, ui.wrapperElement.getChild(0).getTag()); assertTrue(ui.wrapperElement.toString().contains("Available routes:")); } - @Test - public void should_initializeUI_when_wrapperElement_null() { - Location location = new Location("foo"); - ui.getInternals().getRouter().initializeUI(ui, location); - assertNull(ui.wrapperElement); - // attached to body - assertTrue(ui.getElement().toString().contains("Available routes:")); - } - @Test public void should_invoke_clientRoute_when_navigationHasNotBeenStarted() { ui = Mockito.spy(ui); @@ -450,7 +438,7 @@ public void should_not_notify_clientRoute_when_navigatingToTheSame() { @Test public void server_should_not_doClientRoute_when_navigatingToServer() { - ui.connectClient("foo", "bar", "/clean", "", "", null, ""); + ui.connectClient("/clean", "", "", null, ""); assertEquals(Tag.HEADER, ui.wrapperElement.getChild(0).getTag()); assertEquals(Tag.H2, ui.wrapperElement.getChild(0).getChild(0).getTag()); @@ -494,25 +482,23 @@ public void should_removeTitle_when_noAppShellTitle() { @Test public void should_restoreIndexHtmlTitle() { - ui.connectClient("foo", "bar", "empty", "", "app-shell-title", null, - ""); + ui.connectClient("empty", "", "app-shell-title", null, ""); assertEquals("", ui.getInternals().getTitle()); - ui.connectClient("foo", "bar", "dirty", "", "app-shell-title", null, - ""); + ui.connectClient("dirty", "", "app-shell-title", null, ""); assertEquals("app-shell-title", ui.getInternals().getTitle()); } @Test public void should_not_share_dynamic_app_title_for_different_UIs() { String dynamicTitle = UUID.randomUUID().toString(); - ui.connectClient("foo", "bar", "clean", "", dynamicTitle, null, ""); + ui.connectClient("clean", "", dynamicTitle, null, ""); assertEquals(dynamicTitle, ui.getInternals().getTitle()); String anotherDynamicTitle = UUID.randomUUID().toString(); UI anotherUI = new UI(); anotherUI.getInternals().setSession(mocks.getSession()); - anotherUI.connectClient("foo", "bar", "clean", "", anotherDynamicTitle, - null, ""); + anotherUI.doInit(null, 0, "anotherUiId"); + anotherUI.connectClient("clean", "", anotherDynamicTitle, null, ""); assertEquals(anotherDynamicTitle, anotherUI.getInternals().getTitle()); ui.navigate("dirty"); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/JavaScriptBootstrapHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/JavaScriptBootstrapHandlerTest.java index 9862a70e77a..91507c1d8ec 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/JavaScriptBootstrapHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/JavaScriptBootstrapHandlerTest.java @@ -139,7 +139,7 @@ public void should_attachViewTo_UiContainer() throws Exception { jsInitHandler.handleRequest(session, request, response); UI ui = UI.getCurrent(); - ui.connectClient("a-tag", "an-id", "a-route", "", "", null, ""); + ui.connectClient("a-route", "", "", null, ""); TestNodeVisitor visitor = new TestNodeVisitor(true); BasicElementStateProvider.get().visit(ui.getElement().getNode(), @@ -147,7 +147,7 @@ public void should_attachViewTo_UiContainer() throws Exception { Assert.assertTrue( hasNodeTag(visitor, "^.*", ElementType.REGULAR)); - Assert.assertTrue(hasNodeTag(visitor, "^.*", + Assert.assertTrue(hasNodeTag(visitor, "^.*", ElementType.VIRTUAL_ATTACHED)); Assert.assertTrue(hasNodeTag(visitor, "^
.*", ElementType.REGULAR)); Assert.assertTrue( diff --git a/flow-tests/test-eager-bootstrap/src/main/java/com/vaadin/flow/eagerbootstrap/ParameterView.java b/flow-tests/test-eager-bootstrap/src/main/java/com/vaadin/flow/eagerbootstrap/ParameterView.java new file mode 100644 index 00000000000..332d20de653 --- /dev/null +++ b/flow-tests/test-eager-bootstrap/src/main/java/com/vaadin/flow/eagerbootstrap/ParameterView.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2023 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.BeforeEvent; +import com.vaadin.flow.router.HasUrlParameter; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.router.RouterLink; + +@Route("parameter") +public class ParameterView extends Div implements HasUrlParameter { + + private Div parameters; + + public ParameterView() { + setId("view"); + + RouterLink fooLink = new RouterLink("Navigate with parameter 'foo'", + ParameterView.class, "foo"); + fooLink.setId("fooLink"); + add(fooLink); + add(new Div()); + RouterLink barLink = new RouterLink("Navigate with parameter 'bar'", + ParameterView.class, "bar"); + barLink.setId("barLink"); + add(barLink); + + parameters = new Div(); + parameters.setId("parameters"); + parameters.getStyle() + .setWhiteSpace(com.vaadin.flow.dom.Style.WhiteSpace.PRE); + add(parameters); + + } + + @Override + public void setParameter(BeforeEvent event, String parameter) { + parameters.setText(parameters.getText() + "\n" + + "setParameter called with: " + parameter); + } +} diff --git a/flow-tests/test-eager-bootstrap/src/test/java/com/vaadin/flow/eagerbootstrap/ParameterIT.java b/flow-tests/test-eager-bootstrap/src/test/java/com/vaadin/flow/eagerbootstrap/ParameterIT.java new file mode 100644 index 00000000000..1509271d464 --- /dev/null +++ b/flow-tests/test-eager-bootstrap/src/test/java/com/vaadin/flow/eagerbootstrap/ParameterIT.java @@ -0,0 +1,41 @@ +package com.vaadin.flow.eagerbootstrap; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.flow.testutil.ChromeBrowserTest; + +public class ParameterIT extends ChromeBrowserTest { + + @Override + protected String getTestPath() { + return "/parameter"; + } + + private void openWithParameter(String parameter) { + String url = getTestURL(); + getDriver().get(url + "/" + parameter); + } + + @Test + public void setParameterCalledAsExpected() { + openWithParameter("foo"); + Assert.assertEquals("setParameter called with: foo", + getParametersText()); + $("*").id("barLink").click(); + Assert.assertEquals( + "setParameter called with: foo\nsetParameter called with: bar", + getParametersText()); + } + + private String getParametersText() { + return $("*").id("parameters").getText(); + } + + private int getInstance() { + String instanceText = $("*").id("instance").getText(); + return Integer + .parseInt(instanceText.replace("This is view instance ", "")); + } + +} diff --git a/vaadin-spring/src/test/java/com/vaadin/flow/spring/scopes/AbstractUIScopedTest.java b/vaadin-spring/src/test/java/com/vaadin/flow/spring/scopes/AbstractUIScopedTest.java index b67cf8ac883..3a4502da2ec 100644 --- a/vaadin-spring/src/test/java/com/vaadin/flow/spring/scopes/AbstractUIScopedTest.java +++ b/vaadin-spring/src/test/java/com/vaadin/flow/spring/scopes/AbstractUIScopedTest.java @@ -68,7 +68,7 @@ protected UI mockUI() { Mockito.when(appConfig.getPropertyNames()) .thenReturn(Collections.emptyEnumeration()); when(service.getMainDivId(Mockito.any(), Mockito.any())) - .thenReturn(" - "); + .thenReturn("abc"); final Map attributeMap = new HashMap<>();