import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.easymock.EasyMock;
import com.vaadin.navigator.NavigationStateManager;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewBeforeLeaveEvent;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.navigator.ViewDisplay;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ui.PageState;
-import com.vaadin.tests.server.navigator.ClassBasedViewProviderTest.TestView;
import com.vaadin.tests.server.navigator.ClassBasedViewProviderTest.TestView2;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
.createMock(NavigationStateManager.class);
ViewDisplay display = control.createMock(ViewDisplay.class);
ViewProvider provider = control.createMock(ViewProvider.class);
- View view1 = control.createMock(View.class);
- View view2 = control.createMock(View.class);
+ TestView view1 = new TestView();
+ TestView view2 = new TestView();
// prepare mocks: what to expect
manager.setNavigator(EasyMock.anyObject(Navigator.class));
.times(2);
EasyMock.expect(provider.getView("test1")).andReturn(view1);
EasyMock.expect(manager.getState()).andReturn("");
- view1.enter(eventParametersEqual(""));
display.showView(view1);
manager.setState("test1");
EasyMock.expect(manager.getState()).andReturn("test1");
.times(2);
EasyMock.expect(provider.getView("test2")).andReturn(view2);
EasyMock.expect(manager.getState()).andReturn("test1");
- view2.enter(eventParametersEqual(""));
display.showView(view2);
manager.setState("test2");
EasyMock.expect(manager.getState()).andReturn("test2");
.times(2);
EasyMock.expect(provider.getView("test1")).andReturn(view1);
EasyMock.expect(manager.getState()).andReturn("test2");
- view1.enter(eventParametersEqual("params"));
display.showView(view1);
manager.setState("test1/params");
EasyMock.expect(manager.getState()).andReturn("test1/params");
navigator.navigateTo("test1");
assertEquals("test1", navigator.getState());
-
+ assertEquals("", view1.getParams());
navigator.navigateTo("test2/");
assertEquals("test2", navigator.getState());
+ assertEquals("", view2.getParams());
navigator.navigateTo("test1/params");
assertEquals("test1/params", navigator.getState());
+ assertEquals("params", view1.getParams());
+ }
+
+ public static class TestView implements View {
+ private String params;
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ params = event.getParameters();
+ }
+
+ public String getParams() {
+ return params;
+ }
}
@Test
.createMock(NavigationStateManager.class);
ViewDisplay display = control.createMock(ViewDisplay.class);
ViewProvider provider = control.createMock(ViewProvider.class);
- View view1 = control.createMock(View.class);
- View view2 = control.createMock(View.class);
+ TestView view1 = new TestView();
+ TestView view2 = new TestView();
// prepare mocks: what to expect
manager.setNavigator(EasyMock.anyObject(Navigator.class));
.times(2);
EasyMock.expect(provider.getView("test2")).andReturn(view2);
EasyMock.expect(manager.getState()).andReturn("view1");
- view2.enter(eventParametersEqual(""));
display.showView(view2);
manager.setState("test2");
EasyMock.expect(provider.getViewName("")).andReturn("test1").times(2);
EasyMock.expect(provider.getView("test1")).andReturn(view1);
EasyMock.expect(manager.getState()).andReturn("");
- view1.enter(eventParametersEqual(""));
display.showView(view1);
manager.setState("test1");
.times(2);
EasyMock.expect(provider.getView("test1")).andReturn(view1);
EasyMock.expect(manager.getState()).andReturn("test2");
- view1.enter(eventParametersEqual("params"));
display.showView(view1);
manager.setState("test1/params");
navigator.addProvider(provider);
navigator.navigateTo("test2");
+ Assert.assertEquals("", view2.getParams());
+ Assert.assertEquals(null, view1.getParams());
navigator.navigateTo("");
+ Assert.assertEquals("", view1.getParams());
navigator.navigateTo("test1/params");
+ Assert.assertEquals("params", view1.getParams());
}
@Test
.createMock(NavigationStateManager.class);
ViewDisplay display = control.createMock(ViewDisplay.class);
ViewProvider provider = control.createMock(ViewProvider.class);
- View view1 = control.createMock(View.class);
- View view2 = control.createMock(View.class);
+ TestView view1 = new TestView();
+ TestView view2 = new TestView();
ViewChangeTestListener listener = new ViewChangeTestListener();
// create navigator to test
"test1", "");
listener.addExpectedIsViewChangeAllowed(event1, true);
EasyMock.expect(manager.getState()).andReturn("");
- view1.enter(eventParametersEqual(""));
display.showView(view1);
manager.setState("test1");
listener.addExpectedNavigatorViewChange(event1);
"test2", "");
listener.addExpectedIsViewChangeAllowed(event2, true);
EasyMock.expect(manager.getState()).andReturn("test1");
- view2.enter(eventParametersEqual(""));
display.showView(view2);
manager.setState("test2");
listener.addExpectedNavigatorViewChange(event2);
.createMock(NavigationStateManager.class);
ViewDisplay display = control.createMock(ViewDisplay.class);
ViewProvider provider = control.createMock(ViewProvider.class);
- View view1 = control.createMock(View.class);
- View view2 = control.createMock(View.class);
+ TestView view1 = new TestView();
+ TestView view2 = new TestView();
ViewChangeTestListener listener1 = new ViewChangeTestListener();
ViewChangeTestListener listener2 = new ViewChangeTestListener();
"test1", "bar");
listener1.addExpectedIsViewChangeAllowed(event3, true);
listener2.addExpectedIsViewChangeAllowed(event3, true);
- view1.enter(EasyMock.isA(ViewChangeEvent.class));
display.showView(view1);
manager.setState("test1/bar");
listener1.addExpectedNavigatorViewChange(event3);
"test2", "");
listener1.addExpectedIsViewChangeAllowed(event4, true);
listener2.addExpectedIsViewChangeAllowed(event4, true);
- view2.enter(EasyMock.isA(ViewChangeEvent.class));
display.showView(view2);
manager.setState("test2");
listener1.addExpectedNavigatorViewChange(event4);
public void testNavigateToUnknownView() {
TestNavigator navigator = new TestNavigator();
- View errorView = EasyMock.createMock(View.class);
- errorView.enter(EasyMock.anyObject(ViewChangeEvent.class));
- EasyMock.replay(errorView);
+ TestView errorView = new TestView();
try {
navigator.navigateTo("doesnotexist");
navigator.setErrorView(errorView);
navigator.navigateTo("doesnotexist");
- View testView = EasyMock.createMock(View.class);
- testView.enter(EasyMock.anyObject(ViewChangeEvent.class));
- EasyMock.replay(testView);
+ TestView testView = new TestView();
navigator.addView("doesnotexist", testView);
navigator.navigateTo("doesnotexist");
-
- View errorView2 = EasyMock.createMock(View.class);
- errorView2.enter(EasyMock.anyObject(ViewChangeEvent.class));
- EasyMock.replay(errorView2);
+ TestView errorView2 = new TestView();
ViewProvider errorProvider = EasyMock.createMock(ViewProvider.class);
EasyMock.expect(errorProvider.getView("doesnotexist2"))
@Test
public void parameterMapFromViewChangeEvent() {
- // create navigator to test
Navigator navigator = createNavigatorWithState("foo");
- View view1 = EasyMock.createMock(View.class);
- View view2 = EasyMock.createMock(View.class);
- ViewProvider provider = new ViewProvider() {
-
- @Override
- public String getViewName(String viewAndParameters) {
- if (viewAndParameters.contains("/")) {
- return viewAndParameters.substring(0,
- viewAndParameters.indexOf('/'));
- } else {
- return viewAndParameters;
- }
- }
-
- @Override
- public View getView(String viewName) {
- if (viewName.equals("view1")) {
- return view1;
- } else if (viewName.equals("view2")) {
- return view2;
- } else {
- return null;
- }
- }
- };
- navigator.addProvider(provider);
+ TestView view1 = new TestView();
+ TestView view2 = new TestView();
+ navigator.addView("view1", view1);
+ navigator.addView("view2", view2);
AtomicReference<Map<String, String>> mapRef = new AtomicReference<>();
AtomicReference<Map<String, String>> mapRefB = new AtomicReference<>();
entry("d", ""));
assertMap(mapRefB.get(), entry("a&", ""), entry("", "c&d"));
}
+
+ @Test
+ public void view_beforeLeave_preventNavigation() {
+ Navigator navigator = createNavigatorWithState("foo");
+ View view1 = new View() {
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ }
+
+ @Override
+ public void beforeLeave(ViewBeforeLeaveEvent event) {
+ // Leaving this empty means the user can never leave
+ }
+
+ };
+ View view2 = EasyMock.createMock(View.class);
+ navigator.addView("view1", view1);
+ navigator.addView("view2", view2);
+ navigator.navigateTo("view1");
+ navigator.navigateTo("view2");
+ Assert.assertEquals("view1", navigator.getState());
+ }
+
+ @Test
+ public void view_beforeLeave_allowNavigation() {
+ Navigator navigator = createNavigatorWithState("foo");
+ View view1 = new View() {
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ }
+
+ @Override
+ public void beforeLeave(ViewBeforeLeaveEvent event) {
+ event.navigate();
+ }
+
+ };
+ View view2 = EasyMock.createMock(View.class);
+ navigator.addView("view1", view1);
+ navigator.addView("view2", view2);
+ navigator.navigateTo("view1");
+ navigator.navigateTo("view2");
+ Assert.assertEquals("view2", navigator.getState());
+
+ }
+
+ @Test
+ public void view_beforeLeave_delayNavigation() {
+ Navigator navigator = createNavigatorWithState("foo");
+ AtomicReference<ViewBeforeLeaveEvent> eventRef = new AtomicReference<ViewBeforeLeaveEvent>();
+ View view1 = new View() {
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ }
+
+ @Override
+ public void beforeLeave(ViewBeforeLeaveEvent event) {
+ eventRef.set(event);
+ }
+
+ };
+ View view2 = EasyMock.createMock(View.class);
+ navigator.addView("view1", view1);
+ navigator.addView("view2", view2);
+ navigator.navigateTo("view1");
+ navigator.navigateTo("view2");
+ Assert.assertEquals("view1", navigator.getState());
+ eventRef.get().navigate();
+ Assert.assertEquals("view2", navigator.getState());
+
+ }
+
+ @Test
+ public void navigator_invokeBeforeLeaveManually() {
+ Navigator navigator = createNavigatorWithState("foo");
+ AtomicReference<ViewBeforeLeaveEvent> eventRef = new AtomicReference<ViewBeforeLeaveEvent>();
+ View view1 = new View() {
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ }
+
+ @Override
+ public void beforeLeave(ViewBeforeLeaveEvent event) {
+ eventRef.set(event);
+ }
+
+ };
+ TestView view2 = new TestView();
+ navigator.addView("view1", view1);
+ navigator.addView("view2", view2);
+ navigator.navigateTo("view1");
+
+ AtomicInteger leaveCount = new AtomicInteger(0);
+ navigator.runAfterLeaveConfirmation(() -> {
+ leaveCount.incrementAndGet();
+ });
+ Assert.assertEquals(0, leaveCount.get());
+ eventRef.get().navigate();
+ Assert.assertEquals(1, leaveCount.get());
+ Assert.assertEquals("view1", navigator.getState());
+ }
}
--- /dev/null
+/*
+ * 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.tests.navigator;
+
+import com.vaadin.navigator.Navigator;
+import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewBeforeLeaveEvent;
+import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
+import com.vaadin.navigator.ViewLeaveAction;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+
+public class DelayedViewLeaveConfirmation extends AbstractTestUI {
+
+ public static class OtherView extends VerticalLayout implements View {
+ public OtherView() {
+ addComponent(new Label("Just another view"));
+ }
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+
+ }
+ }
+
+ public static class MainView extends VerticalLayout implements View {
+ private Label saved;
+ private TextField input;
+
+ public MainView() {
+ saved = new Label("Initial");
+ saved.setCaption("Saved value");
+ input = new TextField("Enter a value");
+ input.setId("input");
+ Button navigateAway = new Button("Navigate to the other view",
+ e -> {
+ getUI().getNavigator().navigateTo("other");
+ });
+ Button logout = new Button("Simulate logout", e -> {
+ getUI().getNavigator().runAfterLeaveConfirmation(() -> {
+ removeAllComponents();
+ addComponent(new Label("You have been logged out"));
+ getUI().getPage().setUriFragment("", false);
+ });
+ });
+ navigateAway.setId("navigateAway");
+ logout.setId("logout");
+ addComponents(saved, input, navigateAway, logout);
+ }
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ input.setValue(saved.getValue());
+ }
+
+ @Override
+ public void beforeLeave(ViewBeforeLeaveEvent event) {
+ boolean hasChanges = !(saved.getValue().equals(input.getValue()));
+ if (hasChanges) {
+ getUI().addWindow(new ConfirmationWindow(event::navigate));
+ } else {
+ event.navigate();
+ }
+ }
+
+ }
+
+ public static class ConfirmationWindow extends Window {
+ public ConfirmationWindow(ViewLeaveAction action) {
+ super();
+ VerticalLayout layout = new VerticalLayout();
+ layout.addComponent(new Label(
+ "You have unsaved changes. Are you sure you want to leave?"));
+ Button leave = new Button("YES, LEAVE!", e -> {
+ close();
+ action.run();
+ });
+ leave.setId("leave");
+ Button stay = new Button("NO, STAY!", e -> {
+ close();
+ });
+ stay.setId("stay");
+ layout.addComponents(new HorizontalLayout(leave, stay));
+ setContent(layout);
+ }
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ setNavigator(new Navigator(this, this));
+ getNavigator().addView("main", MainView.class);
+ getNavigator().addView("other", OtherView.class);
+ }
+
+}
--- /dev/null
+/*
+ * 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.tests.navigator;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.testbench.elements.WindowElement;
+import com.vaadin.tests.tb3.SingleBrowserTest;
+
+public class DelayedViewLeaveConfirmationTest extends SingleBrowserTest {
+
+ @Test
+ public void navigateAwayWithoutChanges() {
+ openMainView();
+ navigateToOtherView();
+ assertOnOtherView();
+ }
+
+ @Test
+ public void cancelNavigateAwayWithChanges() {
+ openMainView();
+ updateValue();
+ navigateToOtherView();
+ assertOnMainView();
+ chooseToStay();
+ assertOnMainView();
+ }
+
+ @Test
+ public void confirmNavigateAwayWithChanges() {
+ openMainView();
+ updateValue();
+ navigateToOtherView();
+ assertOnMainView();
+ chooseToLeave();
+ assertOnOtherView();
+ }
+
+ @Test
+ public void confirmLogoutWithChanges() {
+ openMainView();
+ updateValue();
+ logout();
+ assertOnMainView();
+ chooseToLeave();
+ assertLoggedOut();
+ }
+
+ @Test
+ public void cancelLogoutWithChanges() {
+ openMainView();
+ updateValue();
+ logout();
+ assertOnMainView();
+ chooseToStay();
+ assertOnMainView();
+ }
+
+ @Test
+ public void logoutWithoutChanges() {
+ openMainView();
+ getLogout().click();
+ assertLoggedOut();
+
+ }
+
+ private void openMainView() {
+ String url = getTestURL(DelayedViewLeaveConfirmation.class);
+ url += "#!main";
+
+ driver.get(url);
+ }
+
+ private void navigateToOtherView() {
+ getNavigateAway().click();
+ }
+
+ private void logout() {
+ getLogout().click();
+ }
+
+ private void assertOnOtherView() {
+ Assert.assertEquals("Just another view",
+ $(LabelElement.class).first().getText());
+ }
+
+ private void assertOnMainView() {
+ Assert.assertEquals("Saved value",
+ $(LabelElement.class).first().getCaption());
+ }
+
+ private void assertLoggedOut() {
+ Assert.assertEquals("You have been logged out",
+ $(LabelElement.class).first().getText());
+ }
+
+ private void chooseToStay() {
+ $(WindowElement.class).first().$(ButtonElement.class).id("stay")
+ .click();
+ }
+
+ private void chooseToLeave() {
+ $(WindowElement.class).first().$(ButtonElement.class).id("leave")
+ .click();
+ }
+
+ private void updateValue() {
+ TextFieldElement input = $(TextFieldElement.class).id("input");
+ input.setValue(input.getValue() + "-upd");
+ }
+
+ private ButtonElement getNavigateAway() {
+ return $(ButtonElement.class).id("navigateAway");
+ }
+
+ private ButtonElement getLogout() {
+ return $(ButtonElement.class).id("logout");
+ }
+}