Commit bc3854ab authored by Clemens Arbesser's avatar Clemens Arbesser Committed by Commit Bot

[Autofill Assistant] Add support for response checking to integration tests.

This CL extends the java test service:
- Test scripts can now contain more than one round trip, which will allow us to test complete flows.
- Tests can now inspect and test the results of actions which would otherwise be sent to the backend.

This CL includes a first proof-of-concept for how to use the new methods, but we should extend all our existing integration tests in the near future.

Bug: b/144978160
Change-Id: I8188a50f0c600acecc687ad58cd4612d767a6dd0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1953109
Commit-Queue: Clemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarMathias Carlen <mcarlen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#722432}
parent 5b1cc6d1
......@@ -207,6 +207,7 @@ android_library("autofill_assistant_java_test_support") {
":test_support_jni_headers",
"//base:jni_java",
"//components/autofill_assistant/browser:proto_java",
"//content/public/test/android:content_java_test_support",
"//third_party/android_deps:com_google_protobuf_protobuf_lite_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
......
......@@ -13,6 +13,7 @@ import static android.support.test.espresso.intent.Intents.intending;
import static android.support.test.espresso.intent.matcher.IntentMatchers.anyIntent;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.hasSibling;
import static android.support.test.espresso.matcher.ViewMatchers.hasTextColor;
......@@ -23,6 +24,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.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.hasTintColor;
......@@ -56,6 +58,8 @@ import org.chromium.chrome.browser.autofill_assistant.proto.FormProto;
import org.chromium.chrome.browser.autofill_assistant.proto.InfoPopupProto;
import org.chromium.chrome.browser.autofill_assistant.proto.InfoPopupProto.DialogButton;
import org.chromium.chrome.browser.autofill_assistant.proto.InfoPopupProto.DialogButton.OpenUrlInCCT;
import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionProto;
import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionStatusProto;
import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto;
import org.chromium.chrome.browser.autofill_assistant.proto.PromptProto.Choice;
import org.chromium.chrome.browser.autofill_assistant.proto.SelectionInputProto;
......@@ -68,6 +72,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Tests autofill assistant bottomsheet.
......@@ -90,6 +95,10 @@ public class AutofillAssistantFormActionTest {
mTestRule.getActivity().getScrim().disableAnimationForTesting(true);
}
/**
* Creates a close-to-real example of a form action with multiple counters and choices,
* interacts with those widgets, and then checks the response to the server.
*/
@Test
@MediumTest
@DisableIf.Build(sdk_is_less_than = 21)
......@@ -143,16 +152,6 @@ public class AutofillAssistantFormActionTest {
.setForm(formProto))
.build());
// Prompt.
list.add((ActionProto) ActionProto.newBuilder()
.setPrompt(PromptProto.newBuilder()
.setMessage("Finished")
.addChoices(Choice.newBuilder().setChip(
ChipProto.newBuilder()
.setType(ChipType.DONE_ACTION)
.setText("End"))))
.build());
AutofillAssistantTestScript script = new AutofillAssistantTestScript(
(SupportedScriptProto) SupportedScriptProto.newBuilder()
.setPath("autofill_assistant_target_website.html")
......@@ -176,6 +175,7 @@ public class AutofillAssistantFormActionTest {
onView(allOf(isDisplayed(), withId(R.id.decrease_button),
hasSibling(hasDescendant(withText("Counter 1")))))
.check(matches(hasTintColor(R.color.modern_grey_800_alpha_38)));
// Click on Counter 1 +, increase from 0 to 1.
onView(allOf(isDisplayed(), withId(R.id.increase_button),
hasSibling(hasDescendant(withText("Counter 1")))))
.perform(click());
......@@ -187,23 +187,69 @@ public class AutofillAssistantFormActionTest {
.check(matches(hasTintColor(R.color.modern_grey_800_alpha_38)));
// Decrease button is still disabled due to the minCountersSum requirement.
// Click expand label to make Counter 2 visible.
onView(allOf(isDisplayed(), withId(R.id.expand_label))).perform(click());
// Click on Counter 3 +, increase from 0 to 1.
onView(allOf(isDisplayed(), withId(R.id.increase_button),
hasSibling(hasDescendant(withText("Counter 3")))))
.perform(click());
// Click on Choice 1, toggle to 'checked'.
onView(allOf(isDisplayed(), withId(R.id.checkbox),
hasSibling(hasDescendant(withText("Choice 1")))))
.perform(click());
// Click on Counter 2 +, increase from 0 to 1.
onView(allOf(isDisplayed(), withId(R.id.increase_button),
hasSibling(hasDescendant(withText("Counter 2")))))
.perform(click());
// Finish form action, wait for response and prepare next set of actions.
List<ActionProto> nextActions = new ArrayList<>();
nextActions.add((ActionProto) ActionProto.newBuilder()
.setPrompt(PromptProto.newBuilder()
.setMessage("Finished")
.addChoices(Choice.newBuilder().setChip(
ChipProto.newBuilder()
.setType(ChipType.DONE_ACTION)
.setText("End"))))
.build());
testService.setNextActions(nextActions);
waitUntilViewMatchesCondition(withText("Continue"), isEnabled());
int numNextActionsCalled = testService.getNextActionsCounter();
onView(withText("Continue")).perform(click());
testService.waitUntilGetNextActions(numNextActionsCalled + 1);
List<ProcessedActionProto> processedActions = testService.getProcessedActions();
assertThat(processedActions.size(), is(1));
assertThat(
processedActions.get(0).getStatus(), is(ProcessedActionStatusProto.ACTION_APPLIED));
assertThat(processedActions.get(0).getResultDataCase(),
is(ProcessedActionProto.ResultDataCase.FORM_RESULT));
List<FormInputProto.Result> formResult =
processedActions.get(0).getFormResult().getInputResultsList();
assertThat(formResult.size(), is(3));
assertThat(formResult.get(0).getInputTypeCase(),
is(FormInputProto.Result.InputTypeCase.COUNTER));
assertThat(formResult.get(0).getCounter().getValuesCount(), is(2));
// Counter 1
assertThat(formResult.get(0).getCounter().getValues(0), is(1));
// Counter 2
assertThat(formResult.get(0).getCounter().getValues(1), is(1));
// Choice 1
assertThat(formResult.get(1).getInputTypeCase(),
is(FormInputProto.Result.InputTypeCase.SELECTION));
assertThat(formResult.get(1).getSelection().getSelectedCount(), is(1));
assertThat(formResult.get(1).getSelection().getSelected(0), is(true));
// Counter 3
assertThat(formResult.get(2).getInputTypeCase(),
is(FormInputProto.Result.InputTypeCase.COUNTER));
assertThat(formResult.get(2).getCounter().getValuesCount(), is(1));
assertThat(formResult.get(2).getCounter().getValues(0), is(1));
waitUntilViewMatchesCondition(withText("End"), isCompletelyDisplayed());
// TODO(b/144978160): check that the values were correctly written to the action response.
}
@Test
......
......@@ -5,8 +5,11 @@
package org.chromium.chrome.browser.autofill_assistant;
import org.chromium.chrome.browser.autofill_assistant.proto.ActionsResponseProto;
import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionProto;
import org.chromium.chrome.browser.autofill_assistant.proto.SupportsScriptResponseProto;
import java.util.List;
/**
* Interface for a Java-side autofill assistant service.
*/
......@@ -28,5 +31,6 @@ public interface AutofillAssistantService {
* Get next sequence of actions according to server payloads in previous response.
* @return the response proto of the service.
*/
ActionsResponseProto getNextActions(byte[] globalPayload, byte[] scriptPayload);
ActionsResponseProto getNextActions(byte[] globalPayload, byte[] scriptPayload,
List<ProcessedActionProto> processedActions);
}
......@@ -4,14 +4,23 @@
package org.chromium.chrome.browser.autofill_assistant;
import android.support.annotation.Nullable;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
import org.chromium.chrome.browser.autofill_assistant.proto.ActionsResponseProto;
import org.chromium.chrome.browser.autofill_assistant.proto.ProcessedActionProto;
import org.chromium.chrome.browser.autofill_assistant.proto.SupportsScriptResponseProto;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
......@@ -22,6 +31,10 @@ public class AutofillAssistantTestService
implements AutofillAssistantService,
AutofillAssistantServiceInjector.NativeServiceProvider {
private final List<AutofillAssistantTestScript> mScripts;
private List<ActionProto> mNextActions = Collections.emptyList();
/** The most recently received list of processed actions. */
private @Nullable List<ProcessedActionProto> mProcessedActions;
private int mNextActionsCounter;
AutofillAssistantTestService(List<AutofillAssistantTestScript> scripts) {
mScripts = scripts;
......@@ -35,6 +48,14 @@ public class AutofillAssistantTestService
AutofillAssistantServiceInjector.setServiceToInject(this);
}
/**
* Sets the actions that will be returned for the next (and only the next) call to {@code
* getNextActions}.
*/
void setNextActions(List<ActionProto> nextActions) {
mNextActions = nextActions;
}
@Override
public long createNativeService() {
// Ask native to create and return a wrapper around |this|. The wrapper will be injected
......@@ -72,10 +93,56 @@ public class AutofillAssistantTestService
return ActionsResponseProto.getDefaultInstance();
}
/** @see AutofillAssistantService#getNextActions(byte[], byte[]) */
/** @see AutofillAssistantService#getNextActions(byte[], byte[], List) */
@Override
public ActionsResponseProto getNextActions(byte[] globalPayload, byte[] scriptPayload) {
return ActionsResponseProto.getDefaultInstance();
public ActionsResponseProto getNextActions(byte[] globalPayload, byte[] scriptPayload,
List<ProcessedActionProto> processedActions) {
mProcessedActions = processedActions;
mNextActionsCounter++;
ActionsResponseProto responseProto =
(ActionsResponseProto) ActionsResponseProto.newBuilder()
.addAllActions(mNextActions)
.setGlobalPayload(ByteString.copyFrom(globalPayload))
.setScriptPayload(ByteString.copyFrom(scriptPayload))
.build();
mNextActions = Collections.emptyList();
return responseProto;
}
/** Returns how many times {@code getNextActions} has been called. */
public int getNextActionsCounter() {
return mNextActionsCounter;
}
/**
* Synchronously waits until {@code getNextActions} was called at least @{code
* targetNextActionsCount} times. After this method returns, the list of the most recently
* returned {@code ProcessedActionProto} can be queried via {@see
* AutofillAssistantTestService#getProcessedActions}.
*/
public void waitUntilGetNextActions(int targetNextActionsCount) {
CriteriaHelper.pollInstrumentationThread(
new Criteria("Timeout while waiting for getNextActions") {
@Override
public boolean isSatisfied() {
return mNextActionsCounter >= targetNextActionsCount;
}
});
}
/** Access to the most recently received list of processed actions. Is initially null. */
public @Nullable List<ProcessedActionProto> getProcessedActions() {
return mProcessedActions;
}
@CalledByNative
private static List<byte[]> createProcessedActionsList() {
return new ArrayList<>();
}
@CalledByNative
private static void addProcessedAction(List<byte[]> list, byte[] serializedProto) {
list.add(serializedProto);
}
@CalledByNative
......@@ -90,8 +157,17 @@ public class AutofillAssistantTestService
}
@CalledByNative
private byte[] getNextActionsNative(byte[] globalPayload, byte[] scriptPayload) {
return getNextActions(globalPayload, scriptPayload).toByteArray();
private byte[] getNextActionsNative(
byte[] globalPayload, byte[] scriptPayload, List<byte[]> processedActions) {
List<ProcessedActionProto> actions = new ArrayList<>();
try {
for (int i = 0; i < processedActions.size(); ++i) {
actions.add(ProcessedActionProto.parseFrom(processedActions.get(i)));
}
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
return getNextActions(globalPayload, scriptPayload, actions).toByteArray();
}
@NativeMethods
......
......@@ -65,10 +65,21 @@ void JavaService::GetNextActions(
const std::vector<ProcessedActionProto>& processed_actions,
ResponseCallback callback) {
JNIEnv* env = base::android::AttachCurrentThread();
auto jprocessed_actions =
Java_AutofillAssistantTestService_createProcessedActionsList(env);
for (const auto& action : processed_actions) {
std::string serialized_proto;
bool success = action.SerializeToString(&serialized_proto);
DCHECK(success);
Java_AutofillAssistantTestService_addProcessedAction(
env, jprocessed_actions,
base::android::ToJavaByteArray(env, serialized_proto));
}
auto jresponse = Java_AutofillAssistantTestService_getNextActionsNative(
env, java_service_,
base::android::ToJavaByteArray(env, previous_global_payload),
base::android::ToJavaByteArray(env, previous_script_payload));
base::android::ToJavaByteArray(env, previous_script_payload),
jprocessed_actions);
std::string response;
base::android::JavaByteArrayToString(env, jresponse, &response);
std::move(callback).Run(true, response);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment