diff options
author | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-09-27 11:40:17 +0300 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-09-27 11:40:17 +0300 |
commit | 367c7751a6ff9234fd47bc5a48e6ef9a4117a7a2 (patch) | |
tree | 5b3849bafb37b49c3dcc8616e064f60bd081dff0 /server | |
parent | 69776b1d08d40bcdd89b9cc5b050e8db793ec06b (diff) | |
download | vaadin-framework-367c7751a6ff9234fd47bc5a48e6ef9a4117a7a2.tar.gz vaadin-framework-367c7751a6ff9234fd47bc5a48e6ef9a4117a7a2.zip |
Add option to use PushState instead of URI fragments in Navigator (#10042)
* Navigator now by default uses pushState and normal URLs
* added documentation for pushState and updated Navigator documentation
* improving docs etc, adding one TODO to be solved before merging
* pushState/replaceState no work better with changing titles
* Making uri fragment navigator work when not using specially mapped UI
* Revert to older default, add annotation for selecting
* Fix tests, add null checks
* Reorder if-clause, fix tests
* Revert unnecessary test change
* Use correct variable in UI, fix test clean up
* Updates to JavaDocs, fix some methods and tests
* Add comments, fix test ui, TODO for fallbacks
* Navigation documentation, JavaDocs, removed TODOs
* Documentation fixes
* Improve JavaDocs
* Fix link name in documentation
* Improve throws declaration in getLocation
* Change documentation about the PushState based navigation
* Add since tags
* Add since tags for UI
Diffstat (limited to 'server')
9 files changed, 409 insertions, 20 deletions
diff --git a/server/src/main/java/com/vaadin/navigator/Navigator.java b/server/src/main/java/com/vaadin/navigator/Navigator.java index 6b18cd4000..d65bad9db7 100644 --- a/server/src/main/java/com/vaadin/navigator/Navigator.java +++ b/server/src/main/java/com/vaadin/navigator/Navigator.java @@ -16,6 +16,7 @@ package com.vaadin.navigator; import java.io.Serializable; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -27,6 +28,7 @@ import java.util.Objects; import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; import com.vaadin.server.Page; +import com.vaadin.server.Page.PopStateEvent; import com.vaadin.shared.Registration; import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.Component; @@ -82,6 +84,95 @@ public class Navigator implements Serializable { } /** + * A {@link NavigationStateManager} using path info, HTML5 push state and + * {@link PopStateEvent}s to track views and enable listening to view + * changes. This manager can be enabled with UI annotation + * {@link PushStateNavigation}. + * <p> + * The part of path after UI's "root path" (UI's path without view + * identifier) is used as {@link View}s identifier. The rest of the path + * after the view name can be used by the developer for extra parameters for + * the View. + * <p> + * This class is mostly for internal use by Navigator, and is only public + * and static to enable testing. + * + * @since 8.2 + */ + public static class PushStateManager implements NavigationStateManager { + private Registration popStateListenerRegistration; + private UI ui; + + /** + * Creates a new PushStateManager. + * + * @param ui + * the UI where the Navigator is attached to + */ + public PushStateManager(UI ui) { + this.ui = ui; + } + + @Override + public void setNavigator(Navigator navigator) { + if (popStateListenerRegistration != null) { + popStateListenerRegistration.remove(); + popStateListenerRegistration = null; + } + if (navigator != null) { + popStateListenerRegistration = ui.getPage() + .addPopStateListener(e -> { + navigator.navigateTo(getState()); + }); + } + } + + @Override + public String getState() { + // Get the current URL + URI location = ui.getPage().getLocation(); + String path = location.getPath(); + if (ui.getUiPathInfo() != null + && path.contains(ui.getUiPathInfo())) { + // Split the path from after the UI PathInfo + path = path.substring(path.indexOf(ui.getUiPathInfo()) + + ui.getUiPathInfo().length()); + } else if (path.startsWith(ui.getUiRootPath())) { + // Use the whole path after UI RootPath + String uiRootPath = ui.getUiRootPath(); + path = path.substring(uiRootPath.length()); + } else { + throw new IllegalStateException(getClass().getSimpleName() + + " is unable to determine the view path from the URL."); + } + + if (path.startsWith("/")) { + // Strip leading '/' + path = path.substring(1); + } + return path; + } + + @Override + public void setState(String state) { + StringBuilder sb = new StringBuilder(ui.getUiRootPath()); + if (!ui.getUiRootPath().endsWith("/")) { + // make sure there is a '/' between the root path and the + // navigation state. + sb.append("/"); + } + sb.append(state); + URI location = ui.getPage().getLocation(); + if (location != null) { + ui.getPage().pushState(location.resolve(sb.toString())); + } else { + throw new IllegalStateException( + "The Page of the UI does not have a location."); + } + } + } + + /** * A {@link NavigationStateManager} using hashbang fragments in the Page * location URI to track views and enable listening to view changes. * <p> @@ -92,6 +183,10 @@ public class Navigator implements Serializable { * <p> * This class is mostly for internal use by Navigator, and is only public * and static to enable testing. + * <p> + * <strong>Note:</strong> Since 8.2 you can use {@link PushStateManager}, + * which is based on HTML5 History API. To use it, add + * {@link PushStateNavigation} annotation to the UI. */ public static class UriFragmentManager implements NavigationStateManager { private final Page page; @@ -426,7 +521,7 @@ public class Navigator implements Serializable { * The ViewDisplay used to display the views. */ public Navigator(UI ui, ViewDisplay display) { - this(ui, new UriFragmentManager(ui.getPage()), display); + this(ui, null, display); } /** @@ -494,7 +589,7 @@ public class Navigator implements Serializable { this.ui = ui; this.ui.setNavigator(this); if (stateManager == null) { - stateManager = new UriFragmentManager(ui.getPage()); + stateManager = createNavigationStateManager(ui); } if (stateManager != null && this.stateManager != null && stateManager != this.stateManager) { @@ -506,6 +601,24 @@ public class Navigator implements Serializable { } /** + * Creates a navigation state manager for given UI. This method should take + * into account any navigation related annotations. + * + * @param ui + * the ui + * @return the navigation state manager + * + * @since 8.2 + */ + protected NavigationStateManager createNavigationStateManager(UI ui) { + if (ui.getClass().getAnnotation(PushStateNavigation.class) != null) { + return new PushStateManager(ui); + } + // Fall back to old default + return new UriFragmentManager(ui.getPage()); + } + + /** * Navigates to a view and initialize the view with given parameters. * <p> * The view string consists of a view name optionally followed by a slash diff --git a/server/src/main/java/com/vaadin/navigator/PushStateNavigation.java b/server/src/main/java/com/vaadin/navigator/PushStateNavigation.java new file mode 100644 index 0000000000..f1cab0391b --- /dev/null +++ b/server/src/main/java/com/vaadin/navigator/PushStateNavigation.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2016 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.navigator; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.vaadin.server.DeploymentConfiguration; +import com.vaadin.server.Page.PopStateEvent; +import com.vaadin.ui.UI; + +/** + * Annotation for {@link UI}s to enable the PushState navigation mode when + * initializing a {@link Navigator} for it. PushState navigation is an + * alternative way to handle URLs in the {@link Navigator}. It uses path info, + * HTML5 push state and {@link PopStateEvent}s to track views and enable + * listening to view changes. + * <p> + * <strong>Note:</strong> For PushState navigation to work, the + * {@link DeploymentConfiguration} parameter + * {@link DeploymentConfiguration#isSendUrlsAsParameters() SendUrlAsParameters} + * must not be set to {@code false}. + * + * @since 8.2 + */ +@Retention(RUNTIME) +@Target(TYPE) +@Inherited +public @interface PushStateNavigation { +} diff --git a/server/src/main/java/com/vaadin/server/Page.java b/server/src/main/java/com/vaadin/server/Page.java index 4c880c2a6b..3e95de0c4b 100644 --- a/server/src/main/java/com/vaadin/server/Page.java +++ b/server/src/main/java/com/vaadin/server/Page.java @@ -1035,8 +1035,12 @@ public class Page implements Serializable { * deployed in due to potential proxies, redirections and similar. * * @return The browser location URI. + * @throws IllegalStateException + * if the + * {@link DeploymentConfiguration#isSendUrlsAsParameters()} is + * set to {@code false} */ - public URI getLocation() { + public URI getLocation() throws IllegalStateException { if (location == null && !uI.getSession().getConfiguration() .isSendUrlsAsParameters()) { throw new IllegalStateException("Location is not available as the " diff --git a/server/src/main/java/com/vaadin/ui/UI.java b/server/src/main/java/com/vaadin/ui/UI.java index ac4815f92d..5d27c1de74 100644 --- a/server/src/main/java/com/vaadin/ui/UI.java +++ b/server/src/main/java/com/vaadin/ui/UI.java @@ -44,6 +44,7 @@ import com.vaadin.event.UIEvents.PollEvent; import com.vaadin.event.UIEvents.PollListener; import com.vaadin.event.UIEvents.PollNotifier; import com.vaadin.navigator.Navigator; +import com.vaadin.navigator.PushStateNavigation; import com.vaadin.server.ClientConnector; import com.vaadin.server.ComponentSizeValidator; import com.vaadin.server.ComponentSizeValidator.InvalidLayout; @@ -196,7 +197,6 @@ public abstract class UI extends AbstractSingleComponentContainer @Override public void popstate(String uri) { getPage().updateLocation(uri, true, true); - } }; private DebugWindowServerRpc debugRpc = new DebugWindowServerRpc() { @@ -261,8 +261,7 @@ public abstract class UI extends AbstractSingleComponentContainer private WindowOrderRpc windowOrderRpc = new WindowOrderRpc() { @Override - public void windowOrderChanged( - Map<Integer, Connector> windowOrders) { + public void windowOrderChanged(Map<Integer, Connector> windowOrders) { Map<Integer, Window> orders = new LinkedHashMap<>(); for (Entry<Integer, Connector> entry : windowOrders.entrySet()) { if (entry.getValue() instanceof Window) { @@ -661,6 +660,10 @@ public abstract class UI extends AbstractSingleComponentContainer private String embedId; + private String uiPathInfo; + + private String uiRootPath; + private boolean mobileHtml5DndPolyfillLoaded; /** @@ -740,6 +743,36 @@ public abstract class UI extends AbstractSingleComponentContainer getPage().init(request); + String uiPathInfo = (String) request + .getAttribute(ApplicationConstants.UI_ROOT_PATH); + if (uiPathInfo != null) { + setUiPathInfo(uiPathInfo); + } + + if (getSession() != null && getSession().getConfiguration() != null + && getSession().getConfiguration().isSendUrlsAsParameters() + && getPage().getLocation() != null) { + // By default the root is the URL from client + String uiRootPath = getPage().getLocation().getPath(); + + if (uiPathInfo != null && uiRootPath.contains(uiPathInfo)) { + // String everything from the URL after uiPathInfo + // This will remove the navigation state from the URL + uiRootPath = uiRootPath.substring(0, + uiRootPath.indexOf(uiPathInfo) + uiPathInfo.length()); + } else if (request.getPathInfo() != null) { + // uiRootPath does not match the uiPathInfo + // This can happen for example when embedding a Vaadin UI + String pathInfo = request.getPathInfo(); + if (uiRootPath.endsWith(pathInfo)) { + uiRootPath = uiRootPath.substring(0, + uiRootPath.length() - pathInfo.length()); + } + } + // Store the URL as the UI Root Path + setUiRootPath(uiRootPath); + } + // Call the init overridden by the application developer init(request); @@ -750,6 +783,48 @@ public abstract class UI extends AbstractSingleComponentContainer } } + private void setUiRootPath(String uiRootPath) { + this.uiRootPath = uiRootPath; + } + + /** + * Gets the part of path (from browser's URL) that points to this UI. + * Basically the same as the value from {@link Page#getLocation()}, but + * without possible view identifiers or path parameters. + * + * @return the part of path (from browser's URL) that points to this UI, + * without possible view identifiers or path parameters + * + * @since 8.2 + */ + public String getUiRootPath() { + return uiRootPath; + } + + private void setUiPathInfo(String uiPathInfo) { + this.uiPathInfo = uiPathInfo; + } + + /** + * Gets the path info part of the request that is used to detect the UI. + * This is defined during UI init by certain {@link UIProvider UIProviders} + * that map different UIs to different URIs, like Vaadin Spring. This + * information is used by the {@link Navigator} when the {@link UI} is + * annotated with {@link PushStateNavigation}. + * <p> + * For example if the UI is accessed through + * {@code http://example.com/MyUI/mainview/parameter=1} the path info would + * be {@code /MyUI}. + * + * @return the path info part of the request; {@code null} if no request + * from client has been processed + * + * @since 8.2 + */ + public String getUiPathInfo() { + return uiPathInfo; + } + /** * Initializes this UI. This method is intended to be overridden by * subclasses to build the view and configure non-component functionality. diff --git a/server/src/test/java/com/vaadin/server/ConnectorResourceHandlerTest.java b/server/src/test/java/com/vaadin/server/ConnectorResourceHandlerTest.java index fd7dc4291d..57b8ed8ff4 100644 --- a/server/src/test/java/com/vaadin/server/ConnectorResourceHandlerTest.java +++ b/server/src/test/java/com/vaadin/server/ConnectorResourceHandlerTest.java @@ -39,10 +39,14 @@ public class ConnectorResourceHandlerTest { request = control.createMock(VaadinRequest.class); response = control.createMock(VaadinResponse.class); + DeploymentConfiguration dc = control + .createMock(DeploymentConfiguration.class); VaadinService service = control.createMock(VaadinService.class); EasyMock.expect(request.getPathInfo()) .andReturn("/APP/connector/0/1/2"); + EasyMock.expect(request.getParameter("v-loc")) + .andReturn("http://localhost/"); control.replay(); @@ -53,13 +57,14 @@ public class ConnectorResourceHandlerTest { protected void init(VaadinRequest request) { } }; - ui.doInit(request, 0, ""); session.lock(); try { + session.setConfiguration(dc); session.setCommunicationManager( new LegacyCommunicationManager(session)); ui.setSession(session); + ui.doInit(request, 0, ""); session.addUI(ui); } finally { session.unlock(); diff --git a/server/src/test/java/com/vaadin/server/VaadinSessionTest.java b/server/src/test/java/com/vaadin/server/VaadinSessionTest.java index 5b5528e8e3..a3d0746149 100644 --- a/server/src/test/java/com/vaadin/server/VaadinSessionTest.java +++ b/server/src/test/java/com/vaadin/server/VaadinSessionTest.java @@ -32,6 +32,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import org.easymock.EasyMock; +import org.easymock.IMocksControl; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -96,12 +97,22 @@ public class VaadinSessionTest implements Serializable { } }; + IMocksControl control = EasyMock.createNiceControl(); + DeploymentConfiguration dc = control + .createMock(DeploymentConfiguration.class); + session = new VaadinSession(mockService); + mockService.storeSession(session, mockWrappedSession); ui = new MockPageUI(); - vaadinRequest = new VaadinServletRequest( - EasyMock.createMock(HttpServletRequest.class), mockService) { + HttpServletRequest request = control + .createMock(HttpServletRequest.class); + EasyMock.expect(request.getParameter("v-loc")) + .andReturn("http://localhost/"); + control.replay(); + + vaadinRequest = new VaadinServletRequest(request, mockService) { @Override public String getParameter(String name) { if ("theme".equals(name) || "restartApplication".equals(name) @@ -116,6 +127,14 @@ public class VaadinSessionTest implements Serializable { } @Override + public Object getAttribute(String name) { + if (name.equals("com.vaadin.server.UI_ROOT_PATH")) { + return "/"; + } + return super.getAttribute(name); + } + + @Override public String getMethod() { return "POST"; } @@ -128,9 +147,10 @@ public class VaadinSessionTest implements Serializable { }; + session.setConfiguration(dc); + ui.setSession(session); ui.doInit(vaadinRequest, session.getNextUIid(), null); - ui.setSession(session); session.addUI(ui); } @@ -240,9 +260,6 @@ public class VaadinSessionTest implements Serializable { // VaadinSessionTest.this which isn't serializable private static class MockPageUI extends UI { Page page = new Page(this, getState(false).pageState) { - @Override - public void init(VaadinRequest request) { - } }; @Override diff --git a/server/src/test/java/com/vaadin/tests/server/navigator/NavigatorTest.java b/server/src/test/java/com/vaadin/tests/server/navigator/NavigatorTest.java index 636c226e66..019c13698d 100644 --- a/server/src/test/java/com/vaadin/tests/server/navigator/NavigatorTest.java +++ b/server/src/test/java/com/vaadin/tests/server/navigator/NavigatorTest.java @@ -36,6 +36,7 @@ import org.junit.Test; import com.vaadin.navigator.NavigationStateManager; import com.vaadin.navigator.Navigator; +import com.vaadin.navigator.PushStateNavigation; import com.vaadin.navigator.View; import com.vaadin.navigator.ViewBeforeLeaveEvent; import com.vaadin.navigator.ViewChangeListener; @@ -138,6 +139,31 @@ public class NavigatorTest { } } + public static class TestNavigatorWithFragments extends Navigator { + public TestNavigatorWithFragments() { + super(createMockUI(), new NullFragmentManager(), new TestDisplay()); + } + + public TestNavigatorWithFragments(UI ui) { + super(ui, new UriFragmentManager(ui.getPage()), + EasyMock.createMock(ViewDisplay.class)); + } + + public View getView(String viewAndParameters) { + try { + navigateTo(viewAndParameters); + } catch (IllegalArgumentException e) { + // ignore + } + return ((TestDisplay) getDisplay()).getCurrentView(); + } + + @Override + protected NavigationStateManager getStateManager() { + return super.getStateManager(); + } + } + public static class ViewChangeTestListener implements ViewChangeListener { private final LinkedList<ViewChangeEvent> referenceEvents = new LinkedList<>(); private final LinkedList<Boolean> referenceIsCheck = new LinkedList<>(); @@ -244,6 +270,14 @@ public class NavigatorTest { private final Page page; } + @PushStateNavigation + private static class TestPushStateUI extends TestUI { + + TestPushStateUI(Page page) { + super(page); + } + } + private static class TestPage extends Page { public TestPage() { @@ -251,6 +285,31 @@ public class NavigatorTest { } @Override + public Registration addPopStateListener(PopStateListener listener) { + addPopstateCalled = true; + return () -> removePopstateCalled = true; + } + + boolean addPopstateCalled() { + return addPopstateCalled; + } + + boolean removePopstateCalled() { + return removePopstateCalled; + } + + private boolean addPopstateCalled; + + private boolean removePopstateCalled; + } + + private static class TestPageWithUriFragments extends Page { + + public TestPageWithUriFragments() { + super(null, null); + } + + @Override public Registration addUriFragmentChangedListener( UriFragmentChangedListener listener) { addUriFragmentCalled = true; @@ -304,12 +363,13 @@ public class NavigatorTest { return new Navigator(createMockUI(), manager, display); } - @Test(expected = NullPointerException.class) + @Test public void testDestroy_unsetNavigatorInUIAndUriFragmentManager() { - TestPage page = new TestPage(); + TestPageWithUriFragments page = new TestPageWithUriFragments(); UI ui = new TestUI(page); - TestNavigator navigator = new TestNavigator(ui); + TestNavigatorWithFragments navigator = new TestNavigatorWithFragments( + ui); Assert.assertTrue("Add URI fragment Page method has not been called", page.addUriFragmentCalled()); Assert.assertFalse("Unexpected remove URI fragment Page method call", @@ -323,11 +383,44 @@ public class NavigatorTest { Assert.assertNull("Navigator is not null in UI after destroy", ui.getNavigator()); - page.setUriFragment("foobar", true); + try { + page.setUriFragment("foobar", true); // This should throw + Assert.fail( + "Expected null pointer exception after call uriFragmentChanged " + + "for destroyed navigator"); + } catch (NullPointerException e) { + // All ok. + } + } + + @Test + public void testDestroy_unsetNavigatorInUIAndPopstateManager() { + TestPage page = new TestPage(); + UI ui = new TestPushStateUI(page); + + TestNavigator navigator = new TestNavigator(ui); + Assert.assertTrue("Add URI fragment Page method has not been called", + page.addPopstateCalled()); + Assert.assertFalse("Unexpected remove URI fragment Page method call", + page.removePopstateCalled()); + Assert.assertNotNull("Navigator is null in UI", ui.getNavigator()); + + navigator.destroy(); + Assert.assertTrue( + "Remove URI fragment Page method has not been called after destroy", + page.removePopstateCalled()); + Assert.assertNull("Navigator is not null in UI after destroy", + ui.getNavigator()); + + try { + page.updateLocation("http://server/path/info", true, true); - Assert.fail( - "Expected null pointer exception after call uriFragmentChanged " - + "for destroyed navigator"); + Assert.fail( + "Expected null pointer exception after call uriFragmentChanged " + + "for destroyed navigator"); + } catch (NullPointerException e) { + // All ok. + } } @Test diff --git a/server/src/test/java/com/vaadin/ui/UIInitRefreshTest.java b/server/src/test/java/com/vaadin/ui/UIInitRefreshTest.java index c4a44d85a6..65bbc59a5b 100644 --- a/server/src/test/java/com/vaadin/ui/UIInitRefreshTest.java +++ b/server/src/test/java/com/vaadin/ui/UIInitRefreshTest.java @@ -15,17 +15,21 @@ */ package com.vaadin.ui; +import java.util.Locale; + import org.easymock.EasyMock; import org.easymock.IMocksControl; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.vaadin.server.DeploymentConfiguration; import com.vaadin.server.Page.BrowserWindowResizeEvent; import com.vaadin.server.Page.BrowserWindowResizeListener; import com.vaadin.server.Page.UriFragmentChangedEvent; import com.vaadin.server.Page.UriFragmentChangedListener; import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinSession; public class UIInitRefreshTest { @@ -87,6 +91,7 @@ public class UIInitRefreshTest { IMocksControl control = EasyMock.createNiceControl(); VaadinRequest initRequest = control.createMock(VaadinRequest.class); + EasyMock.expect(initRequest.getParameter("v-loc")) .andReturn("http://example.com/#foo"); EasyMock.expect(initRequest.getParameter("v-cw")).andReturn("100"); @@ -98,9 +103,18 @@ public class UIInitRefreshTest { EasyMock.expect(reinitRequest.getParameter("v-cw")).andReturn("200"); EasyMock.expect(reinitRequest.getParameter("v-ch")).andReturn("200"); + VaadinSession session = control.createMock(VaadinSession.class); + DeploymentConfiguration dc = control + .createMock(DeploymentConfiguration.class); + + EasyMock.expect(session.hasLock()).andStubReturn(true); + EasyMock.expect(session.getConfiguration()).andStubReturn(dc); + EasyMock.expect(session.getLocale()).andStubReturn(Locale.getDefault()); + control.replay(); UI ui = new TestUI(); + ui.setSession(session); ui.doInit(initRequest, 0, ""); Assert.assertTrue(initCalled); diff --git a/server/src/test/java/com/vaadin/ui/UIThemeEscapingTest.java b/server/src/test/java/com/vaadin/ui/UIThemeEscapingTest.java index 7c19694eec..656dd96b30 100644 --- a/server/src/test/java/com/vaadin/ui/UIThemeEscapingTest.java +++ b/server/src/test/java/com/vaadin/ui/UIThemeEscapingTest.java @@ -21,10 +21,16 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.Locale; + +import org.easymock.EasyMock; +import org.easymock.IMocksControl; import org.junit.Before; import org.junit.Test; +import com.vaadin.server.DeploymentConfiguration; import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinSession; public class UIThemeEscapingTest { @@ -33,13 +39,28 @@ public class UIThemeEscapingTest { private void initUiWithTheme(String theme) { VaadinRequest request = getRequestWithTheme(theme); + IMocksControl control = EasyMock.createNiceControl(); + VaadinSession session = control.createMock(VaadinSession.class); + DeploymentConfiguration dc = control + .createMock(DeploymentConfiguration.class); + + EasyMock.expect(session.hasLock()).andStubReturn(true); + EasyMock.expect(session.getConfiguration()).andStubReturn(dc); + EasyMock.expect(session.getLocale()).andStubReturn(Locale.getDefault()); + + control.replay(); + + ui.setSession(session); + ui.getPage().init(request); ui.doInit(request, 1234, "foobar"); } private VaadinRequest getRequestWithTheme(String theme) { VaadinRequest request = mock(VaadinRequest.class); + // when(request.getParameter()) when(request.getParameter("theme")).thenReturn(theme); + when(request.getParameter("v-loc")).thenReturn("http://localhost/"); return request; } |