Skip to main content

Matching @InjectProp

note

Checkout the getting started section to setup the test environment correctly.

tip

Checkout the sub-component testing, and Prop Matching section before diving into @InjectProp testing.

Testing injected props#

@InjectProp earmarks props to be provided by the client's dependency injection framework. Components which 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) {
// ...
}
}
  • Create a @TestSpec for MyInjectPropSpec
@TestSpec(MyInjectPropSpec.class)
public interface TestMyInjectPropSpec {}
  • Add @RunWith(LithoTestRunner.class) to the top of the test class.
  • Add a JUnit @Rule LithoViewRule.
  • 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)
);
}
}
  • 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 example shows how tests written for injected props are almost the same as normal props. The Kettle object is instantiated with a temperature, that is verified using a custom matcher.

Testing injected components#

Components can also be @InjectProps. Consider 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));
}