/** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.testing; import com.facebook.litho.Component; import com.facebook.litho.ComponentContext; import com.facebook.litho.ComponentTree; import com.facebook.litho.LithoView; import org.powermock.reflect.Whitebox; import org.robolectric.shadows.ShadowLooper; /** * Helper for writing state update unit tests. */ public class StateUpdatesTestHelper { public interface StateUpdater { void performStateUpdate(ComponentContext context); } /** * Call a state update as specified in {@link StateUpdater#performStateUpdate(ComponentContext)} * on the component and return the updated view. * @param context context * @param component the component to update * @param stateUpdater implementation of {@link StateUpdater} that triggers the state update * @param layoutThreadShadowLooper shadow looper to post messages to the main thread * @return the updated LithoView after the state update was applied */ public static LithoView getViewAfterStateUpdate( ComponentContext context, Component component, StateUpdater stateUpdater, ShadowLooper layoutThreadShadowLooper) throws Exception { return getViewAfterStateUpdate( context, component, stateUpdater, layoutThreadShadowLooper, false); } /** * Call a state update as specified in {@link StateUpdater#performStateUpdate(ComponentContext)} * on the component and return the updated view with the option to incrementally mount. * @param context context * @param component the component to update * @param stateUpdater implementation of {@link StateUpdater} that triggers the state update * @param layoutThreadShadowLooper shadow looper to post messages to the main thread * @param incrementalMountEnabled whether or not to enable incremental mount for the component * @return the updated LithoView after the state update was applied */ public static LithoView getViewAfterStateUpdate( ComponentContext context, Component component, StateUpdater stateUpdater, ShadowLooper layoutThreadShadowLooper, boolean incrementalMountEnabled) throws Exception { return getViewAfterStateUpdate( context, component, stateUpdater, new ShadowLooper[]{layoutThreadShadowLooper}, incrementalMountEnabled); } /** * Call a state update as specified in {@link StateUpdater#performStateUpdate(ComponentContext)} * on the component and return the updated view with the option to incrementally mount. * @param context context * @param component the component to update * @param stateUpdater implementation of {@link StateUpdater} that triggers the state update * @param loopers shadow loopers to post messages to the main thread, run in the same order they * are specified * @param incrementalMountEnabled whether or not to enable incremental mount for the component * @return the updated LithoView after the state update was applied */ public static LithoView getViewAfterStateUpdate( ComponentContext context, Component component, StateUpdater stateUpdater, ShadowLooper[] loopers, boolean incrementalMountEnabled) throws Exception { // This is for working around component immutability, to be able to retrieve the updated // instance of the component. Whitebox.invokeMethod(component, "setKey", "bogusKeyForTest"); final ComponentTree componentTree = ComponentTree.create(context, component) .incrementalMount(incrementalMountEnabled) .layoutDiffing(false) .build(); final LithoView lithoView = new LithoView(context); ComponentTestHelper.mountComponent(lithoView, componentTree); Whitebox.setInternalState(component, "mGlobalKey", "bogusKeyForTest"); Whitebox.setInternalState(component, "mId", 457282882); Whitebox.setInternalState(context, "mComponentScope", component); Whitebox.setInternalState(context, "mComponentTree", componentTree); stateUpdater.performStateUpdate(context); for (ShadowLooper looper : loopers) { looper.runToEndOfTasks(); } ComponentTestHelper.mountComponent(lithoView, componentTree); return lithoView; } }