Commit 420d83ba authored by Eric Aleshire's avatar Eric Aleshire Committed by Commit Bot

Add the "autofill" automation action to the iOS EG Autofill automation tests.

This action performs the actual autofilling of the form, by selecting a specific
element in an autofillable form, then tapping on the autofill suggestion.

The profile data used to autofill is hardcoded in this file for now. uwyiming@
may have plans to move this profile data into the test recipe in the future, but
for now this is sufficient.

Additionally, I move some shared code between the click and autofill actions to
a base class.

I tested this action using a recipe I wrote against Walmart's shop page.

Bug: 881096
Cq-Include-Trybots: luci.chromium.try:ios-simulator-cronet;luci.chromium.try:ios-simulator-full-configs
Change-Id: I9629a11da48a3910c1765f455491456005aada75
Reviewed-on: https://chromium-review.googlesource.com/1208141
Commit-Queue: ericale <ericale@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Reviewed-by: default avatarEric Noyau <noyau@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590452}
parent c12c50e9
......@@ -14,8 +14,11 @@ source_set("eg_tests") {
deps = [
"//base",
"//components/autofill/core/browser:browser",
"//components/autofill/ios/browser:browser",
"//components/strings",
"//ios/chrome/app/strings",
"//ios/chrome/browser/autofill:autofill",
"//ios/chrome/browser/infobars",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/infobars:test_support",
......
......@@ -6,9 +6,15 @@
#import "ios/chrome/browser/autofill/automation/automation_action.h"
#include "base/guid.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/ios/browser/autofill_driver_ios.h"
#import "ios/chrome/browser/autofill/form_suggestion_label.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/web/public/test/earl_grey/web_view_actions.h"
......@@ -48,7 +54,7 @@ using web::test::ElementSelector;
// "selector": "//*[@id=\"add-to-cart-button\"]",
// "context": [],
// "type": "click"
// },
// }
@interface AutomationActionClick : AutomationAction
@end
......@@ -59,10 +65,22 @@ using web::test::ElementSelector;
// "type": "waitFor",
// "assertions": ["return document.querySelector().style.display ===
// 'none';"]
// },
// }
@interface AutomationActionWaitFor : AutomationAction
@end
// An action that performs autofill on a form by selecting an element
// that is part of an autofillable form, then tapping the relevant
// autofill suggestion. We assume this action has a format resembling:
// {
// "selectorType": "xpath",
// "selector": "//*[@data-tl-id=\"COAC2ShpAddrFirstName\"]",
// "context": [],
// "type": "autofill"
// }
@interface AutomationActionAutofill : AutomationAction
@end
@implementation AutomationAction
+ (instancetype)actionWithValueDictionary:
......@@ -82,6 +100,7 @@ using web::test::ElementSelector;
static NSDictionary* classForType = @{
@"click" : [AutomationActionClick class],
@"waitFor" : [AutomationActionWaitFor class],
@"autofill" : [AutomationActionAutofill class],
// More to come.
};
......@@ -105,19 +124,9 @@ using web::test::ElementSelector;
return actionDictionary_;
}
@end
@implementation AutomationActionClick
- (void)execute {
const base::Value* xpathValue(self.actionDictionary->FindKeyOfType(
"selector", base::Value::Type::STRING));
GREYAssert(xpathValue, @"Selector is missing in action.");
const std::string xpath(xpathValue->GetString());
GREYAssert(!xpath.empty(), @"selector is an empty value.");
auto selector(ElementSelector::ElementSelectorXPath(xpath));
// A shared flow across many actions, this waits for the target element to be
// visible, scrolls it into view, then taps on it.
- (void)tapOnTarget:(web::test::ElementSelector)selector {
web::WebState* web_state = chrome_test_util::GetCurrentWebState();
// Wait for the element to be visible on the page.
......@@ -130,6 +139,30 @@ using web::test::ElementSelector;
performAction:web::WebViewTapElement(web_state, selector)];
}
// Creates a selector targeting the element specified in the action.
- (web::test::ElementSelector)selectorForTarget {
const base::Value* xpathValue(self.actionDictionary->FindKeyOfType(
"selector", base::Value::Type::STRING));
GREYAssert(xpathValue, @"Selector is missing in action.");
const std::string xpath(xpathValue->GetString());
GREYAssert(!xpath.empty(), @"selector is an empty value.");
// Creates a selector from the action dictionary.
web::test::ElementSelector selector(
ElementSelector::ElementSelectorXPath(xpath));
return selector;
}
@end
@implementation AutomationActionClick
- (void)execute {
web::test::ElementSelector selector = [self selectorForTarget];
[self tapOnTarget:selector];
}
@end
@implementation AutomationActionWaitFor
......@@ -188,6 +221,51 @@ using web::test::ElementSelector;
@end
@implementation AutomationActionAutofill
static const char PROFILE_NAME_FULL[] = "Yuki Nagato";
static const char PROFILE_HOME_LINE1[] = "1600 Amphitheatre Parkway";
static const char PROFILE_HOME_CITY[] = "Mountain View";
static const char PROFILE_HOME_STATE[] = "CA";
static const char PROFILE_HOME_ZIP[] = "94043";
// Loads the predefined autofill profile into the personal data manager, so that
// autofill actions will be suggested when tapping on an autofillable form.
- (void)prepareAutofillProfileWithWebState:(web::WebState*)web_state {
autofill::AutofillManager* autofill_manager =
autofill::AutofillDriverIOS::FromWebState(web_state)->autofill_manager();
autofill::PersonalDataManager* personal_data_manager =
autofill_manager->client()->GetPersonalDataManager();
autofill::AutofillProfile profile(base::GenerateGUID(),
"https://www.example.com/");
profile.SetRawInfo(autofill::NAME_FULL, base::UTF8ToUTF16(PROFILE_NAME_FULL));
profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1,
base::UTF8ToUTF16(PROFILE_HOME_LINE1));
profile.SetRawInfo(autofill::ADDRESS_HOME_CITY,
base::UTF8ToUTF16(PROFILE_HOME_CITY));
profile.SetRawInfo(autofill::ADDRESS_HOME_STATE,
base::UTF8ToUTF16(PROFILE_HOME_STATE));
profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP,
base::UTF8ToUTF16(PROFILE_HOME_ZIP));
personal_data_manager->SaveImportedProfile(profile);
}
- (void)execute {
web::WebState* web_state = chrome_test_util::GetCurrentWebState();
[self prepareAutofillProfileWithWebState:web_state];
web::test::ElementSelector selector = [self selectorForTarget];
[self tapOnTarget:selector];
// Tap on the autofill suggestion to perform the actual autofill.
[[EarlGrey
selectElementWithMatcher:grey_accessibilityID(
kFormSuggestionLabelAccessibilityIdentifier)]
performAction:grey_tap()];
}
@end
@implementation AutomationActionUnrecognized
- (void)execute {
......
......@@ -7,6 +7,8 @@
#import <UIKit/UIKit.h>
// a11y identifier used to locate the autofill suggestion in automation
extern NSString* const kFormSuggestionLabelAccessibilityIdentifier;
@class FormSuggestion;
@protocol FormSuggestionViewClient;
......
......@@ -26,6 +26,10 @@
#error "This file requires ARC support."
#endif
// a11y identifier used to locate the autofill suggestion in automation
NSString* const kFormSuggestionLabelAccessibilityIdentifier =
@"formSuggestionLabelAXID";
namespace {
// The button corner radius.
......@@ -133,6 +137,8 @@ UILabel* TextLabel(NSString* text, CGFloat alpha, BOOL bold) {
suggestion.displayDescription),
base::IntToString16(index + 1),
base::IntToString16(numSuggestions))];
[self
setAccessibilityIdentifier:kFormSuggestionLabelAccessibilityIdentifier];
}
return self;
......
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