package org.activityinfo.ui.client.page; /* * #%L * ActivityInfo Server * %% * Copyright (C) 2009 - 2013 UNICEF * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import com.google.gwt.user.client.rpc.AsyncCallback; import org.activityinfo.legacy.client.monitor.NullAsyncMonitor; import org.activityinfo.ui.client.MockEventBus; import org.activityinfo.ui.client.page.app.Section; import org.easymock.Capture; import org.easymock.IAnswer; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.easymock.EasyMock.*; public class NavigationHandlerTest { private MockEventBus eventBus = new MockEventBus(); private Frame rootFrameSet = createMock("rootFrameSet", Frame.class); private FrameId outerFrameSetId = new FrameId("outerFrameSet"); private Frame outerFrameSet = createMock("outerFrameSet", Frame.class); private PageId firstPageId = new PageId("page1"); private Page firstPage = createMock("firstPage", Frame.class); private PageId secondPageId = new PageId("page2"); private Page secondPage = createMock("secondPage", Page.class); private PageLoader pageLoader = createMock("pageLoader", PageLoader.class); private PageState innerPlaceWithOuterFrame = new MockPageState(firstPageId, Arrays.asList(outerFrameSetId, firstPageId)); private PageState secondInnerPlaceWithSameOuterFrame = new MockPageState( secondPageId, Arrays.asList(outerFrameSetId, secondPageId)); private PageState firstPlace = new MockPageState(firstPageId, Arrays.asList(firstPageId)); private PageState secondPlace = new MockPageState(secondPageId, Arrays.asList(secondPageId)); private NavigationHandler pageManager; @Before public void setUp() { expect(outerFrameSet.getPageId()).andReturn(outerFrameSetId).anyTimes(); expect(firstPage.getPageId()).andReturn(firstPageId).anyTimes(); pageManager = new NavigationHandler(eventBus, rootFrameSet); } @Test public void verifyThatAPageWithOneOuterContainerIsCorrectlyLoaded() { thereIsNoActivePageIn(rootFrameSet); expectLoadingPlaceHolderToBeShown(rootFrameSet); expectAndCaptureLoadRequestFor(outerFrameSetId); expectPageToBeSetTo(rootFrameSet, outerFrameSet); thereIsNoActivePageIn(outerFrameSet); expectLoadingPlaceHolderToBeShown(outerFrameSet); expectAndCaptureLoadRequestFor(firstPageId); expectPageToBeSetTo(outerFrameSet, firstPage); replayAll(); pageManager.registerPageLoader(outerFrameSetId, pageLoader); pageManager.registerPageLoader(firstPageId, pageLoader); requestNavigationTo(innerPlaceWithOuterFrame); pageLoadFinishes(outerFrameSetId, outerFrameSet); pageLoadFinishes(firstPageId, firstPage); verify(rootFrameSet, outerFrameSet, firstPage, pageLoader); } @Test public void innerPageCanCancelNavigation() { theRootPageIs(outerFrameSet); theOuterFrameSetIsShowing(firstPage); navigationRequestWillBeRefusedBy(firstPage); replayAll(); requestNavigationTo(secondInnerPlaceWithSameOuterFrame); verify(outerFrameSet, firstPage); eventBus.assertNotFired(NavigationHandler.NAVIGATION_AGREED); } @Test public void navigationProceedsUponApprovalOfInnerPage() { theRootPageIs(outerFrameSet); theOuterFrameSetIsShowing(firstPage); expectAndAgreeToNavigationRequestionOn(firstPage); expectNavigate(outerFrameSet); expectLoadingPlaceHolderToBeShown(outerFrameSet); expectAndCaptureLoadRequestFor(secondPageId); expectShutdownCallTo(firstPage); expectPageToBeSetTo(outerFrameSet, secondPage); replayAll(); pageManager.registerPageLoader(secondPageId, pageLoader); requestNavigationTo(secondInnerPlaceWithSameOuterFrame); pageLoadFinishes(secondPageId, secondPage); verify(outerFrameSet, firstPage, pageLoader); Assert.assertEquals(1, eventBus.getEventCount(NavigationHandler.NAVIGATION_AGREED)); } @Test public void userCanNavigateToDifferentPageWhilePreviousRequestIsLoading() { thereIsNoActivePageIn(rootFrameSet); expectLoadingPlaceHolderToBeShownTwiceIn(rootFrameSet); expectAndCaptureLoadRequestFor(firstPageId); expectAndCaptureLoadRequestFor(secondPageId); expectPageToBeSetTo(rootFrameSet, secondPage); replayAll(); pageManager.registerPageLoader(firstPageId, pageLoader); pageManager.registerPageLoader(secondPageId, pageLoader); requestNavigationTo(firstPlace); requestNavigationTo(secondPlace); pageLoadFinishes(secondPageId, secondPage); pageLoadFinishes(firstPageId, firstPage); verify(rootFrameSet, pageLoader); } private class MockPageState implements PageState { private final PageId pageId; private final List<PageId> viewPath; private MockPageState(PageId pageId, List<PageId> viewPath) { this.pageId = pageId; this.viewPath = viewPath; } @Override public PageId getPageId() { return pageId; } @Override public String serializeAsHistoryToken() { return null; } @Override public List<PageId> getEnclosingFrames() { return viewPath; } @Override public Section getSection() { return Section.HOME; } } @Test public void duplicateNavigationRequestsAreIgnored() { thereIsNoActivePageIn(rootFrameSet); expectLoadingPlaceHolderToBeShown(rootFrameSet); expectAndCaptureLoadRequestFor(firstPageId); expectPageToBeSetTo(rootFrameSet, firstPage); replayAll(); pageManager.registerPageLoader(firstPageId, pageLoader); requestNavigationTo(firstPlace); requestNavigationTo(firstPlace); pageLoadFinishes(firstPageId, firstPage); verify(rootFrameSet, pageLoader, firstPage); } private void theRootPageIs(Page page) { expect(rootFrameSet.getActivePage()).andReturn(page).anyTimes(); } private void theOuterFrameSetIsShowing(Page page) { expect(outerFrameSet.getActivePage()).andReturn(page).anyTimes(); } private void requestNavigationTo(PageState place) { eventBus.fireEvent(new NavigationEvent( NavigationHandler.NAVIGATION_REQUESTED, place)); } private void thereIsNoActivePageIn(Frame rootFrameSet) { expect(rootFrameSet.getActivePage()).andReturn(null).anyTimes(); } private void expectShutdownCallTo(Page page) { page.shutdown(); } private void expectNavigate(Frame frameSet) { expect(frameSet.navigate(isA(PageState.class))).andReturn(true); } private Map<PageId, Capture<AsyncCallback<Page>>> loadCallbacks = new HashMap(); private void expectAndCaptureLoadRequestFor(PageId pageId) { Capture<AsyncCallback<Page>> capture = new Capture<AsyncCallback<Page>>(); loadCallbacks.put(pageId, capture); pageLoader.load(eq(pageId), isA(PageState.class), capture(capture)); expectLastCall().anyTimes(); } private void pageLoadFinishes(PageId pageId, Page page) { loadCallbacks.get(pageId).getValue().onSuccess(page); } private void expectPageToBeSetTo(Frame frameSet, Page page) { frameSet.setActivePage(page); } private void expectLoadingPlaceHolderToBeShown(Frame frame) { expect( frame.showLoadingPlaceHolder(isA(PageId.class), isA(PageState.class))) .andReturn(new NullAsyncMonitor()); } private void expectLoadingPlaceHolderToBeShownTwiceIn(Frame frame) { expect( frame.showLoadingPlaceHolder(isA(PageId.class), isA(PageState.class))) .andReturn(new NullAsyncMonitor()) .times(2); } private void navigationRequestWillBeRefusedBy(Page page) { navigationRequestWillBeAnsweredBy(page, false); } private void expectAndAgreeToNavigationRequestionOn(Page page) { navigationRequestWillBeAnsweredBy(page, true); } private void navigationRequestWillBeAnsweredBy(Page page, final boolean allowed) { page.requestToNavigateAway(isA(PageState.class), isA(NavigationCallback.class)); expectLastCall().andAnswer(new IAnswer<Void>() { @Override public Void answer() throws Throwable { ((NavigationCallback) (getCurrentArguments()[1])) .onDecided(allowed); return null; } }); } private void replayAll() { replay(rootFrameSet); replay(pageLoader); replay(outerFrameSet); replay(firstPage); replay(secondPage); } }