Commit 0a7e8c38 authored by zhaoyangli's avatar zhaoyangli Committed by Commit Bot

Make autofill automation EG2 compatible and create eg2test target.

This is the major change for autofill automation EG2 migration.

- Separated test and app side code in former automation_egtest.mm by
creating private helper function and app interface for app side calls.
|NSString*| and |NSError*| are communicated between test and app. App
interface code is mostly migrated from automation_egtest.mm with minor
changes:
  - |GREYAssert|s are changed to |NSError*| to be sent back to test.
  - Moved some instance variable and methods to static variable and
  functions.

- Overrode |launchAppForTestMethod| in |AutofillAutomationTestCase| to
start app with needed features.

- Created eg2test target and eg_app_support+eg2 target in automation
BUILD.gn. Created new eg2tests_module and included new eg2test target
in earlgrey2 BUILD.gn.

- Removed unused headers in code and unused deps from build file.


Bug: 987646, 1003605
Change-Id: I22ae675848bd1b08df9cdb375a6dcfb2f42b8c75
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1850739
Commit-Queue: Zhaoyang Li <zhaoyangli@chromium.org>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706954}
parent 6112a794
......@@ -10,32 +10,86 @@ source_set("eg_tests") {
"automation_action.h",
"automation_action.mm",
"automation_action_egtest.mm",
"automation_app_interface.h",
"automation_app_interface.mm",
"automation_egtest.mm",
]
deps = [
"//base",
"//components/autofill/core/browser:browser",
"//components/autofill/core/browser",
"//components/autofill/ios/browser",
"//components/autofill/ios/browser:autofill_test_bundle_data",
"//components/autofill/ios/browser:browser",
"//components/strings",
"//ios/chrome/app/strings",
"//ios/chrome/browser/autofill:autofill",
"//ios/chrome/browser/infobars",
"//ios/chrome/browser/ui/infobars:infobars_ui",
"//ios/chrome/browser/ui/infobars:test_support",
"//ios/chrome/browser/ui/toolbar/buttons",
"//ios/chrome/browser/ui/toolbar/public",
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/autofill",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/ui/infobars:constants",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support",
"//ios/testing/earl_grey:earl_grey_support",
"//ios/web:earl_grey_test_support",
"//ios/web/public/js_messaging",
"//ios/web/public/test:element_selector",
"//ios/web/public/test/http_server:http_server",
"//ui/base",
]
libs = [ "XCTest.framework" ]
}
source_set("eg2_tests") {
defines = [ "CHROME_EARL_GREY_2" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
testonly = true
sources = [
"automation_action.h",
"automation_action.mm",
"automation_action_egtest.mm",
"automation_app_interface.h",
"automation_egtest.mm",
]
deps = [
"//base",
"//base/test:test_support",
"//components/autofill/core/browser",
"//components/autofill/ios/browser:autofill_test_bundle_data",
"//components/strings",
"//ios/chrome/app/strings",
"//ios/chrome/browser/autofill:constants",
"//ios/chrome/browser/ui/infobars:constants",
"//ios/chrome/test/earl_grey:eg_test_support+eg2",
"//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib",
"//ios/web/public/test:element_selector",
"//net:test_support",
]
libs = [ "XCTest.framework" ]
}
source_set("eg_app_support+eg2") {
defines = [ "CHROME_EARL_GREY_2" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
testonly = true
sources = [
"automation_app_interface.h",
"automation_app_interface.mm",
]
deps = [
"//base",
"//components/autofill/core/browser",
"//components/autofill/ios/browser",
"//components/strings",
"//ios/chrome/app/strings",
"//ios/chrome/browser/autofill",
"//ios/chrome/browser/browser_state",
"//ios/chrome/test/app:test_support",
"//ios/testing:nserror_support",
"//ios/testing/earl_grey:eg_app_support+eg2",
"//ios/web/public",
"//ios/web/public/js_messaging",
]
libs = [ "XCTest.framework" ]
}
// 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.
#ifndef IOS_CHROME_BROWSER_AUTOFILL_AUTOMATION_AUTOMATION_APP_INTERFACE_H_
#define IOS_CHROME_BROWSER_AUTOFILL_AUTOMATION_AUTOMATION_APP_INTERFACE_H_
#import <Foundation/Foundation.h>
// AutomationAppInterface contains the app-side implementations for
// automation_egtest helpers which involve app-side classes.
@interface AutomationAppInterface : NSObject
// Sets autofill automation profile data in app side. Passes JSON format
// NSString to app side, extracts and sets autofill profile in app side.
+ (NSError*)setAutofillAutomationProfile:(NSString*)profileJSON;
@end
#endif // IOS_CHROME_BROWSER_AUTOFILL_AUTOMATION_AUTOMATION_APP_INTERFACE_H_
// 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.
#import "ios/chrome/browser/autofill/automation/automation_app_interface.h"
#include "base/guid.h"
#include "base/json/json_reader.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/testing/nserror_util.h"
#import "ios/web/public/js_messaging/web_frames_manager.h"
#import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using autofill::PersonalDataManager;
using autofill::PersonalDataManagerFactory;
namespace {
// Converts a string (from the test recipe) to the autofill ServerFieldType it
// represents.
autofill::ServerFieldType ServerFieldTypeFromString(const std::string& str,
NSError** error) {
static std::map<const std::string, autofill::ServerFieldType>
string_to_field_type_map;
// Only init the string to autofill field type map on the first call.
// The test recipe can contain both server and html field types, as when
// creating the recipe either type can be returned from predictions.
// Therefore, store both in this map.
if (string_to_field_type_map.empty()) {
for (size_t i = autofill::NO_SERVER_DATA;
i < autofill::MAX_VALID_FIELD_TYPE; ++i) {
autofill::AutofillType autofill_type(
static_cast<autofill::ServerFieldType>(i));
string_to_field_type_map[autofill_type.ToString()] =
autofill_type.GetStorableType();
}
for (size_t i = autofill::HTML_TYPE_UNSPECIFIED;
i < autofill::HTML_TYPE_UNRECOGNIZED; ++i) {
autofill::AutofillType autofill_type(
static_cast<autofill::HtmlFieldType>(i), autofill::HTML_MODE_NONE);
string_to_field_type_map[autofill_type.ToString()] =
autofill_type.GetStorableType();
}
}
if (string_to_field_type_map.find(str) == string_to_field_type_map.end()) {
NSString* error_description = [NSString
stringWithFormat:@"Unable to recognize autofill field type %@!",
base::SysUTF8ToNSString(str)];
*error = testing::NSErrorWithLocalizedDescription(error_description);
return autofill::UNKNOWN_TYPE;
}
return string_to_field_type_map[str];
}
// Loads the defined autofill profile into the personal data manager, so that
// autofill actions will be suggested when tapping on an autofillable form.
// The autofill profile should be pulled from the test recipe, and consists of
// a list of dictionaries, each mapping one autofill type to one value, like so:
// "autofillProfile": [
// { "type": "NAME_FIRST", "value": "Satsuki" },
// { "type": "NAME_LAST", "value": "Yumizuka" },
// ],
NSError* PrepareAutofillProfileWithValues(const base::Value* autofill_profile) {
if (!autofill_profile) {
return testing::NSErrorWithLocalizedDescription(
@"Unable to find autofill profile in parsed JSON value.");
}
autofill::AutofillProfile profile(base::GenerateGUID(),
"https://www.example.com/");
autofill::CreditCard credit_card(base::GenerateGUID(),
"https://www.example.com/");
base::span<const base::Value> profile_entries_list =
autofill_profile->GetList();
// For each type-value dictionary in the autofill profile list, validate it,
// then add it to the appropriate profile.
for (const auto& it_entry : profile_entries_list) {
const base::DictionaryValue* entry = nullptr;
if (!it_entry.GetAsDictionary(&entry)) {
return testing::NSErrorWithLocalizedDescription(
@"Failed to extract an entry!");
}
const base::Value* type_container = entry->FindKey("type");
if (base::Value::Type::STRING != type_container->type()) {
return testing::NSErrorWithLocalizedDescription(@"Type is not a string!");
}
const base::Value* value_container = entry->FindKey("value");
if (base::Value::Type::STRING != value_container->type()) {
return testing::NSErrorWithLocalizedDescription(
@"Value is not a string!");
}
const std::string field_type = type_container->GetString();
NSError* error = nil;
autofill::ServerFieldType type =
ServerFieldTypeFromString(field_type, &error);
if (error) {
return error;
}
// TODO(crbug.com/895968): Autofill profile and credit card info should be
// loaded from separate fields in the recipe, instead of being grouped
// together. However, need to make sure this change is also performed on
// desktop automation.
const std::string field_value = value_container->GetString();
if (base::StartsWith(field_type, "HTML_TYPE_CREDIT_CARD_",
base::CompareCase::INSENSITIVE_ASCII) ||
base::StartsWith(field_type, "CREDIT_CARD_",
base::CompareCase::INSENSITIVE_ASCII)) {
credit_card.SetRawInfo(type, base::UTF8ToUTF16(field_value));
} else {
profile.SetRawInfo(type, base::UTF8ToUTF16(field_value));
}
}
// Save the profile and credit card generated to the personal data manager.
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
PersonalDataManager* personal_data_manager =
PersonalDataManagerFactory::GetForBrowserState(browser_state);
personal_data_manager->ClearAllLocalData();
personal_data_manager->AddCreditCard(credit_card);
personal_data_manager->SaveImportedProfile(profile);
return nil;
}
} // namespace
@implementation AutomationAppInterface
+ (NSError*)setAutofillAutomationProfile:(NSString*)profileJSON {
base::Optional<base::Value> readResult =
base::JSONReader::Read(base::SysNSStringToUTF8(profileJSON));
if (!readResult.has_value()) {
return testing::NSErrorWithLocalizedDescription(
@"Unable to parse JSON string in app side.");
}
base::Value recipeRoot = std::move(readResult).value();
const base::Value* autofillProfile =
recipeRoot.FindKeyOfType("autofillProfile", base::Value::Type::LIST);
return PrepareAutofillProfileWithValues(autofillProfile);
}
@end
......@@ -346,6 +346,7 @@ source_set("eg_app_support+eg2") {
"//components/unified_consent",
"//ios/chrome/app/strings",
"//ios/chrome/browser/autofill",
"//ios/chrome/browser/autofill/automation:eg_app_support+eg2",
"//ios/chrome/browser/content_settings:content_settings",
"//ios/chrome/browser/ntp:features",
"//ios/chrome/browser/ui:feature_flags",
......
......@@ -9,6 +9,7 @@ import("//ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni")
group("all_tests") {
testonly = true
deps = [
":ios_chrome_autofill_automation_eg2tests_module",
":ios_chrome_eg2tests",
":ios_chrome_smoke_eg2tests_module",
":ios_chrome_ui_eg2tests_module",
......@@ -19,6 +20,14 @@ group("all_tests") {
chrome_ios_eg2_test_app_host("ios_chrome_eg2tests") {
}
chrome_ios_eg2_test("ios_chrome_autofill_automation_eg2tests_module") {
xcode_test_application_name = "ios_chrome_eg2tests"
deps = [
"//ios/chrome/browser/autofill/automation:eg2_tests",
]
}
chrome_ios_eg2_test("ios_chrome_smoke_eg2tests_module") {
xcode_test_application_name = "ios_chrome_eg2tests"
......
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