[iOS][Restore]Create an eg test for the restore promo
This test ensures that, if Chrome starts with an account, and we
simulate a post device restore, the promo to add back the account is
opened, and the continue button open the add account view.
This required a lot of preparation work. As far as I can see, promos
were generally not tested. I hope this CL will show to to proceed
to eg test them.
I also need to ensure to add a test switch whose behavior is the same
as the experimental flag to simulate post device restore. Indeed, we
want to test the same feature.
I need to sign-in at startup. Which currently most work after a restart and not the initial start.
Given that this alert is implemented as a promo, I also needed to
use `kEnableIPH` to allow this promo to be enabled. By default, they
all are disabled in eg tests.
To be more specific, they are all disabled by two switches.
I removed the second and redundant switch in crrev.com/c/6172453.
Change-Id: Ia4f8a35fcf226babfa1cda575a8e22a688c18a6a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6170430
Reviewed-by: Jérôme Lebel <jlebel@chromium.org>
Commit-Queue: Arthur Milchior <arthurmilchior@chromium.org>
Commit-Queue: Jérôme Lebel <jlebel@chromium.org>
Commit-Queue: David Roger <droger@chromium.org>
Auto-Submit: Arthur Milchior <arthurmilchior@chromium.org>
Reviewed-by: David Roger <droger@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1408636}
diff --git a/ios/chrome/app/perf_tests_hook.mm b/ios/chrome/app/perf_tests_hook.mm
index 03ef79f..8b3c913 100644
--- a/ios/chrome/app/perf_tests_hook.mm
+++ b/ios/chrome/app/perf_tests_hook.mm
@@ -67,6 +67,9 @@
policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() {
return nullptr;
}
+bool SimulatePostDeviceRestore() {
+ return false;
+}
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager() {
return nullptr;
}
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm
index 11bc671..ddbf9047 100644
--- a/ios/chrome/app/tests_fake_hook.mm
+++ b/ios/chrome/app/tests_fake_hook.mm
@@ -51,6 +51,9 @@
policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() {
return nullptr;
}
+bool SimulatePostDeviceRestore() {
+ return false;
+}
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager() {
return nullptr;
}
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h
index 4907beb..a6b5dcd 100644
--- a/ios/chrome/app/tests_hook.h
+++ b/ios/chrome/app/tests_hook.h
@@ -112,6 +112,11 @@
// provider when testing. May return nullptr.
policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider();
+// Whether a phone backup/restore state should be simulated for testing purpose.
+// Uses`experimental_flags::SimulatePostDeviceRestore()` to check whether this
+// feature should be enabled due to experimental feature.
+bool SimulatePostDeviceRestore();
+
// Allows overriding the SystemIdentityManager factory. The real factory will
// be used if this hook returns null.
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager();
diff --git a/ios/chrome/browser/post_restore_signin/ui_bundled/BUILD.gn b/ios/chrome/browser/post_restore_signin/ui_bundled/BUILD.gn
index 030771c..ac07be4 100644
--- a/ios/chrome/browser/post_restore_signin/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/post_restore_signin/ui_bundled/BUILD.gn
@@ -62,3 +62,22 @@
"//ui/base",
]
}
+
+source_set("eg2_tests") {
+ configs += [ "//build/config/ios:xctest_config" ]
+ testonly = true
+ sources = [ "post_restore_signin_egtest.mm" ]
+ deps = [
+ "//components/signin/public/base",
+ "//ios/chrome/app/strings",
+ "//ios/chrome/browser/authentication/ui_bundled:eg_test_support+eg2",
+ "//ios/chrome/browser/metrics/model:eg_test_support+eg2",
+ "//ios/chrome/browser/shared/public/features:system_flags",
+ "//ios/chrome/browser/signin/model:fake_system_identity",
+ "//ios/chrome/browser/signin/model:test_constants",
+ "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+ "//ios/chrome/test/earl_grey:switches",
+ "//ios/testing/earl_grey:eg_test_support+eg2",
+ "//ui/base",
+ ]
+}
diff --git a/ios/chrome/browser/post_restore_signin/ui_bundled/post_restore_signin_egtest.mm b/ios/chrome/browser/post_restore_signin/ui_bundled/post_restore_signin_egtest.mm
new file mode 100644
index 0000000..2b65ab1
--- /dev/null
+++ b/ios/chrome/browser/post_restore_signin/ui_bundled/post_restore_signin_egtest.mm
@@ -0,0 +1,116 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "components/signin/public/base/signin_metrics.h"
+#import "ios/chrome/browser/authentication/ui_bundled/expected_signin_histograms.h"
+#import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h"
+#import "ios/chrome/browser/metrics/model/metrics_app_interface.h"
+#import "ios/chrome/browser/shared/public/features/system_flags.h"
+#import "ios/chrome/browser/signin/model/fake_system_identity.h"
+#import "ios/chrome/browser/signin/model/test_constants.h"
+#import "ios/chrome/grit/ios_branded_strings.h"
+#import "ios/chrome/grit/ios_strings.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/chrome/test/earl_grey/test_switches.h"
+#import "ios/testing/earl_grey/app_launch_manager.h"
+#import "ios/testing/earl_grey/earl_grey_test.h"
+#import "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// The primary identity.
+FakeSystemIdentity* const kPrimaryIdentity = [FakeSystemIdentity fakeIdentity1];
+
+} // namespace
+
+@interface PostRestoreSigninTestCase : ChromeTestCase
+@end
+
+@implementation PostRestoreSigninTestCase
+
+- (void)setUp {
+ [super setUp];
+
+ [SigninEarlGrey signinWithFakeIdentity:kPrimaryIdentity];
+
+ // Create the config to relaunch Chrome.
+ AppLaunchConfiguration config;
+ config.relaunch_policy = ForceRelaunchByCleanShutdown;
+
+ // Add the switch to make sure that fakeIdentity1 is known at startup to avoid
+ // automatic sign out.
+ config.additional_args.push_back(
+ std::string("-") + test_switches::kAddFakeIdentitiesAtStartup + "=" +
+ [FakeSystemIdentity encodeIdentitiesToBase64:@[ kPrimaryIdentity ]]);
+ config.additional_args.push_back(std::string("-") +
+ test_switches::kSimulatePostDeviceRestore);
+ // The post-restore signin alert is a promo, and promo are implemented as IPH.
+ // All IPH are disabled by default in EGtests. This flag enable this
+ // particular IPH.
+ config.additional_args.push_back(std::string("-") +
+ test_switches::kEnableIPH +
+ "=IPH_iOSPromoPostRestore");
+
+ // Relaunch the app to take the configuration into account.
+ [[AppLaunchManager sharedManager] ensureAppLaunchedWithConfiguration:config];
+ chrome_test_util::GREYAssertErrorNil(
+ [MetricsAppInterface setupHistogramTester]);
+
+ [SigninEarlGrey verifySignedOut];
+ [[EarlGrey selectElementWithMatcher:
+ grey_text(l10n_util::GetNSString(
+ IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_TITLE))]
+ assertWithMatcher:grey_sufficientlyVisible()];
+}
+
+// Test that continue opens the add account view.
+- (void)testContinue {
+ // Tap on 'Continue' to present the add account view.
+ [[EarlGrey
+ selectElementWithMatcher:
+ grey_text(l10n_util::GetNSString(
+ IDS_IOS_POST_RESTORE_SIGN_IN_FULLSCREEN_PRIMARY_ACTION_SHORT))]
+ performAction:grey_tap()];
+
+ // Ensure the fake add-account menu is
+ // displayed. The existence of the "add
+ // account" accessibility button on screen verifies that the screen
+ // was shown.
+ [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+ kFakeAuthAddAccountButtonIdentifier)]
+ assertWithMatcher:grey_notNil()];
+
+ ExpectedSigninHistograms* expecteds = [[ExpectedSigninHistograms alloc]
+ initWithAccessPoint:signin_metrics::AccessPoint::
+ ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO];
+ // TODO(crbug.com/41493423): We should log that the signin was offered,
+ // and started.
+ [SigninEarlGrey assertExpectedSigninHistograms:expecteds];
+}
+
+// Test that cancel does not opens the add account view.
+- (void)testCancel {
+ // Tap on 'Cancel' to present the add account view.
+ [[EarlGrey selectElementWithMatcher:
+ grey_text(l10n_util::GetNSString(
+ IDS_IOS_POST_RESTORE_SIGN_IN_ALERT_PROMO_CANCEL_ACTION))]
+ performAction:grey_tap()];
+
+ // Ensure the fake add-account menu is
+ // not displayed. The absence of the "add
+ // account" accessibility button on screen verifies that the screen
+ // was not shown.
+ [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+ kFakeAuthCancelButtonIdentifier)]
+ assertWithMatcher:grey_nil()];
+
+ ExpectedSigninHistograms* expecteds = [[ExpectedSigninHistograms alloc]
+ initWithAccessPoint:signin_metrics::AccessPoint::
+ ACCESS_POINT_POST_DEVICE_RESTORE_SIGNIN_PROMO];
+ // TODO(crbug.com/41493423): We should log that the signin was offered.
+ [SigninEarlGrey assertExpectedSigninHistograms:expecteds];
+}
+
+@end
diff --git a/ios/chrome/browser/shared/public/features/system_flags.h b/ios/chrome/browser/shared/public/features/system_flags.h
index b73ec054..c062095f 100644
--- a/ios/chrome/browser/shared/public/features/system_flags.h
+++ b/ios/chrome/browser/shared/public/features/system_flags.h
@@ -136,7 +136,9 @@
// former takes precedence.
std::string GetSegmentForForcedShopperExperience();
-// Whether a phone backup/restore state should be simulated.
+// Whether a phone backup/restore state should be simulated due to experimental
+// settings. Uses `tests_hook::SimulatePostDeviceRestore()` to check whether
+// this feature should be enabled for EG tests.
bool SimulatePostDeviceRestore();
// In production, the history sync opt-in isn't shown if it was declined too
diff --git a/ios/chrome/browser/signin/model/BUILD.gn b/ios/chrome/browser/signin/model/BUILD.gn
index 0b517e71..578e944 100644
--- a/ios/chrome/browser/signin/model/BUILD.gn
+++ b/ios/chrome/browser/signin/model/BUILD.gn
@@ -141,6 +141,7 @@
"//components/sync/base",
"//components/sync/service",
"//google_apis",
+ "//ios/chrome/app:tests_hook",
"//ios/chrome/browser/authentication/ui_bundled/signin:signin_headers",
"//ios/chrome/browser/bookmarks/model:model_utils",
"//ios/chrome/browser/crash_report/model",
@@ -192,10 +193,12 @@
"//base",
"//components/prefs",
"//components/signin/public/identity_manager",
+ "//ios/chrome/app:tests_hook",
"//ios/chrome/browser/shared/model/application_context",
"//ios/chrome/browser/shared/model/prefs:pref_names",
"//ios/chrome/browser/shared/public/features:system_flags",
"//ios/public/provider/chrome/browser/signin:signin_error_api",
+ "//ios/public/provider/chrome/browser/signin:signin_identity_api",
]
}
diff --git a/ios/chrome/browser/signin/model/authentication_service.mm b/ios/chrome/browser/signin/model/authentication_service.mm
index 0dbab83..15209aa 100644
--- a/ios/chrome/browser/signin/model/authentication_service.mm
+++ b/ios/chrome/browser/signin/model/authentication_service.mm
@@ -710,12 +710,12 @@
return;
}
- // YES if the primary identity should be ignore to simulate a backup/restore
+ // YES if the primary identity should be ignored to simulate a backup/restore
// of the device.
bool simulate_identity_lost_for_restore =
- device_restore && experimental_flags::SimulatePostDeviceRestore();
- // If the restore shorty is needs to be simulated, the primary identity should
- // not found.
+ device_restore && SimulatePostDeviceRestore();
+ // If the restore shorty needs to be simulated, the primary identity should
+ // not be found.
id<SystemIdentity> authenticated_identity =
simulate_identity_lost_for_restore
? nil
diff --git a/ios/chrome/browser/signin/model/signin_util.h b/ios/chrome/browser/signin/model/signin_util.h
index ef8ab3fd4..934db42 100644
--- a/ios/chrome/browser/signin/model/signin_util.h
+++ b/ios/chrome/browser/signin/model/signin_util.h
@@ -41,8 +41,8 @@
// The value is cached. The result is cached for later calls.
signin::Tribool IsFirstSessionAfterDeviceRestore();
-// Stores a user's account info and if history sync was enabled or not, when we
-// detect that it was forgotten during a device restore.
+// Stores a user's account info and whether history sync was enabled or not,
+// when we detect that it was forgotten during a device restore.
void StorePreRestoreIdentity(PrefService* profile_pref,
AccountInfo account,
bool history_sync_enabled);
@@ -65,4 +65,8 @@
// can be cached for later usage.
void RunSystemCapabilitiesPrefetch(NSArray<id<SystemIdentity>>* identities);
+// Whether a phone backup/restore state should be simulated.
+// This can be triggered either by EG test flag or by Experimental settings.
+bool SimulatePostDeviceRestore();
+
#endif // IOS_CHROME_BROWSER_SIGNIN_MODEL_SIGNIN_UTIL_H_
diff --git a/ios/chrome/browser/signin/model/signin_util.mm b/ios/chrome/browser/signin/model/signin_util.mm
index e16753ab..d152905 100644
--- a/ios/chrome/browser/signin/model/signin_util.mm
+++ b/ios/chrome/browser/signin/model/signin_util.mm
@@ -15,6 +15,7 @@
#import "google_apis/gaia/core_account_id.h"
#import "google_apis/gaia/gaia_auth_util.h"
#import "google_apis/gaia/gaia_id.h"
+#import "ios/chrome/app/tests_hook.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/public/features/system_flags.h"
@@ -22,6 +23,7 @@
#import "ios/chrome/browser/signin/model/system_identity.h"
#import "ios/chrome/browser/signin/model/system_identity_manager.h"
#import "ios/public/provider/chrome/browser/signin/signin_error_api.h"
+#import "ios/public/provider/chrome/browser/signin/signin_identity_api.h"
namespace {
@@ -97,7 +99,7 @@
}
signin::Tribool IsFirstSessionAfterDeviceRestore() {
- if (experimental_flags::SimulatePostDeviceRestore()) {
+ if (SimulatePostDeviceRestore()) {
return signin::Tribool::kTrue;
}
static signin::Tribool is_first_session_after_device_restore =
@@ -161,3 +163,10 @@
}));
}
}
+
+bool SimulatePostDeviceRestore() {
+ // We simulate post device restore if required either by experimental settings
+ // or test flag.
+ return tests_hook::SimulatePostDeviceRestore() ||
+ experimental_flags::SimulatePostDeviceRestore();
+}
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm
index c9599b1..62e3af01 100644
--- a/ios/chrome/test/earl_grey/eg_tests_hook.mm
+++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -43,6 +43,7 @@
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/browser/signin/model/fake_system_identity_manager.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
+#import "ios/chrome/browser/signin/model/signin_util.h"
#import "ios/chrome/browser/sync/model/data_type_store_service_factory.h"
#import "ios/chrome/browser/sync/model/device_info_sync_service_factory.h"
#import "ios/chrome/test/app/chrome_test_util.h"
@@ -137,6 +138,11 @@
return GetTestPlatformPolicyProvider();
}
+bool SimulatePostDeviceRestore() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ test_switches::kSimulatePostDeviceRestore);
+}
+
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/ios/chrome/test/earl_grey/test_switches.h b/ios/chrome/test/earl_grey/test_switches.h
index 4a6979f..dc859c133 100644
--- a/ios/chrome/test/earl_grey/test_switches.h
+++ b/ios/chrome/test/earl_grey/test_switches.h
@@ -25,6 +25,9 @@
// Ignored if kForceRealSystemIdentityManager is used.
extern const char kSignInAtStartup[];
+// Switch used to simulate a post device restore in EG tests.
+extern const char kSimulatePostDeviceRestore[];
+
// Switch used to enable FakeTabGroupSyncService for testing. The feature
// kTabGroupSync should be enabled as well.
extern const char kEnableFakeTabGroupSyncService[];
diff --git a/ios/chrome/test/earl_grey/test_switches.mm b/ios/chrome/test/earl_grey/test_switches.mm
index 84bd6101..ee4e2c3 100644
--- a/ios/chrome/test/earl_grey/test_switches.mm
+++ b/ios/chrome/test/earl_grey/test_switches.mm
@@ -16,6 +16,9 @@
// Sign in automatically at startup.
const char kSignInAtStartup[] = "sign-in-at-startup";
+// Simulate post device restore.
+const char kSimulatePostDeviceRestore[] = "simulate-post-device-restore";
+
// Enables FakeTabGroupSyncService.
const char kEnableFakeTabGroupSyncService[] =
"enable-fake-tab-group-sync-service";
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index c65f265..64868791 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -176,6 +176,7 @@
"//ios/chrome/browser/authentication/ui_bundled/signin/forced_signin:eg2_tests",
"//ios/chrome/browser/authentication/ui_bundled/signin/two_screens_signin:eg2_tests",
"//ios/chrome/browser/authentication/ui_bundled/signout_action_sheet:eg2_tests",
+ "//ios/chrome/browser/post_restore_signin/ui_bundled:eg2_tests",
"//ios/chrome/browser/signin/model:eg2_tests",
]
data_deps = [ ":ios_chrome_eg2tests" ]
diff --git a/ios/chrome/test/wpt/cwt_tests_hook.mm b/ios/chrome/test/wpt/cwt_tests_hook.mm
index 93b3a21..7d0f2e1 100644
--- a/ios/chrome/test/wpt/cwt_tests_hook.mm
+++ b/ios/chrome/test/wpt/cwt_tests_hook.mm
@@ -54,6 +54,9 @@
policy::ConfigurationPolicyProvider* GetOverriddenPlatformPolicyProvider() {
return nullptr;
}
+bool SimulatePostDeviceRestore() {
+ return false;
+}
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager() {
return nullptr;
}
diff --git a/ios/chrome/test/xcuitest/xcuitests_hook.mm b/ios/chrome/test/xcuitest/xcuitests_hook.mm
index 08f1d719..936da87b 100644
--- a/ios/chrome/test/xcuitest/xcuitests_hook.mm
+++ b/ios/chrome/test/xcuitest/xcuitests_hook.mm
@@ -63,6 +63,10 @@
return nullptr;
}
+bool SimulatePostDeviceRestore() {
+ return false;
+}
+
std::unique_ptr<SystemIdentityManager> CreateSystemIdentityManager() {
return nullptr;
}