blob: 4431bccc5f91cbc7b06cd73c6476999aeaacf94e [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.autofill_assistant;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.hasTypefaceSpan;
import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.hasTypefaceStyle;
import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.isImportantForAccessibility;
import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.isTextMaxLines;
import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.support.test.InstrumentationRegistry;
import android.view.View;
import androidx.test.filters.MediumTest;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.autofill_assistant.R;
import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetails;
import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsCoordinator;
import org.chromium.chrome.browser.autofill_assistant.details.AssistantDetailsModel;
import org.chromium.chrome.browser.autofill_assistant.details.AssistantPlaceholdersConfiguration;
import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.Arrays;
/** Tests for the Autofill Assistant details. */
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@RunWith(ChromeJUnit4ClassRunner.class)
public class AutofillAssistantDetailsUiTest {
public static final AssistantPlaceholdersConfiguration NO_PLACEHOLDERS =
new AssistantPlaceholdersConfiguration(
/* showImagePlaceholder= */ false,
/* showTitlePlaceholder= */ false,
/* showDescriptionLine1Placeholder= */ false,
/* showDescriptionLine2Placeholder= */ false,
/* showDescriptionLine3Placeholder= */ false);
@Rule
public CustomTabActivityTestRule mTestRule = new CustomTabActivityTestRule();
/**
* Matchers for the different views of a single details item in the details list. We need to use
* matchers (instead of directly querying with findViewById) because the inflation of the
* details views if postponed to the UI-thread when adding items to the list, so we can't assume
* that the details views are available directly after adding items to the details list.
*/
private static class ViewMatchers {
final Matcher<View> mImageView;
final Matcher<View> mTitleView;
final Matcher<View> mDescriptionLine1View;
final Matcher<View> mDescriptionLine2View;
final Matcher<View> mDescriptionLine3View;
final Matcher<View> mPriceAttributionView;
final Matcher<View> mPriceView;
final Matcher<View> mTotalPriceLabelView;
final Matcher<View> mTotalPriceView;
ViewMatchers(View detailsListView) {
mImageView = descendantWithId(detailsListView, R.id.details_image);
mTitleView = descendantWithId(detailsListView, R.id.details_title);
mDescriptionLine1View = descendantWithId(detailsListView, R.id.details_line1);
mDescriptionLine2View = descendantWithId(detailsListView, R.id.details_line2);
mDescriptionLine3View = descendantWithId(detailsListView, R.id.details_line3);
mPriceAttributionView =
descendantWithId(detailsListView, R.id.details_price_attribution);
mPriceView = descendantWithId(detailsListView, R.id.details_price);
mTotalPriceView = descendantWithId(detailsListView, R.id.details_total_price);
mTotalPriceLabelView =
descendantWithId(detailsListView, R.id.details_total_price_label);
}
private Matcher<View> descendantWithId(View ancestor, int id) {
return allOf(isDescendantOfA(is(ancestor)), withId(id));
}
}
private AssistantDetailsModel createModel() {
return TestThreadUtils.runOnUiThreadBlockingNoException(AssistantDetailsModel::new);
}
/** Creates a coordinator for use in UI tests, and adds it to the global view hierarchy. */
private AssistantDetailsCoordinator createCoordinator(AssistantDetailsModel model)
throws Exception {
AssistantDetailsCoordinator coordinator = runOnUiThreadBlocking(() -> {
Bitmap testImage = BitmapFactory.decodeResource(
mTestRule.getActivity().getResources(), R.drawable.btn_close);
return new AssistantDetailsCoordinator(InstrumentationRegistry.getTargetContext(),
model, new AutofillAssistantUiTestUtil.MockImageFetcher(testImage, null));
});
runOnUiThreadBlocking(()
-> AutofillAssistantUiTestUtil.attachToCoordinator(
mTestRule.getActivity(), coordinator.getView()));
return coordinator;
}
private static void setDetails(AssistantDetailsModel model, AssistantDetails... details) {
runOnUiThreadBlocking(() -> model.setDetailsList(Arrays.asList(details)));
// Wait for the main thread to be idle (i.e. the UI should be stable).
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@Before
public void setUp() {
mTestRule.startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
InstrumentationRegistry.getTargetContext(), "about:blank"));
}
/** Tests assumptions about the initial state of the details. */
@Test
@MediumTest
public void testInitialState() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
assertThat(model.get(AssistantDetailsModel.DETAILS).size(), is(0));
assertThat(coordinator.getView().getChildCount(), is(0));
}
/** Tests visibility of views. */
@Test
@MediumTest
public void testVisibility() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "", "line 3", false, false, false, false, false,
NO_PLACEHOLDERS));
onView(viewMatchers.mImageView).check(matches(isDisplayed()));
onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine1View).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine2View).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
onView(viewMatchers.mPriceView).check(matches(isDisplayed()));
onView(viewMatchers.mTotalPriceLabelView).check(matches(isDisplayed()));
onView(viewMatchers.mTotalPriceView).check(matches(isDisplayed()));
onView(viewMatchers.mPriceAttributionView).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testAccessibility() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "", "line 3", false, false, false, false, false,
NO_PLACEHOLDERS));
onView(viewMatchers.mImageView).check(matches(withContentDescription("hint")));
onView(viewMatchers.mImageView)
.check(matches(isImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO)));
}
@Test
@MediumTest
public void testAccessibilityEmpty() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
setDetails(model,
new AssistantDetails("title", "image", "", null, "Total", "$12", "line 1", "line 2",
"", "line 3", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mImageView).check(matches(withContentDescription("")));
onView(viewMatchers.mImageView)
.check(matches(isImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO)));
}
@Test
@MediumTest
public void testTitle() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Description lines 1 and 2 are set, title must be in single line. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "", "price", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(1)));
onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
/* Description line 1 is set, title must be max 2 lines. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1", "",
"", "price", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
/* Description line 2 is set, title must be max 2 lines. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "line 2",
"", "price", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
/* None of description line 1 or 2 is set, title must be max 3 lines. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
"price", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(3)));
onView(viewMatchers.mTitleView).check(matches(allOf(withText("title"), isDisplayed())));
/* There is a placeholder for description line 1, title must be max 2 lines. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
"price", false, false, false, false, false,
new AssistantPlaceholdersConfiguration(
/* showImagePlaceholder= */ false,
/* showTitlePlaceholder= */ false,
/* showDescriptionLine1Placeholder= */ true,
/* showDescriptionLine2Placeholder= */ false,
/* showDescriptionLine3Placeholder= */ false)));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(2)));
/* There is a placeholder for description line 1 & 2, title must be max 1 line. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
"price", false, false, false, false, false,
new AssistantPlaceholdersConfiguration(
/* showImagePlaceholder= */ false,
/* showTitlePlaceholder= */ false,
/* showDescriptionLine1Placeholder= */ true,
/* showDescriptionLine2Placeholder= */ true,
/* showDescriptionLine3Placeholder= */ false)));
onView(viewMatchers.mTitleView).check(matches(isTextMaxLines(1)));
}
@Test
@MediumTest
public void testDescriptionLine1() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Description line 1 is set and should be visible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "line 1", "", "", "",
false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine1View)
.check(matches(allOf(withText("line 1"), isDisplayed())));
/* Description line 1 is not set and should be invisible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine1View).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testDescriptionLine2() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Description line 2 is set and should be visible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "line 2", "", "",
false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine2View)
.check(matches(allOf(withText("line 2"), isDisplayed())));
/* Description line 2 is not set and should be invisible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine2View).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testDescriptionLine3() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Description line 3 is set and should be visible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "", "line 3", "",
false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine3View)
.check(matches(allOf(withText("line 3"), isDisplayed())));
/* Description line 3 is not set and should be invisible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "line 3",
false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testPriceAttribution() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Price attribution is set and should be visible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "", "", "",
"price attribution", false, false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mPriceAttributionView)
.check(matches(allOf(withText("price attribution"), isDisplayed())));
/* Price attribution is not set and should be invisible. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "", "", "", "", "", "", false,
false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mPriceAttributionView).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
public void testHighlighting() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
/* Check that title is highlighted. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "line 3", "Est. total", true, true, false, false, false,
NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
onView(viewMatchers.mDescriptionLine1View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine2View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine3View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mPriceAttributionView)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
/* Check that description 1 is highlighted. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "line 3", "Est. total", true, false, true, false, false,
NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine1View)
.check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
onView(viewMatchers.mDescriptionLine2View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine3View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mPriceAttributionView)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
/* Check that description 2 is highlighted. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "line 3", "Est. total", true, false, false, true, false,
NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine1View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine2View)
.check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
onView(viewMatchers.mDescriptionLine3View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mPriceAttributionView)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
/* Check that description 3 and price attribution are highlighted. */
setDetails(model,
new AssistantDetails("title", "image", "hint", null, "Total", "$12", "line 1",
"line 2", "line 3", "Est. total", true, false, false, false, true,
NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine1View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine2View)
.check(matches(not(hasTypefaceStyle(Typeface.BOLD_ITALIC))));
onView(viewMatchers.mDescriptionLine3View)
.check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
onView(viewMatchers.mPriceAttributionView)
.check(matches(hasTypefaceStyle(Typeface.BOLD_ITALIC)));
}
@Test
@MediumTest
public void testStyleSpans() throws Exception {
AssistantDetailsModel model = createModel();
createCoordinator(model);
setDetails(model,
new AssistantDetails("<b>title</b>", "image", "hint", null, "<b>Total</b>",
"<b>$12</b>", "<b>line 1</b>", "<b>line 2</b>", "", "<b>line 3</b>", false,
false, false, false, false, NO_PLACEHOLDERS));
onView(withText("title"))
.check(matches(hasTypefaceSpan(0, "title".length() - 1, Typeface.BOLD)));
onView(withText("Total"))
.check(matches(hasTypefaceSpan(0, "Total".length() - 1, Typeface.BOLD)));
onView(withText("$12"))
.check(matches(hasTypefaceSpan(0, "$12".length() - 1, Typeface.BOLD)));
onView(withText("line 1"))
.check(matches(hasTypefaceSpan(0, "line 1".length() - 1, Typeface.BOLD)));
onView(withText("line 2"))
.check(matches(hasTypefaceSpan(0, "line 2".length() - 1, Typeface.BOLD)));
onView(withText("line 3"))
.check(matches(hasTypefaceSpan(0, "line 3".length() - 1, Typeface.BOLD)));
}
@Test
@MediumTest
public void testPlaceholders() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
// Without placeholders, the image and descriptions are hidden. The title is always
// displayed.
setDetails(model,
new AssistantDetails("title", "", "hint", null, "", "", "", "", "", "", false,
false, false, false, false, NO_PLACEHOLDERS));
onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
onView(viewMatchers.mImageView).check(matches(not(isDisplayed())));
onView(viewMatchers.mDescriptionLine1View).check(matches(not(isDisplayed())));
onView(viewMatchers.mDescriptionLine2View).check(matches(not(isDisplayed())));
onView(viewMatchers.mDescriptionLine3View).check(matches(not(isDisplayed())));
// With placeholders, the image and descriptions are displayed.
setDetails(model,
new AssistantDetails("title", "", "hint", null, "", "", "", "", "", "", false,
false, false, false, false,
new AssistantPlaceholdersConfiguration(
/* showImagePlaceholder= */ true,
/* showTitlePlaceholder= */ true,
/* showDescriptionLine1Placeholder= */ true,
/* showDescriptionLine2Placeholder= */ true,
/* showDescriptionLine3Placeholder= */ true)));
onView(viewMatchers.mTitleView).check(matches(isDisplayed()));
onView(viewMatchers.mImageView).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine1View).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine2View).check(matches(isDisplayed()));
onView(viewMatchers.mDescriptionLine3View).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testMultipleDetails() throws Exception {
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
ViewMatchers viewMatchers = new ViewMatchers(coordinator.getView());
setDetails(model,
new AssistantDetails("title 1", "", "", null, "", "", "", "", "", "", false, false,
false, false, false, NO_PLACEHOLDERS),
new AssistantDetails("title 2", "", "", null, "", "", "", "", "", "", false, false,
false, false, false, NO_PLACEHOLDERS),
new AssistantDetails("title 3", "", "", null, "", "", "", "", "", "", false, false,
false, false, false, NO_PLACEHOLDERS));
onView(allOf(viewMatchers.mTitleView, withText("title 1"))).check(matches(isDisplayed()));
onView(allOf(viewMatchers.mTitleView, withText("title 2"))).check(matches(isDisplayed()));
onView(allOf(viewMatchers.mTitleView, withText("title 3"))).check(matches(isDisplayed()));
}
@Test
@MediumTest
public void testPlaceholdersAnimation() throws Exception {
// Test that the placeholders animation is running only when details have placeholders.
AssistantDetailsModel model = createModel();
AssistantDetailsCoordinator coordinator = createCoordinator(model);
assertThat(coordinator.isRunningPlaceholdersAnimationForTesting(), is(false));
setDetails(model,
new AssistantDetails("title 1", "", "", null, "", "", "", "", "", "", false, false,
false, false, false, NO_PLACEHOLDERS));
assertThat(coordinator.isRunningPlaceholdersAnimationForTesting(), is(false));
setDetails(model,
new AssistantDetails("title 1", "", "", null, "", "", "", "", "", "", false, false,
false, false, false,
new AssistantPlaceholdersConfiguration(
/* showImagePlaceholder= */ true,
/* showTitlePlaceholder= */ false,
/* showDescriptionLine1Placeholder= */ false,
/* showDescriptionLine2Placeholder= */ false,
/* showDescriptionLine3Placeholder= */ false)));
assertThat(coordinator.isRunningPlaceholdersAnimationForTesting(), is(true));
setDetails(model);
assertThat(coordinator.isRunningPlaceholdersAnimationForTesting(), is(false));
}
}