Skip to main content

Matching @InjectProp

Tips

For help with setting up the test environment, see the Getting Started page.

Before learning about @InectProp matching, it's recommended you become familiar with sub-component testing.

Testing Injected Props​

@InjectProp earmarks props to be provided by the client's dependency injection framework. Components that have injected props can be tested using a @TestSpec and the prop-matching APIs.

Consider the following LayoutSpec:

@LayoutSpec
class MyInjectPropSpec {
@OnCreateLayout
static Component onCreateLayout(
ComponentContext c,
@Prop String normalProp,
@InjectProp UserController injectedProp,
@InjectProp ProfilePictureComponent profilePicture) {
// ...
}
}

To test using injected props, take the following steps:

  1. Create a @TestSpec for MyInjectPropSpec:
@TestSpec(MyInjectPropSpec.class)
public interface TestMyInjectPropSpec {}
  1. Add @RunWith(LithoTestRunner.class) to the top of the test class.
  2. Add a JUnit @Rule LithoViewRule.
  3. Add a check to ensure that tests are run in debug mode. ComponentsConfiguration.IS_INTERNAL_BUILD must be true.

The test class should look like the following:

@RunWith(LithoTestRunner.class)
public class InjectPropMatcherGenerationTest {

public final @Rule LithoViewRule mLithoViewRule = new LithoViewRule();

@Before
public void assumeInDebugMode() {
assumeThat(
"These tests can only be run in debug mode.",
ComponentsConfiguration.IS_INTERNAL_BUILD, is(true)
);
}
}
  1. Set the value of the injected props before evaluating any assertions:
@Test
public void whenMyInjectPropComponentIsRendered_shouldUseProvidedInjectProps() {
final ComponentContext c = mLithoViewRule.getContext();
final MyInjectProp component = MyInjectProp.create(c)
.normalProp("normal string")
.build();

// Set the injected prop values.
component.injectedString = "injected string";
component.injectedKettle = new Kettle(92f);

final Condition<InspectableComponent> matcher =
TestMyInjectProp.matcher(c)
.normalString("normal string")
.injectedString("injected string")
.injectedKettle(new CustomTypeSafeMatcher<MyInjectPropSpec.Kettle>("matches temperature") {
@Override
protected boolean matchesSafely(MyInjectPropSpec.Kettle item) {
return Math.abs(item.temperatureCelsius - 92f) < 0.1;
}
})
.build();

assertThat(c, component).has(deepSubComponentWith(c, matcher));
}

The above example shows how tests written for injected props are almost the same as normal props. The Kettle object is instantiated with a temperature, which is verified using a custom matcher.

Testing Injected Components​

Components can also be @InjectProps, as shown in the following LayoutSpec:

@LayoutSpec
class MyInjectPropSpec {
@OnCreateLayout
static Component onCreateLayout(
ComponentContext c,
@InjectProp Text injectedComponent) {
return Column.create(c).child(injectedComponent).build();
}
}

Assert if MyInjectProp is mounted with the injected Text component:

@Test
public void whenMyInjectPropComponentIsRendered_shouldUseProvidedInjectedComponent() {
final ComponentContext c = mLithoViewRule.getContext();
final MyInjectProp component = MyInjectProp.create(c).build();

component.injectedComponent = Text.create(c).text("injected text").build();

final Condition<InspectableComponent> matcher =
TestMyInjectProp.matcher(c)
.injectedComponent(TestText.matcher(c).text("injected text").build())
.build();

assertThat(c, component).has(deepSubComponentWith(c, matcher));
}